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 "../../disco/fd_txn_m.h"
6 : #include "../../discof/replay/fd_exec.h"
7 : #include "../../discof/replay/fd_vote_tracker.h"
8 : #include "../../flamenco/runtime/context/fd_capture_ctx.h"
9 : #include "../../flamenco/runtime/fd_bank.h"
10 : #include "../../flamenco/runtime/fd_runtime.h"
11 : #include "../../disco/metrics/fd_metrics.h"
12 :
13 : #include "../../funk/fd_funk.h"
14 :
15 : /* The exec tile is responsible for executing single transactions. The
16 : tile recieves a parsed transaction (fd_txn_p_t) and an identifier to
17 : which bank to execute against (index into the bank pool). With this,
18 : the exec tile is able to identify the correct bank and accounts db
19 : handle (funk_txn) to execute the transaction against. The exec tile
20 : then commits the results of the transaction to the accounts db and
21 : makes any necessary updates to the bank. */
22 :
23 : typedef struct link_ctx {
24 : ulong idx;
25 : fd_wksp_t * mem;
26 : ulong chunk;
27 : ulong chunk0;
28 : ulong wmark;
29 : } link_ctx_t;
30 :
31 : typedef struct fd_exec_tile_ctx {
32 :
33 : ulong tile_idx;
34 :
35 : /* link-related data structures. */
36 : link_ctx_t replay_in[ 1 ];
37 : link_ctx_t send_in[ 1 ];
38 : link_ctx_t exec_replay_out[ 1 ]; /* TODO: Remove with solcap v2 */
39 : link_ctx_t capture_replay_out[ 1 ]; /* TODO: Remove with solcap v2 */
40 :
41 : fd_bank_hash_cmp_t * bank_hash_cmp;
42 :
43 : fd_spad_t * exec_spad;
44 : fd_wksp_t * exec_spad_wksp;
45 :
46 : /* Data structures related to managing and executing the transaction.
47 : The fd_txn_p_t is refreshed with every transaction and is sent
48 : from the dispatch/replay tile. The fd_exec_txn_ctx_t * is a valid
49 : local join that lives in the top-most frame of the spad that is
50 : setup when the exec tile is booted; its members are refreshed on
51 : the slot/epoch boundary. */
52 : fd_exec_txn_ctx_t * txn_ctx;
53 :
54 : /* Capture context for debugging runtime execution. */
55 : fd_capture_ctx_t * capture_ctx;
56 : uchar * solcap_publish_buffer_ptr;
57 : ulong account_updates_flushed;
58 :
59 : /* A transaction can be executed as long as there is a valid handle to
60 : a funk_txn and a bank. These are queried from fd_banks_t and
61 : fd_funk_t.
62 : TODO: These should probably be made read-only handles. */
63 : fd_banks_t * banks;
64 : fd_funk_t funk[ 1 ];
65 :
66 : fd_txncache_t * txncache;
67 :
68 : fd_vote_tracker_t * vote_tracker;
69 : fd_signature_t vote_signature[ 1 ];
70 :
71 : /* We need to ensure that all solcap updates have been published
72 : before this message. */
73 : int pending_txn_finalized_msg;
74 : } fd_exec_tile_ctx_t;
75 :
76 : FD_FN_CONST static inline ulong
77 0 : scratch_align( void ) {
78 0 : return 128UL;
79 0 : }
80 :
81 : FD_FN_PURE static inline ulong
82 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
83 0 : ulong l = FD_LAYOUT_INIT;
84 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_exec_tile_ctx_t), sizeof(fd_exec_tile_ctx_t) );
85 0 : l = FD_LAYOUT_APPEND( l, fd_capture_ctx_align(), fd_capture_ctx_footprint() );
86 0 : l = FD_LAYOUT_APPEND( l, fd_txncache_align(), fd_txncache_footprint( tile->exec.max_live_slots ) );
87 0 : l = FD_LAYOUT_APPEND( l, fd_vote_tracker_align(), fd_vote_tracker_footprint() );
88 0 : return FD_LAYOUT_FINI( l, scratch_align() );
89 0 : }
90 :
91 : static int
92 : before_frag( fd_exec_tile_ctx_t * ctx,
93 : ulong in_idx FD_FN_UNUSED,
94 : ulong seq FD_FN_UNUSED,
95 0 : ulong sig ) {
96 0 : return (sig&0xFFFFFFFFUL)!=ctx->tile_idx;
97 0 : }
98 :
99 : static void
100 : during_frag( fd_exec_tile_ctx_t * ctx,
101 : ulong in_idx,
102 : ulong seq FD_PARAM_UNUSED,
103 : ulong sig,
104 : ulong chunk,
105 : ulong sz,
106 0 : ulong ctl FD_PARAM_UNUSED ) {
107 0 : if( FD_LIKELY( in_idx==ctx->replay_in->idx ) ) {
108 0 : if( FD_UNLIKELY( chunk < ctx->replay_in->chunk0 || chunk > ctx->replay_in->wmark ) ) {
109 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]",
110 0 : chunk,
111 0 : sz,
112 0 : ctx->replay_in->chunk0,
113 0 : ctx->replay_in->wmark ));
114 0 : }
115 0 : if( FD_LIKELY( (sig>>32)==EXEC_NEW_TXN_SIG ) ) {
116 0 : fd_exec_txn_msg_t * txn = (fd_exec_txn_msg_t *)fd_chunk_to_laddr( ctx->replay_in->mem, chunk );
117 :
118 0 : ctx->txn_ctx->exec_err = fd_runtime_prepare_and_execute_txn(
119 0 : ctx->banks,
120 0 : txn->bank_idx,
121 0 : ctx->txn_ctx,
122 0 : &txn->txn,
123 0 : ctx->exec_spad,
124 0 : ctx->capture_ctx,
125 0 : 1 );
126 0 : } else {
127 0 : FD_LOG_CRIT(( "Unknown signature %lu", sig ));
128 0 : }
129 0 : }
130 0 : else if( FD_LIKELY( in_idx==ctx->send_in->idx ) ) {
131 0 : fd_txn_m_t * txnm = fd_type_pun( fd_chunk_to_laddr( ctx->send_in->mem, chunk ) );
132 0 : uchar * payload = ((uchar *)txnm) + sizeof(fd_txn_m_t);
133 0 : uchar txn_mem[ FD_TXN_MAX_SZ ] __attribute__((aligned(alignof(fd_txn_t))));
134 0 : fd_txn_t * txn = (fd_txn_t *)txn_mem;
135 0 : if( FD_UNLIKELY( !fd_txn_parse( payload, txnm->payload_sz, txn_mem, NULL ) ) ) {
136 0 : FD_LOG_CRIT(( "Could not parse txn from send tile" ));
137 0 : }
138 0 : FD_STATIC_ASSERT( sizeof(*ctx->vote_signature) == FD_TXN_SIGNATURE_SZ, sizeof );
139 0 : fd_memcpy( ctx->vote_signature, payload + txn->signature_off, FD_TXN_SIGNATURE_SZ );
140 0 : }
141 0 : else FD_LOG_ERR(( "invalid in_idx %lu", in_idx ));
142 0 : }
143 :
144 : static void
145 : after_frag( fd_exec_tile_ctx_t * ctx,
146 : ulong in_idx,
147 : ulong seq FD_PARAM_UNUSED,
148 : ulong sig,
149 : ulong sz FD_PARAM_UNUSED,
150 : ulong tsorig FD_PARAM_UNUSED,
151 : ulong tspub FD_PARAM_UNUSED,
152 0 : fd_stem_context_t * stem FD_PARAM_UNUSED ) {
153 0 : if( FD_LIKELY( in_idx==ctx->replay_in->idx ) ) {
154 0 : if( FD_LIKELY( (sig>>32)==EXEC_NEW_TXN_SIG ) ) {
155 : /* At this point we can assume that the transaction is done
156 : executing. Commit the transaction back to funk. */
157 :
158 0 : fd_bank_t * bank = fd_banks_bank_query( ctx->banks, ctx->txn_ctx->bank_idx );
159 0 : if( FD_UNLIKELY( !bank ) ) {
160 0 : FD_LOG_CRIT(( "Could not find bank for slot %lu", ctx->txn_ctx->slot ));
161 0 : }
162 0 : ctx->txn_ctx->bank = bank;
163 :
164 0 : fd_funk_txn_xid_t xid = (fd_funk_txn_xid_t){ .ul = { fd_bank_slot_get( bank ), fd_bank_slot_get( bank ) } };
165 :
166 : /* Query the vote signature against the recently generated vote txn
167 : signatures. If the query is successful, then we have seen our
168 : own vote transaction and this should be marked in the bank. */
169 0 : uchar * txn_signature = ctx->txn_ctx->txn.payload + TXN( &ctx->txn_ctx->txn )->signature_off;
170 0 : if( fd_vote_tracker_query_sig( ctx->vote_tracker, (fd_signature_t *)txn_signature ) ) {
171 0 : FD_ATOMIC_FETCH_AND_ADD( fd_bank_has_identity_vote_modify( bank ), 1 );
172 0 : }
173 :
174 0 : if( FD_LIKELY( ctx->txn_ctx->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS ) ) {
175 0 : fd_runtime_finalize_txn(
176 0 : ctx->funk,
177 0 : ctx->txncache,
178 0 : &xid,
179 0 : ctx->txn_ctx,
180 0 : bank,
181 0 : ctx->capture_ctx );
182 0 : } else {
183 : /* This means that we should mark the block as dead. */
184 0 : fd_banks_mark_bank_dead( ctx->banks, bank );
185 0 : }
186 :
187 : /* Notify the replay tile that we are done with this txn. */
188 0 : ctx->pending_txn_finalized_msg = 1;
189 0 : } else {
190 0 : FD_LOG_ERR(( "Unknown message signature %lu", sig ));
191 0 : }
192 0 : }
193 0 : else if( FD_LIKELY( in_idx==ctx->send_in->idx ) ) {
194 : /* This means that the send tile has signed and sent a vote. Add
195 : this vote to the vote tracker. */
196 0 : fd_vote_tracker_insert( ctx->vote_tracker, ctx->vote_signature );
197 0 : }
198 0 : else FD_LOG_ERR(( "invalid in_idx %lu", in_idx ));
199 0 : }
200 :
201 : static void
202 : unprivileged_init( fd_topo_t * topo,
203 0 : fd_topo_tile_t * tile ) {
204 :
205 : /********************************************************************/
206 : /* validate allocations */
207 : /********************************************************************/
208 :
209 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
210 :
211 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
212 0 : fd_exec_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_tile_ctx_t), sizeof(fd_exec_tile_ctx_t) );
213 0 : void * capture_ctx_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_capture_ctx_align(), fd_capture_ctx_footprint() );
214 0 : void * _txncache = FD_SCRATCH_ALLOC_APPEND( l, fd_txncache_align(), fd_txncache_footprint( tile->exec.max_live_slots ) );
215 0 : void * vote_tracker_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_tracker_align(), fd_vote_tracker_footprint() );
216 0 : ulong scratch_alloc_mem = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
217 :
218 0 : if( FD_UNLIKELY( scratch_alloc_mem - (ulong)scratch - scratch_footprint( tile ) ) ) {
219 0 : FD_LOG_ERR( ( "Scratch_alloc_mem did not match scratch_footprint diff: %lu alloc: %lu footprint: %lu",
220 0 : scratch_alloc_mem - (ulong)scratch - scratch_footprint( tile ),
221 0 : scratch_alloc_mem,
222 0 : (ulong)scratch + scratch_footprint( tile ) ) );
223 0 : }
224 :
225 : /********************************************************************/
226 : /* validate links */
227 : /********************************************************************/
228 :
229 0 : ctx->tile_idx = tile->kind_id;
230 :
231 : /* First find and setup the in-link from replay to exec. */
232 0 : ctx->replay_in->idx = fd_topo_find_tile_in_link( topo, tile, "replay_exec", 0UL );
233 0 : FD_TEST( ctx->replay_in->idx!=ULONG_MAX );
234 0 : fd_topo_link_t * replay_in_link = &topo->links[ tile->in_link_id[ ctx->replay_in->idx ] ];
235 0 : FD_TEST( replay_in_link!=NULL );
236 0 : ctx->replay_in->mem = topo->workspaces[ topo->objs[ replay_in_link->dcache_obj_id ].wksp_id ].wksp;
237 0 : ctx->replay_in->chunk0 = fd_dcache_compact_chunk0( ctx->replay_in->mem, replay_in_link->dcache );
238 0 : ctx->replay_in->wmark = fd_dcache_compact_wmark( ctx->replay_in->mem, replay_in_link->dcache, replay_in_link->mtu );
239 0 : ctx->replay_in->chunk = ctx->replay_in->chunk0;
240 :
241 0 : ulong send_tile_cnt = fd_topo_tile_name_cnt( topo, "send" );
242 0 : if( send_tile_cnt>0UL ) {
243 0 : ctx->send_in->idx = fd_topo_find_tile_in_link( topo, tile, "send_txns", 0UL );
244 0 : FD_TEST( ctx->send_in->idx!=ULONG_MAX );
245 0 : fd_topo_link_t * send_in_link = &topo->links[ tile->in_link_id[ ctx->send_in->idx ] ];
246 0 : ctx->send_in->mem = topo->workspaces[ topo->objs[ send_in_link->dcache_obj_id ].wksp_id ].wksp;
247 0 : ctx->send_in->chunk0 = fd_dcache_compact_chunk0( ctx->send_in->mem, send_in_link->dcache );
248 0 : ctx->send_in->wmark = fd_dcache_compact_wmark( ctx->send_in->mem, send_in_link->dcache, send_in_link->mtu );
249 0 : ctx->send_in->chunk = ctx->send_in->chunk0;
250 0 : }
251 :
252 0 : ctx->exec_replay_out->idx = fd_topo_find_tile_out_link( topo, tile, "exec_replay", ctx->tile_idx );
253 0 : if( FD_LIKELY( ctx->exec_replay_out->idx!=ULONG_MAX ) ) {
254 0 : fd_topo_link_t * exec_replay_link = &topo->links[ tile->out_link_id[ ctx->exec_replay_out->idx ] ];
255 0 : ctx->exec_replay_out->mem = topo->workspaces[ topo->objs[ exec_replay_link->dcache_obj_id ].wksp_id ].wksp;
256 0 : ctx->exec_replay_out->chunk0 = fd_dcache_compact_chunk0( ctx->exec_replay_out->mem, exec_replay_link->dcache );
257 0 : ctx->exec_replay_out->wmark = fd_dcache_compact_wmark( ctx->exec_replay_out->mem, exec_replay_link->dcache, exec_replay_link->mtu );
258 0 : ctx->exec_replay_out->chunk = ctx->exec_replay_out->chunk0;
259 0 : }
260 :
261 0 : ctx->capture_replay_out->idx = fd_topo_find_tile_out_link( topo, tile, "capt_replay", ctx->tile_idx );
262 0 : if( FD_UNLIKELY( ctx->capture_replay_out->idx!=ULONG_MAX ) ) {
263 0 : fd_topo_link_t * capture_replay_link = &topo->links[ tile->out_link_id[ ctx->capture_replay_out->idx ] ];
264 0 : ctx->capture_replay_out->mem = topo->workspaces[ topo->objs[ capture_replay_link->dcache_obj_id ].wksp_id ].wksp;
265 0 : ctx->capture_replay_out->chunk0 = fd_dcache_compact_chunk0( ctx->capture_replay_out->mem, capture_replay_link->dcache );
266 0 : ctx->capture_replay_out->wmark = fd_dcache_compact_wmark( ctx->capture_replay_out->mem, capture_replay_link->dcache, capture_replay_link->mtu );
267 0 : ctx->capture_replay_out->chunk = ctx->capture_replay_out->chunk0;
268 0 : }
269 :
270 : /********************************************************************/
271 : /* banks */
272 : /********************************************************************/
273 :
274 0 : ulong banks_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "banks" );
275 0 : if( FD_UNLIKELY( banks_obj_id==ULONG_MAX ) ) {
276 0 : FD_LOG_ERR(( "Could not find topology object for banks" ));
277 0 : }
278 :
279 0 : ctx->banks = fd_banks_join( fd_topo_obj_laddr( topo, banks_obj_id ) );
280 0 : if( FD_UNLIKELY( !ctx->banks ) ) {
281 0 : FD_LOG_ERR(( "Failed to join banks" ));
282 0 : }
283 :
284 : /********************************************************************/
285 : /* spad allocator */
286 : /********************************************************************/
287 :
288 0 : ulong exec_spad_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "exec_spad.%lu", ctx->tile_idx );
289 0 : if( FD_UNLIKELY( exec_spad_obj_id==ULONG_MAX ) ) {
290 0 : FD_LOG_ERR(( "Could not find topology object for exec spad" ));
291 0 : }
292 :
293 0 : ctx->exec_spad = fd_spad_join( fd_topo_obj_laddr( topo, exec_spad_obj_id ) );
294 0 : if( FD_UNLIKELY( !ctx->exec_spad ) ) {
295 0 : FD_LOG_ERR(( "Failed to join exec spad" ));
296 0 : }
297 0 : ctx->exec_spad_wksp = fd_wksp_containing( ctx->exec_spad );
298 :
299 : /********************************************************************/
300 : /* bank hash cmp */
301 : /********************************************************************/
302 :
303 0 : ulong bank_hash_cmp_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "bh_cmp" );
304 0 : if( FD_UNLIKELY( bank_hash_cmp_obj_id==ULONG_MAX ) ) {
305 0 : FD_LOG_ERR(( "Could not find topology object for bank hash cmp" ));
306 0 : }
307 0 : ctx->bank_hash_cmp = fd_bank_hash_cmp_join( fd_topo_obj_laddr( topo, bank_hash_cmp_obj_id ) );
308 0 : if( FD_UNLIKELY( !ctx->bank_hash_cmp ) ) {
309 0 : FD_LOG_ERR(( "Failed to join bank hash cmp" ));
310 0 : }
311 :
312 : /********************************************************************/
313 : /* funk-specific setup */
314 : /********************************************************************/
315 :
316 0 : FD_TEST( fd_funk_join( ctx->funk, fd_topo_obj_laddr( topo, tile->exec.funk_obj_id ) ) );
317 :
318 : /********************************************************************/
319 : /* setup txncache */
320 : /********************************************************************/
321 :
322 0 : void * _txncache_shmem = fd_topo_obj_laddr( topo, tile->exec.txncache_obj_id );
323 0 : fd_txncache_shmem_t * txncache_shmem = fd_txncache_shmem_join( _txncache_shmem );
324 0 : FD_TEST( txncache_shmem );
325 0 : ctx->txncache = fd_txncache_join( fd_txncache_new( _txncache, txncache_shmem ) );
326 0 : FD_TEST( ctx->txncache );
327 :
328 : /********************************************************************/
329 : /* setup txn ctx */
330 : /********************************************************************/
331 :
332 0 : fd_spad_push( ctx->exec_spad );
333 0 : uchar * txn_ctx_mem = fd_spad_alloc_check( ctx->exec_spad, FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT );
334 0 : ctx->txn_ctx = fd_exec_txn_ctx_join( fd_exec_txn_ctx_new( txn_ctx_mem ), ctx->exec_spad, ctx->exec_spad_wksp );
335 0 : *ctx->txn_ctx->funk = *ctx->funk;
336 0 : ctx->txn_ctx->status_cache = ctx->txncache;
337 0 : ctx->txn_ctx->bank_hash_cmp = ctx->bank_hash_cmp;
338 0 : ctx->txn_ctx->spad = ctx->exec_spad;
339 0 : ctx->txn_ctx->spad_wksp = ctx->exec_spad_wksp;
340 :
341 : /********************************************************************/
342 : /* Vote tracker */
343 : /********************************************************************/
344 :
345 0 : ctx->vote_tracker = fd_vote_tracker_join( fd_vote_tracker_new( vote_tracker_mem, 0UL ) );
346 0 : if( FD_UNLIKELY( !ctx->vote_tracker ) ) {
347 0 : FD_LOG_ERR(( "Failed to join and create vote tracker object" ));
348 0 : }
349 :
350 : /********************************************************************/
351 : /* Capture context */
352 : /********************************************************************/
353 :
354 0 : ctx->capture_ctx = NULL;
355 0 : ctx->solcap_publish_buffer_ptr = NULL;
356 0 : ctx->account_updates_flushed = 0UL;
357 0 : if( FD_UNLIKELY( strlen( tile->exec.solcap_capture ) || strlen( tile->exec.dump_proto_dir ) ) ) {
358 0 : ctx->capture_ctx = fd_capture_ctx_join( fd_capture_ctx_new( capture_ctx_mem ) );
359 :
360 0 : if( strlen( tile->exec.dump_proto_dir ) ) {
361 0 : ctx->capture_ctx->dump_proto_output_dir = tile->exec.dump_proto_dir;
362 0 : ctx->capture_ctx->dump_proto_start_slot = tile->exec.capture_start_slot;
363 0 : ctx->capture_ctx->dump_instr_to_pb = tile->exec.dump_instr_to_pb;
364 0 : ctx->capture_ctx->dump_txn_to_pb = tile->exec.dump_txn_to_pb;
365 0 : ctx->capture_ctx->dump_syscall_to_pb = tile->exec.dump_syscall_to_pb;
366 0 : ctx->capture_ctx->dump_elf_to_pb = tile->exec.dump_elf_to_pb;
367 0 : }
368 :
369 0 : if( strlen( tile->exec.solcap_capture ) ) {
370 0 : ctx->capture_ctx->capture_txns = 0;
371 0 : ctx->capture_ctx->solcap_start_slot = tile->exec.capture_start_slot;
372 0 : ctx->account_updates_flushed = 0;
373 0 : ctx->solcap_publish_buffer_ptr = ctx->capture_ctx->account_updates_buffer;
374 0 : }
375 0 : }
376 :
377 0 : ctx->pending_txn_finalized_msg = 0;
378 0 : }
379 :
380 : /* Publish the next account update event buffered in the capture tile to the replay tile
381 :
382 : TODO: remove this when solcap v2 is here. */
383 : static void
384 : publish_next_capture_ctx_account_update( fd_exec_tile_ctx_t * ctx,
385 0 : fd_stem_context_t * stem ) {
386 0 : if( FD_UNLIKELY( !ctx->capture_ctx ) ) {
387 0 : return;
388 0 : }
389 :
390 : /* Copy the account update event to the buffer */
391 0 : ulong chunk = ctx->capture_replay_out->chunk;
392 0 : uchar * out_ptr = fd_chunk_to_laddr( ctx->capture_replay_out->mem, chunk );
393 0 : fd_capture_ctx_account_update_msg_t * msg = (fd_capture_ctx_account_update_msg_t *)ctx->solcap_publish_buffer_ptr;
394 0 : memcpy( out_ptr, msg, sizeof(fd_capture_ctx_account_update_msg_t) );
395 0 : ctx->solcap_publish_buffer_ptr += sizeof(fd_capture_ctx_account_update_msg_t);
396 0 : out_ptr += sizeof(fd_capture_ctx_account_update_msg_t);
397 :
398 : /* Copy the data to the buffer */
399 0 : ulong data_sz = msg->data_sz;
400 0 : memcpy( out_ptr, ctx->solcap_publish_buffer_ptr, data_sz );
401 0 : ctx->solcap_publish_buffer_ptr += data_sz;
402 0 : out_ptr += data_sz;
403 :
404 : /* Stem publish the account update event */
405 0 : ulong msg_sz = sizeof(fd_capture_ctx_account_update_msg_t) + msg->data_sz;
406 0 : fd_stem_publish( stem, ctx->capture_replay_out->idx, 0UL, chunk, msg_sz, 0UL, 0UL, 0UL );
407 0 : ctx->capture_replay_out->chunk = fd_dcache_compact_next(
408 0 : chunk,
409 0 : msg_sz,
410 0 : ctx->capture_replay_out->chunk0,
411 0 : ctx->capture_replay_out->wmark );
412 :
413 : /* Advance the number of account updates flushed */
414 0 : ctx->account_updates_flushed++;
415 :
416 : /* If we have published all the account updates, reset the buffer pointer and length */
417 0 : if( ctx->account_updates_flushed == ctx->capture_ctx->account_updates_len ) {
418 0 : ctx->capture_ctx->account_updates_buffer_ptr = ctx->capture_ctx->account_updates_buffer;
419 0 : ctx->solcap_publish_buffer_ptr = ctx->capture_ctx->account_updates_buffer;
420 0 : ctx->capture_ctx->account_updates_len = 0UL;
421 0 : ctx->account_updates_flushed = 0UL;
422 0 : }
423 0 : }
424 :
425 : /* Publish the txn finalized message to the replay tile */
426 : static void
427 : publish_txn_finalized_msg( fd_exec_tile_ctx_t * ctx,
428 0 : fd_stem_context_t * stem ) {
429 0 : fd_exec_replay_txn_finalized_msg_t * msg = (fd_exec_replay_txn_finalized_msg_t *)
430 0 : fd_chunk_to_laddr( ctx->exec_replay_out->mem, ctx->exec_replay_out->chunk );
431 0 : msg->exec_tile_id = (uchar)ctx->tile_idx;
432 0 : msg->bank_idx = ctx->txn_ctx->bank_idx;
433 :
434 0 : fd_stem_publish(
435 0 : stem,
436 0 : ctx->exec_replay_out->idx,
437 0 : 0UL,
438 0 : ctx->exec_replay_out->chunk,
439 0 : sizeof(fd_exec_replay_txn_finalized_msg_t),
440 0 : 0UL,
441 0 : 0UL,
442 0 : 0UL );
443 :
444 0 : ctx->exec_replay_out->chunk = fd_dcache_compact_next(
445 0 : ctx->exec_replay_out->chunk,
446 0 : sizeof(fd_exec_replay_txn_finalized_msg_t),
447 0 : ctx->exec_replay_out->chunk0,
448 0 : ctx->exec_replay_out->wmark );
449 :
450 0 : ctx->pending_txn_finalized_msg = 0;
451 0 : }
452 :
453 : static void
454 : after_credit( fd_exec_tile_ctx_t * ctx,
455 : fd_stem_context_t * stem,
456 : int * opt_poll_in,
457 0 : int * charge_busy FD_PARAM_UNUSED ) {
458 : /* If we have outstanding account updates to send to solcap, send them.
459 : Note that we set opt_poll_in to 0 here because we must not consume
460 : any more fragments from the exec tiles before publishing our messages,
461 : so that solcap updates are not interleaved between slots.
462 : */
463 0 : if( FD_UNLIKELY( ctx->capture_ctx && ctx->account_updates_flushed < ctx->capture_ctx->account_updates_len ) ) {
464 0 : publish_next_capture_ctx_account_update( ctx, stem );
465 0 : *opt_poll_in = 0;
466 0 : } else if( ctx->pending_txn_finalized_msg ) {
467 0 : publish_txn_finalized_msg( ctx, stem );
468 0 : *opt_poll_in = 0;
469 0 : }
470 0 : }
471 :
472 : static ulong
473 : populate_allowed_seccomp( fd_topo_t const * topo FD_PARAM_UNUSED,
474 : fd_topo_tile_t const * tile FD_PARAM_UNUSED,
475 : ulong out_cnt,
476 0 : struct sock_filter * out ) {
477 0 : populate_sock_filter_policy_fd_exec_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
478 0 : return sock_filter_policy_fd_exec_tile_instr_cnt;
479 0 : }
480 :
481 : static ulong
482 : populate_allowed_fds( fd_topo_t const * topo FD_PARAM_UNUSED,
483 : fd_topo_tile_t const * tile FD_PARAM_UNUSED,
484 : ulong out_fds_cnt,
485 0 : int * out_fds ) {
486 :
487 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
488 :
489 0 : ulong out_cnt = 0UL;
490 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
491 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
492 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
493 0 : return out_cnt;
494 0 : }
495 :
496 0 : #define STEM_BURST (1UL)
497 : /* Right now, depth of the replay_exec link and depth of the exec_replay
498 : links is 16K. At 1M TPS, that's ~16ms to fill. But we also want to
499 : be conservative here, so we use 1ms. */
500 0 : #define STEM_LAZY (1000000UL)
501 :
502 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_exec_tile_ctx_t
503 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_exec_tile_ctx_t)
504 :
505 0 : #define STEM_CALLBACK_BEFORE_FRAG before_frag
506 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
507 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
508 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
509 :
510 : #include "../../disco/stem/fd_stem.c"
511 :
512 : fd_topo_run_tile_t fd_tile_execor = {
513 : .name = "exec",
514 : .loose_footprint = 0UL,
515 : .populate_allowed_seccomp = populate_allowed_seccomp,
516 : .populate_allowed_fds = populate_allowed_fds,
517 : .scratch_align = scratch_align,
518 : .scratch_footprint = scratch_footprint,
519 : .unprivileged_init = unprivileged_init,
520 : .run = stem_run,
521 : };
|