Line data Source code
1 : #include "../../disco/tiles.h"
2 : #include "generated/fd_exec_tile_seccomp.h"
3 :
4 : #include "../../util/pod/fd_pod_format.h"
5 : #include "../../flamenco/runtime/context/fd_capture_ctx.h"
6 : #include "../../flamenco/runtime/fd_runtime.h"
7 : #include "../../flamenco/runtime/fd_runtime_public.h"
8 : #include "../../flamenco/runtime/fd_executor.h"
9 : #include "../../flamenco/runtime/fd_hashes.h"
10 : #include "../../flamenco/runtime/program/fd_bpf_program_util.h"
11 :
12 : #include "../../funk/fd_funk.h"
13 :
14 : struct fd_exec_tile_out_ctx {
15 : ulong idx;
16 : fd_wksp_t * mem;
17 : ulong chunk;
18 : ulong chunk0;
19 : ulong wmark;
20 : };
21 : typedef struct fd_exec_tile_out_ctx fd_exec_tile_out_ctx_t;
22 :
23 : struct fd_exec_tile_ctx {
24 :
25 : /* link-related data structures. */
26 : ulong replay_exec_in_idx;
27 : ulong tile_cnt;
28 : ulong tile_idx;
29 :
30 : fd_wksp_t * replay_in_mem;
31 : ulong replay_in_chunk0;
32 : ulong replay_in_wmark;
33 :
34 : fd_exec_tile_out_ctx_t exec_writer_out[ 1 ];
35 : uchar boot_msg_sent;
36 :
37 : /* Runtime public and local joins of its members. */
38 : fd_wksp_t * runtime_public_wksp;
39 : fd_runtime_public_t * runtime_public;
40 : fd_spad_t const * runtime_spad;
41 :
42 : /* Shared bank hash cmp object. */
43 : fd_bank_hash_cmp_t * bank_hash_cmp;
44 :
45 : fd_spad_t * exec_spad;
46 : fd_wksp_t * exec_spad_wksp;
47 :
48 : fd_funk_t funk[1];
49 :
50 : /* Data structures related to managing and executing the transaction.
51 : The fd_txn_p_t is refreshed with every transaction and is sent
52 : from the dispatch/replay tile. The fd_exec_txn_ctx_t * is a valid
53 : local join that lives in the top-most frame of the spad that is
54 : setup when the exec tile is booted; its members are refreshed on
55 : the slot/epoch boundary. */
56 : fd_txn_p_t txn;
57 : fd_exec_txn_ctx_t * txn_ctx;
58 : int exec_res;
59 :
60 : /* The txn/bpf id are sequence numbers. */
61 : /* The txn id is a value that is monotonically increased after
62 : executing a transaction. It is used to prevent race conditions in
63 : interactions between the exec and replay tile. It is expected to
64 : overflow back to 0. */
65 : uint txn_id;
66 : /* The bpf id is the txn_id counterparts for updates to the bpf cache. */
67 : uint bpf_id;
68 :
69 : ulong * exec_fseq;
70 :
71 : /* Pairs len is the number of accounts to hash. */
72 : ulong pairs_len;
73 :
74 : /* Current slot being executed. */
75 : ulong slot;
76 :
77 : /* Current bank being executed. */
78 : fd_banks_t * banks;
79 : fd_bank_t * bank;
80 :
81 : fd_capture_ctx_t * capture_ctx;
82 : };
83 : typedef struct fd_exec_tile_ctx fd_exec_tile_ctx_t;
84 :
85 : FD_FN_CONST static inline ulong
86 0 : scratch_align( void ) {
87 0 : return 128UL;
88 0 : }
89 :
90 : FD_FN_PURE static inline ulong
91 0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
92 : /* clang-format off */
93 0 : ulong l = FD_LAYOUT_INIT;
94 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_exec_tile_ctx_t), sizeof(fd_exec_tile_ctx_t) );
95 0 : l = FD_LAYOUT_APPEND( l, FD_CAPTURE_CTX_ALIGN, FD_CAPTURE_CTX_FOOTPRINT );
96 0 : return FD_LAYOUT_FINI( l, scratch_align() );
97 : /* clang-format on */
98 0 : }
99 :
100 : static void
101 0 : execute_txn( fd_exec_tile_ctx_t * ctx ) {
102 :
103 0 : FD_SPAD_FRAME_BEGIN( ctx->exec_spad ) {
104 :
105 : /* Query the funk transaction for the given slot. */
106 0 : fd_funk_txn_map_t * txn_map = fd_funk_txn_map( ctx->funk );
107 0 : if( FD_UNLIKELY( !txn_map->map ) ) {
108 0 : FD_LOG_ERR(( "Could not find valid funk transaction map" ));
109 0 : }
110 0 : fd_funk_txn_xid_t xid = { .ul = { ctx->slot, ctx->slot } };
111 0 : fd_funk_txn_start_read( ctx->funk );
112 0 : fd_funk_txn_t * funk_txn = fd_funk_txn_query( &xid, txn_map );
113 0 : if( FD_UNLIKELY( !funk_txn ) ) {
114 0 : FD_LOG_ERR(( "Could not find valid funk transaction" ));
115 0 : }
116 0 : fd_funk_txn_end_read( ctx->funk );
117 0 : ctx->txn_ctx->funk_txn = funk_txn;
118 :
119 : /* Get the bank for the given slot. */
120 0 : ctx->bank = fd_banks_get_bank( ctx->banks, ctx->slot );
121 0 : if( FD_UNLIKELY( !ctx->bank ) ) {
122 0 : FD_LOG_ERR(( "Could not get bank for slot %lu", ctx->slot ));
123 0 : }
124 :
125 : /* Setup and execute the transaction.*/
126 0 : ctx->txn_ctx->bank = ctx->bank;
127 0 : ctx->txn_ctx->slot = ctx->bank->slot;
128 0 : ctx->txn_ctx->features = fd_bank_features_get( ctx->bank );
129 :
130 0 : fd_execute_txn_task_info_t task_info = {
131 0 : .txn_ctx = ctx->txn_ctx,
132 0 : .exec_res = 0,
133 0 : .txn = &ctx->txn,
134 0 : };
135 :
136 0 : fd_txn_t const * txn_descriptor = TXN( task_info.txn );
137 0 : fd_rawtxn_b_t raw_txn = {
138 0 : .raw = task_info.txn->payload,
139 0 : .txn_sz = (ushort)task_info.txn->payload_sz
140 0 : };
141 :
142 0 : task_info.txn->flags = FD_TXN_P_FLAGS_SANITIZE_SUCCESS;
143 :
144 0 : fd_exec_txn_ctx_setup( ctx->txn_ctx, txn_descriptor, &raw_txn );
145 0 : ctx->txn_ctx->capture_ctx = ctx->capture_ctx;
146 :
147 0 : int err = fd_executor_setup_accessed_accounts_for_txn( ctx->txn_ctx );
148 0 : if( FD_UNLIKELY( err ) ) {
149 0 : task_info.txn->flags = 0U;
150 0 : task_info.exec_res = err;
151 0 : return;
152 0 : }
153 :
154 0 : if( FD_UNLIKELY( fd_executor_txn_verify( ctx->txn_ctx )!=0 ) ) {
155 0 : FD_LOG_WARNING(( "sigverify failed: %s", FD_BASE58_ENC_64_ALLOCA( (uchar *)ctx->txn_ctx->_txn_raw->raw+ctx->txn_ctx->txn_descriptor->signature_off ) ));
156 0 : task_info.txn->flags = 0U;
157 0 : task_info.exec_res = FD_RUNTIME_TXN_ERR_SIGNATURE_FAILURE;
158 0 : return;
159 0 : }
160 :
161 0 : uchar dump_txn = !!( ctx->txn_ctx->capture_ctx && ctx->txn_ctx->slot >= ctx->txn_ctx->capture_ctx->dump_proto_start_slot && ctx->txn_ctx->capture_ctx->dump_txn_to_pb );
162 0 : fd_runtime_pre_execute_check( &task_info, dump_txn );
163 0 : if( FD_UNLIKELY( !( task_info.txn->flags & FD_TXN_P_FLAGS_SANITIZE_SUCCESS ) ) ) {
164 0 : return;
165 0 : }
166 :
167 : /* Execute */
168 0 : task_info.txn->flags |= FD_TXN_P_FLAGS_EXECUTE_SUCCESS;
169 0 : ctx->exec_res = fd_execute_txn( &task_info );
170 :
171 0 : if( FD_LIKELY( ctx->exec_res==FD_EXECUTOR_INSTR_SUCCESS ) ) {
172 0 : fd_txn_reclaim_accounts( task_info.txn_ctx );
173 0 : }
174 :
175 0 : } FD_SPAD_FRAME_END;
176 0 : }
177 :
178 : // TODO: hashing can be moved into the writer tile
179 : static void
180 : hash_accounts( fd_exec_tile_ctx_t * ctx,
181 0 : fd_runtime_public_hash_bank_msg_t * msg ) {
182 :
183 0 : ctx->slot = msg->slot;
184 0 : fd_funk_txn_map_t * txn_map = fd_funk_txn_map( ctx->funk );
185 0 : if( FD_UNLIKELY( !txn_map->map ) ) {
186 0 : FD_LOG_ERR(( "Could not find valid funk transaction map" ));
187 0 : }
188 0 : fd_funk_txn_xid_t xid = { .ul = { ctx->slot, ctx->slot } };
189 0 : fd_funk_txn_start_read( ctx->funk );
190 0 : fd_funk_txn_t * funk_txn = fd_funk_txn_query( &xid, txn_map );
191 0 : if( FD_UNLIKELY( !funk_txn ) ) {
192 0 : FD_LOG_ERR(( "Could not find valid funk transaction" ));
193 0 : }
194 0 : fd_funk_txn_end_read( ctx->funk );
195 0 : ctx->txn_ctx->funk_txn = funk_txn;
196 :
197 0 : ctx->bank = fd_banks_get_bank( ctx->banks, ctx->slot );
198 0 : if( FD_UNLIKELY( !ctx->bank ) ) {
199 0 : FD_LOG_ERR(( "Could not get bank for slot %lu", ctx->slot ));
200 0 : }
201 :
202 0 : ctx->txn_ctx->bank = ctx->bank;
203 0 : ctx->txn_ctx->slot = ctx->bank->slot;
204 :
205 0 : ulong start_idx = msg->start_idx;
206 0 : ulong end_idx = msg->end_idx;
207 :
208 0 : fd_accounts_hash_task_info_t * task_info = fd_wksp_laddr_fast( ctx->runtime_public_wksp, msg->task_infos_gaddr );
209 0 : if( FD_UNLIKELY( !task_info ) ) {
210 0 : FD_LOG_ERR(( "Unable to join task info array" ));
211 0 : }
212 :
213 0 : if( FD_UNLIKELY( !msg->lthash_gaddr ) ) {
214 0 : FD_LOG_ERR(( "lthash gaddr is zero" ));
215 0 : }
216 0 : fd_lthash_value_t * lthash = fd_wksp_laddr_fast( ctx->runtime_public_wksp, msg->lthash_gaddr );
217 0 : if( FD_UNLIKELY( !lthash ) ) {
218 0 : FD_LOG_ERR(( "Unable to join lthash" ));
219 0 : }
220 0 : fd_lthash_zero( lthash );
221 :
222 0 : for( ulong i=start_idx; i<=end_idx; i++ ) {
223 0 : fd_account_hash( ctx->txn_ctx->funk,
224 0 : ctx->txn_ctx->funk_txn,
225 0 : &task_info[i],
226 0 : lthash,
227 0 : ctx->txn_ctx->slot,
228 0 : &ctx->txn_ctx->features );
229 0 : }
230 0 : }
231 :
232 : static void
233 0 : snap_hash_count( fd_exec_tile_ctx_t * ctx ) {
234 0 : ctx->pairs_len = fd_accounts_sorted_subrange_count( ctx->funk, (uint)ctx->tile_idx, (uint)ctx->tile_cnt );
235 0 : }
236 :
237 : static void
238 : snap_hash_gather( fd_exec_tile_ctx_t * ctx,
239 0 : fd_runtime_public_snap_hash_msg_t * msg ) {
240 :
241 0 : ulong * num_pairs = fd_wksp_laddr_fast( ctx->runtime_public_wksp, msg->num_pairs_out_gaddr );
242 0 : if( FD_UNLIKELY( !num_pairs ) ) {
243 0 : FD_LOG_ERR(( "Unable to join num_pairs" ));
244 0 : }
245 0 : fd_pubkey_hash_pair_t * pairs = fd_wksp_laddr_fast( ctx->runtime_public_wksp, msg->pairs_gaddr );
246 0 : if( FD_UNLIKELY( !pairs ) ) {
247 0 : FD_LOG_ERR(( "Unable to join pairs" ));
248 0 : }
249 0 : fd_lthash_value_t * lthash_value = fd_wksp_laddr_fast( ctx->runtime_public_wksp, msg->lt_hash_value_out_gaddr );
250 0 : if( FD_UNLIKELY( !lthash_value ) ) {
251 0 : FD_LOG_ERR(( "Unable to join lthash values" ));
252 0 : }
253 :
254 0 : fd_accounts_sorted_subrange_gather( ctx->funk, (uint)ctx->tile_idx, (uint)ctx->tile_cnt,
255 0 : num_pairs, lthash_value,
256 0 : pairs, &ctx->runtime_public->features );
257 0 : }
258 :
259 : static void
260 : during_frag( fd_exec_tile_ctx_t * ctx,
261 : ulong in_idx,
262 : ulong seq FD_PARAM_UNUSED,
263 : ulong sig,
264 : ulong chunk,
265 : ulong sz,
266 0 : ulong ctl FD_PARAM_UNUSED ) {
267 :
268 0 : if( FD_LIKELY( in_idx == ctx->replay_exec_in_idx ) ) {
269 0 : if( FD_UNLIKELY( chunk < ctx->replay_in_chunk0 || chunk > ctx->replay_in_wmark ) ) {
270 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]",
271 0 : chunk,
272 0 : sz,
273 0 : ctx->replay_in_chunk0,
274 0 : ctx->replay_in_wmark ));
275 0 : }
276 :
277 0 : if( FD_LIKELY( sig==EXEC_NEW_TXN_SIG ) ) {
278 0 : fd_runtime_public_txn_msg_t * txn = (fd_runtime_public_txn_msg_t *)fd_chunk_to_laddr( ctx->replay_in_mem, chunk );
279 0 : ctx->txn = txn->txn;
280 0 : ctx->slot = txn->slot;
281 0 : execute_txn( ctx );
282 0 : return;
283 0 : } else if( sig==EXEC_HASH_ACCS_SIG ) {
284 0 : fd_runtime_public_hash_bank_msg_t * msg = fd_chunk_to_laddr( ctx->replay_in_mem, chunk );
285 0 : FD_LOG_DEBUG(( "hash accs=%lu msg recvd", msg->end_idx - msg->start_idx ));
286 0 : hash_accounts( ctx, msg );
287 0 : return;
288 0 : } else if( sig==EXEC_SNAP_HASH_ACCS_CNT_SIG ) {
289 0 : FD_LOG_DEBUG(( "snap hash count msg recvd" ));
290 0 : snap_hash_count( ctx );
291 0 : } else if( sig==EXEC_SNAP_HASH_ACCS_GATHER_SIG ) {
292 0 : fd_runtime_public_snap_hash_msg_t * msg = fd_chunk_to_laddr( ctx->replay_in_mem, chunk );
293 0 : FD_LOG_DEBUG(( "snap hash gather msg recvd" ));
294 0 : snap_hash_gather( ctx, msg );
295 0 : } else {
296 0 : FD_LOG_ERR(( "Unknown signature" ));
297 0 : }
298 0 : }
299 0 : }
300 :
301 : static void
302 : after_frag( fd_exec_tile_ctx_t * ctx,
303 : ulong in_idx FD_PARAM_UNUSED,
304 : ulong seq FD_PARAM_UNUSED,
305 : ulong sig,
306 : ulong sz FD_PARAM_UNUSED,
307 : ulong tsorig,
308 : ulong tspub,
309 0 : fd_stem_context_t * stem ) {
310 :
311 0 : if( sig==EXEC_NEW_TXN_SIG ) {
312 0 : FD_LOG_DEBUG(( "Sending ack for new txn msg" ));
313 : /* At this point we can assume that the transaction is done
314 : executing. A writer tile will be repsonsible for commiting
315 : the transaction back to funk. */
316 0 : ctx->txn_ctx->exec_err = ctx->exec_res;
317 0 : ctx->txn_ctx->flags = ctx->txn.flags;
318 :
319 0 : fd_exec_tile_out_ctx_t * exec_out = ctx->exec_writer_out;
320 :
321 0 : fd_runtime_public_exec_writer_txn_msg_t * msg = fd_type_pun( fd_chunk_to_laddr( exec_out->mem, exec_out->chunk ) );
322 0 : msg->exec_tile_id = (uchar)ctx->tile_idx;
323 0 : msg->txn_id = ctx->txn_id;
324 :
325 0 : fd_stem_publish( stem,
326 0 : exec_out->idx,
327 0 : FD_WRITER_TXN_SIG,
328 0 : exec_out->chunk,
329 0 : sizeof(*msg),
330 0 : 0UL,
331 0 : tsorig,
332 0 : tspub );
333 0 : exec_out->chunk = fd_dcache_compact_next( exec_out->chunk, sizeof(*msg), exec_out->chunk0, exec_out->wmark );
334 :
335 : /* Make sure that the txn/bpf id can never be equal to the sentinel
336 : value (this means that this is unintialized. )*/
337 0 : ctx->txn_id++;
338 0 : if( FD_UNLIKELY( ctx->txn_id==FD_EXEC_ID_SENTINEL ) ) {
339 0 : ctx->txn_id = 0U;
340 0 : }
341 0 : } else if( sig==EXEC_HASH_ACCS_SIG ) {
342 0 : FD_LOG_DEBUG(( "Sending ack for hash accs msg" ));
343 0 : fd_fseq_update( ctx->exec_fseq, fd_exec_fseq_set_hash_done( ctx->slot ) );
344 0 : } else if( sig==EXEC_SNAP_HASH_ACCS_CNT_SIG ) {
345 0 : FD_LOG_NOTICE(( "Sending ack for snap hash count msg pairs_len=%lu", ctx->pairs_len ));
346 0 : fd_fseq_update( ctx->exec_fseq, fd_exec_fseq_set_snap_hash_cnt_done( (uint)ctx->pairs_len ) );
347 0 : } else if( sig==EXEC_SNAP_HASH_ACCS_GATHER_SIG ) {
348 0 : FD_LOG_NOTICE(("Sending ack for snap hash gather msg" ));
349 0 : fd_fseq_update( ctx->exec_fseq, fd_exec_fseq_set_snap_hash_gather_done() );
350 0 : } else {
351 0 : FD_LOG_ERR(( "Unknown message signature" ));
352 0 : }
353 0 : }
354 :
355 : static void
356 : privileged_init( fd_topo_t * topo FD_PARAM_UNUSED,
357 0 : fd_topo_tile_t * tile FD_PARAM_UNUSED ) {
358 0 : }
359 :
360 : static void
361 : unprivileged_init( fd_topo_t * topo,
362 0 : fd_topo_tile_t * tile ) {
363 :
364 : /********************************************************************/
365 : /* validate allocations */
366 : /********************************************************************/
367 :
368 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
369 :
370 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
371 0 : fd_exec_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_tile_ctx_t), sizeof(fd_exec_tile_ctx_t) );
372 0 : void * capture_ctx_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_CAPTURE_CTX_ALIGN, FD_CAPTURE_CTX_FOOTPRINT );
373 0 : ulong scratch_alloc_mem = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
374 0 : if( FD_UNLIKELY( scratch_alloc_mem - (ulong)scratch - scratch_footprint( tile ) ) ) {
375 0 : FD_LOG_ERR( ( "Scratch_alloc_mem did not match scratch_footprint diff: %lu alloc: %lu footprint: %lu",
376 0 : scratch_alloc_mem - (ulong)scratch - scratch_footprint( tile ),
377 0 : scratch_alloc_mem,
378 0 : (ulong)scratch + scratch_footprint( tile ) ) );
379 0 : }
380 :
381 : /********************************************************************/
382 : /* validate links */
383 : /********************************************************************/
384 :
385 0 : ctx->tile_cnt = fd_topo_tile_name_cnt( topo, tile->name );
386 0 : ctx->tile_idx = tile->kind_id;
387 :
388 : /* First find and setup the in-link from replay to exec. */
389 0 : ctx->replay_exec_in_idx = fd_topo_find_tile_in_link( topo, tile, "replay_exec", ctx->tile_idx );
390 0 : if( FD_UNLIKELY( ctx->replay_exec_in_idx==ULONG_MAX ) ) {
391 0 : FD_LOG_ERR(( "Could not find replay_exec in-link" ));
392 0 : }
393 0 : fd_topo_link_t * replay_exec_in_link = &topo->links[tile->in_link_id[ctx->replay_exec_in_idx]];
394 0 : if( FD_UNLIKELY( !replay_exec_in_link) ) {
395 0 : FD_LOG_ERR(( "Invalid replay_exec in-link" ));
396 0 : }
397 0 : ctx->replay_in_mem = topo->workspaces[topo->objs[replay_exec_in_link->dcache_obj_id].wksp_id].wksp;
398 0 : ctx->replay_in_chunk0 = fd_dcache_compact_chunk0( ctx->replay_in_mem, replay_exec_in_link->dcache );
399 0 : ctx->replay_in_wmark = fd_dcache_compact_wmark( ctx->replay_in_mem,
400 0 : replay_exec_in_link->dcache,
401 0 : replay_exec_in_link->mtu );
402 :
403 : /* Setup out link. */
404 0 : ulong idx = fd_topo_find_tile_out_link( topo, tile, "exec_writer", ctx->tile_idx );
405 0 : fd_topo_link_t * exec_out_link = &topo->links[ tile->out_link_id[ idx ] ];
406 :
407 0 : if( strcmp( exec_out_link->name, "exec_writer" ) ) {
408 0 : FD_LOG_CRIT(("exec_writer link has unexpected name %s", exec_out_link->name ));
409 0 : }
410 :
411 0 : fd_exec_tile_out_ctx_t * exec_out = ctx->exec_writer_out;
412 0 : exec_out->idx = idx;
413 0 : exec_out->mem = topo->workspaces[ topo->objs[ exec_out_link->dcache_obj_id ].wksp_id ].wksp;
414 0 : exec_out->chunk0 = fd_dcache_compact_chunk0( exec_out->mem, exec_out_link->dcache );
415 0 : exec_out->wmark = fd_dcache_compact_wmark( exec_out->mem, exec_out_link->dcache, exec_out_link->mtu );
416 0 : exec_out->chunk = exec_out->chunk0;
417 0 : ctx->boot_msg_sent = 0U;
418 :
419 : /********************************************************************/
420 : /* runtime public */
421 : /********************************************************************/
422 :
423 0 : ulong runtime_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "runtime_pub" );
424 0 : if( FD_UNLIKELY( runtime_obj_id==ULONG_MAX ) ) {
425 0 : FD_LOG_ERR(( "Could not find topology object for runtime public" ));
426 0 : }
427 :
428 0 : ctx->runtime_public_wksp = topo->workspaces[ topo->objs[ runtime_obj_id ].wksp_id ].wksp;
429 0 : if( FD_UNLIKELY( !ctx->runtime_public_wksp ) ) {
430 0 : FD_LOG_ERR(( "No runtime_public workspace" ));
431 0 : }
432 :
433 0 : ctx->runtime_public = fd_runtime_public_join( fd_topo_obj_laddr( topo, runtime_obj_id ) );
434 0 : if( FD_UNLIKELY( !ctx->runtime_public ) ) {
435 0 : FD_LOG_ERR(( "Failed to join runtime public" ));
436 0 : }
437 :
438 0 : ctx->runtime_spad = fd_runtime_public_spad( ctx->runtime_public );
439 0 : if( FD_UNLIKELY( !ctx->runtime_spad ) ) {
440 0 : FD_LOG_ERR(( "Failed to get and join runtime spad" ));
441 0 : }
442 :
443 : /********************************************************************/
444 : /* banks */
445 : /********************************************************************/
446 :
447 0 : ulong banks_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "banks" );
448 0 : if( FD_UNLIKELY( banks_obj_id==ULONG_MAX ) ) {
449 0 : FD_LOG_ERR(( "Could not find topology object for banks" ));
450 0 : }
451 :
452 0 : ctx->banks = fd_banks_join( fd_topo_obj_laddr( topo, banks_obj_id ) );
453 0 : if( FD_UNLIKELY( !ctx->banks ) ) {
454 0 : FD_LOG_ERR(( "Failed to join banks" ));
455 0 : }
456 :
457 : /********************************************************************/
458 : /* spad allocator */
459 : /********************************************************************/
460 :
461 : /* First join the correct exec spad and hten the correct runtime spad
462 : which lives inside of the runtime public wksp. */
463 :
464 0 : ulong exec_spad_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "exec_spad.%lu", ctx->tile_idx );
465 0 : if( FD_UNLIKELY( exec_spad_obj_id==ULONG_MAX ) ) {
466 0 : FD_LOG_ERR(( "Could not find topology object for exec spad" ));
467 0 : }
468 :
469 0 : ctx->exec_spad = fd_spad_join( fd_topo_obj_laddr( topo, exec_spad_obj_id ) );
470 0 : if( FD_UNLIKELY( !ctx->exec_spad ) ) {
471 0 : FD_LOG_ERR(( "Failed to join exec spad" ));
472 0 : }
473 0 : ctx->exec_spad_wksp = fd_wksp_containing( ctx->exec_spad );
474 :
475 : /********************************************************************/
476 : /* bank hash cmp */
477 : /********************************************************************/
478 :
479 0 : ulong bank_hash_cmp_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "bh_cmp" );
480 0 : if( FD_UNLIKELY( bank_hash_cmp_obj_id==ULONG_MAX ) ) {
481 0 : FD_LOG_ERR(( "Could not find topology object for bank hash cmp" ));
482 0 : }
483 0 : ctx->bank_hash_cmp = fd_bank_hash_cmp_join( fd_topo_obj_laddr( topo, bank_hash_cmp_obj_id ) );
484 0 : if( FD_UNLIKELY( !ctx->bank_hash_cmp ) ) {
485 0 : FD_LOG_ERR(( "Failed to join bank hash cmp" ));
486 0 : }
487 :
488 : /********************************************************************/
489 : /* funk-specific setup */
490 : /********************************************************************/
491 :
492 0 : if( FD_UNLIKELY( !fd_funk_join( ctx->funk, fd_topo_obj_laddr( topo, tile->exec.funk_obj_id ) ) ) ) {
493 0 : FD_LOG_ERR(( "Failed to join database cache" ));
494 0 : }
495 :
496 : /********************************************************************/
497 : /* setup txncache */
498 : /********************************************************************/
499 :
500 : /* TODO: Implement this. */
501 :
502 : /********************************************************************/
503 : /* setup txn ctx */
504 : /********************************************************************/
505 :
506 0 : fd_spad_push( ctx->exec_spad );
507 : // FIXME account for this in exec spad footprint
508 0 : uchar * txn_ctx_mem = fd_spad_alloc_check( ctx->exec_spad, FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT );
509 0 : ctx->txn_ctx = fd_exec_txn_ctx_join( fd_exec_txn_ctx_new( txn_ctx_mem ), ctx->exec_spad, ctx->exec_spad_wksp );
510 0 : *ctx->txn_ctx->funk = *ctx->funk;
511 :
512 0 : ctx->txn_ctx->runtime_pub_wksp = ctx->runtime_public_wksp;
513 0 : if( FD_UNLIKELY( !ctx->txn_ctx->runtime_pub_wksp ) ) {
514 0 : FD_LOG_ERR(( "Failed to find public wksp" ));
515 0 : }
516 :
517 0 : ctx->txn_ctx->bank_hash_cmp = ctx->bank_hash_cmp;
518 :
519 : /********************************************************************/
520 : /* setup exec fseq */
521 : /********************************************************************/
522 :
523 0 : ulong exec_fseq_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "exec_fseq.%lu", ctx->tile_idx );
524 0 : ctx->exec_fseq = fd_fseq_join( fd_topo_obj_laddr( topo, exec_fseq_id ) );
525 0 : if( FD_UNLIKELY( !ctx->exec_fseq ) ) {
526 0 : FD_LOG_ERR(( "exec tile %lu has no fseq", ctx->tile_idx ));
527 0 : }
528 0 : fd_fseq_update( ctx->exec_fseq, FD_EXEC_STATE_NOT_BOOTED );
529 :
530 : /* Initialize sequence numbers to be 0. */
531 0 : ctx->txn_id = 0U;
532 0 : ctx->bpf_id = 0U;
533 :
534 0 : FD_LOG_NOTICE(( "Done booting exec tile idx=%lu", ctx->tile_idx ));
535 :
536 0 : if( strlen(tile->exec.dump_proto_dir) > 0 ) {
537 0 : ctx->capture_ctx = fd_capture_ctx_new( capture_ctx_mem );
538 0 : ctx->capture_ctx->dump_proto_output_dir = tile->exec.dump_proto_dir;
539 0 : ctx->capture_ctx->dump_proto_start_slot = tile->exec.capture_start_slot;
540 0 : ctx->capture_ctx->dump_instr_to_pb = tile->exec.dump_instr_to_pb;
541 0 : ctx->capture_ctx->dump_txn_to_pb = tile->exec.dump_txn_to_pb;
542 0 : ctx->capture_ctx->dump_syscall_to_pb = tile->exec.dump_syscall_to_pb;
543 0 : }
544 0 : }
545 :
546 : static void
547 : after_credit( fd_exec_tile_ctx_t * ctx,
548 : fd_stem_context_t * stem,
549 : int * opt_poll_in,
550 0 : int * charge_busy ) {
551 :
552 0 : (void)opt_poll_in;
553 0 : (void)charge_busy;
554 :
555 0 : if( FD_UNLIKELY( !ctx->boot_msg_sent ) ) {
556 :
557 0 : ctx->boot_msg_sent = 1U;
558 :
559 0 : ulong txn_ctx_gaddr = fd_wksp_gaddr( ctx->exec_spad_wksp, ctx->txn_ctx );
560 0 : if( FD_UNLIKELY( !txn_ctx_gaddr ) ) {
561 0 : FD_LOG_CRIT(( "Could not get gaddr for txn_ctx" ));
562 0 : }
563 :
564 0 : ulong exec_spad_gaddr = fd_wksp_gaddr( ctx->exec_spad_wksp, ctx->exec_spad );
565 0 : if( FD_UNLIKELY( !exec_spad_gaddr ) ) {
566 0 : FD_LOG_CRIT(( "Could not get gaddr for exec_spad" ));
567 0 : }
568 :
569 0 : if( FD_UNLIKELY( txn_ctx_gaddr-exec_spad_gaddr>UINT_MAX ) ) {
570 0 : FD_LOG_CRIT(( "txn_ctx offset from exec spad is too large" ));
571 0 : }
572 :
573 0 : uint txn_ctx_offset = (uint)(txn_ctx_gaddr-exec_spad_gaddr);
574 :
575 : /* Notify writer tiles. */
576 :
577 0 : ulong tsorig = fd_frag_meta_ts_comp( fd_tickcount() );
578 :
579 0 : fd_exec_tile_out_ctx_t * exec_out = ctx->exec_writer_out;
580 :
581 0 : fd_runtime_public_exec_writer_boot_msg_t * msg = fd_type_pun( fd_chunk_to_laddr( exec_out->mem, exec_out->chunk ) );
582 :
583 0 : msg->txn_ctx_offset = txn_ctx_offset;
584 :
585 0 : ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
586 0 : fd_stem_publish( stem,
587 0 : exec_out->idx,
588 0 : FD_WRITER_BOOT_SIG,
589 0 : exec_out->chunk,
590 0 : sizeof(*msg),
591 0 : 0UL,
592 0 : tsorig,
593 0 : tspub );
594 0 : exec_out->chunk = fd_dcache_compact_next( exec_out->chunk, sizeof(*msg), exec_out->chunk0, exec_out->wmark );
595 :
596 : /* Notify replay tile. */
597 :
598 0 : fd_fseq_update( ctx->exec_fseq, fd_exec_fseq_set_booted( txn_ctx_offset ) );
599 0 : }
600 0 : }
601 :
602 : static ulong
603 : populate_allowed_seccomp( fd_topo_t const * topo,
604 : fd_topo_tile_t const * tile,
605 : ulong out_cnt,
606 0 : struct sock_filter * out ) {
607 0 : (void)topo;
608 0 : (void)tile;
609 :
610 0 : populate_sock_filter_policy_fd_exec_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
611 0 : return sock_filter_policy_fd_exec_tile_instr_cnt;
612 0 : }
613 :
614 : static ulong
615 : populate_allowed_fds( fd_topo_t const * topo,
616 : fd_topo_tile_t const * tile,
617 : ulong out_fds_cnt,
618 0 : int * out_fds ) {
619 0 : (void)topo;
620 0 : (void)tile;
621 :
622 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
623 :
624 0 : ulong out_cnt = 0UL;
625 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
626 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
627 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
628 0 : return out_cnt;
629 0 : }
630 :
631 : /* The stem burst is bound by the max number of exec tiles that are
632 : posible. */
633 0 : #define STEM_BURST (1UL)
634 :
635 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_exec_tile_ctx_t
636 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_exec_tile_ctx_t)
637 :
638 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
639 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
640 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
641 :
642 : #include "../../disco/stem/fd_stem.c"
643 :
644 : fd_topo_run_tile_t fd_tile_execor = {
645 : .name = "exec",
646 : .loose_footprint = 0UL,
647 : .populate_allowed_seccomp = populate_allowed_seccomp,
648 : .populate_allowed_fds = populate_allowed_fds,
649 : .scratch_align = scratch_align,
650 : .scratch_footprint = scratch_footprint,
651 : .privileged_init = privileged_init,
652 : .unprivileged_init = unprivileged_init,
653 : .run = stem_run,
654 : };
|