Line data Source code
1 : #include "../poh/fd_poh.h"
2 : #include "../../flamenco/alpenglow/fd_block_marker_serde.h"
3 : #include "../replay/fd_replay_tile.h"
4 : #include "../../disco/tiles.h"
5 : #include "../../discof/fd_startup.h"
6 : #include "../../util/pod/fd_pod.h"
7 : #include <time.h> /* CLOCK_REALTIME for the startup gate seccomp policy */
8 : #include "generated/fd_motor_tile_seccomp.h"
9 :
10 : /* The motor tile replaces the poh tile under Alpenglow.
11 :
12 : Structure of an Alpenglow block:
13 :
14 : header | entries* | footer | alpentick
15 :
16 : Every block begins with a header, which contains the parent slot and
17 : parent block hash. The header is serialized and sent to shred, which
18 : produces an entire entry batch (a fixed-32 shred FEC set) containing
19 : exclusively those two fields (the remainder is padding).
20 :
21 : Following the header are entries. As in PoH, each entry is sent to
22 : shred which groups into entry batches that divide into FEC sets.
23 : Unlike in PoH, entries cannot be interleaved with ticks. Every entry
24 : in the block has num_hashes==1. A transaction entry hashes
25 : sha256(prev || merkle_root(txn signatures)), where the mixin is
26 : computed by the execle tile (again, this is the same as in PoH).
27 :
28 : Next is the footer, which contains various fields, most notably the
29 : bank hash. The various fields in the footer feed into the bank hash
30 : itself, resulting in a sequential and somewhat circular dependency
31 : to construct the footer.
32 :
33 : Every block concludes with the alpentick, the only tick in the block,
34 : which as in PoH is sha256(prev) with no mixin. PoH is not a
35 : component of the Alpenglow protocol, but for legacy reasons Agave
36 : continues to produce a PoH-style tick at the very end of a block.
37 : This format is validated by Agave or the block will not be accepted,
38 : so Firedancer is required to do the same.
39 :
40 : Currently, the motor tile computes the alpentick, but
41 : replay needs in order to compute the bank hash. The result is a
42 : circular dance involving delicate coordination between motor and
43 : replay.
44 :
45 : When pack is done, motor hashes the alpentick and sends it to replay
46 : in the slot ended message. Replay picks the footer timestamp and
47 : certs, applies them, computes the bank hash, and publishes the footer
48 : fields back (REPLAY_SIG_LEADER_FOOTER). Motor then serializes the
49 : footer and sends it and the alpentick to shred to finish the block. */
50 :
51 0 : #define IN_KIND_REPLAY (0)
52 0 : #define IN_KIND_PACK (1)
53 0 : #define IN_KIND_EXECLE (2)
54 :
55 : struct fd_motor_in {
56 : fd_wksp_t * mem;
57 : ulong chunk0;
58 : ulong wmark;
59 : ulong mtu;
60 : };
61 : typedef struct fd_motor_in fd_motor_in_t;
62 :
63 : struct fd_motor_tile {
64 :
65 : /* Alpenglow-specific */
66 :
67 : ulong slot;
68 : ulong parent_slot;
69 : fd_hash_t parent_cmr; /* required by shred to produce chained merkle shreds */
70 : fd_hash_t parent_dmr;
71 : fd_hash_t parent_alpentick;
72 :
73 : /* Inherited from fd_poh_tile.c */
74 :
75 : fd_hash_t poh_hash;
76 :
77 : uint expect_pack_idx; /* see long comment in fd_poh_tile */
78 :
79 : fd_leader_txn_timing_table_t * timing_tables; /* per-transaction leader timings for the GUI, read by replay */
80 : ulong timing_table_idx;
81 : ulong timing_table_max; /* records per table */
82 :
83 : fd_startup_gate_t startup_gate[1];
84 :
85 : int in_kind[ 64 ];
86 : fd_motor_in_t in[ 64 ];
87 :
88 : fd_poh_out_t shred_out[ 1 ];
89 : fd_poh_out_t replay_out[ 1 ];
90 : };
91 : typedef struct fd_motor_tile fd_motor_tile_t;
92 :
93 : FD_STATIC_ASSERT( FD_POH_SHRED_MTU-sizeof(fd_entry_batch_meta_t)>=FD_BLOCK_MARKER_SER_MAX, fd_motor_tile );
94 :
95 : static ulong
96 0 : prepare_header( fd_motor_tile_t * ctx ) {
97 0 : fd_block_marker_t marker[1];
98 0 : marker->kind = FD_BLOCK_MARKER_KIND_HEADER;
99 0 : marker->header.parent_slot = ctx->parent_slot;
100 0 : marker->header.parent_block_id = ctx->parent_dmr;
101 :
102 0 : ulong marker_sz = fd_block_marker_ser( marker, (uchar *)fd_chunk_to_laddr( ctx->shred_out->mem, ctx->shred_out->chunk )+sizeof(fd_entry_batch_meta_t) );
103 0 : if( FD_UNLIKELY( !marker_sz ) ) FD_LOG_ERR(( "fd_block_marker_ser(HEADER) failed" ));
104 0 : return marker_sz;
105 0 : }
106 :
107 : static ulong
108 : prepare_entry( fd_motor_tile_t * ctx,
109 : fd_microblock_trailer_t const * trailer,
110 : ulong txn_cnt,
111 0 : fd_txn_p_t const * txns ) {
112 0 : ulong executed_txn_cnt = 0UL;
113 0 : for( ulong i=0UL; i<txn_cnt; i++ ) executed_txn_cnt += !!(txns[ i ].flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS);
114 0 : if( FD_UNLIKELY( !executed_txn_cnt ) ) return 0UL;
115 :
116 0 : if( FD_LIKELY( ctx->timing_tables ) ) {
117 0 : fd_leader_txn_timing_table_t * table = fd_leader_txn_timing_table( ctx->timing_tables, ctx->timing_table_idx, ctx->timing_table_max );
118 0 : long mixed_ticks = fd_tickcount();
119 0 : for( ulong i=0UL; i<txn_cnt && table->cnt<ctx->timing_table_max; i++ ) {
120 0 : if( FD_UNLIKELY( !(txns[ i ].flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS) ) ) continue;
121 0 : table->rec[ table->cnt++ ] = (fd_leader_txn_timing_rec_t){
122 0 : .received_ns = txns[ i ].first_seen_nanos,
123 0 : .dispatched_ticks = trailer->exec_start_ticks,
124 0 : .replayed_ticks = trailer->exec_end_ticks,
125 0 : .poh_mixed_ticks = mixed_ticks,
126 0 : };
127 0 : }
128 0 : }
129 :
130 0 : uchar data[ 64 ];
131 0 : memcpy( data, ctx->poh_hash.uc, sizeof(fd_hash_t) );
132 0 : memcpy( data+32UL, trailer->hash, sizeof(fd_hash_t) );
133 0 : fd_sha256_hash( data, sizeof(data), ctx->poh_hash.uc );
134 :
135 0 : fd_entry_batch_header_t * entry = (fd_entry_batch_header_t *)((uchar *)fd_chunk_to_laddr( ctx->shred_out->mem, ctx->shred_out->chunk )+sizeof(fd_entry_batch_meta_t));
136 0 : entry->hashcnt_delta = 1UL; /* every Alpenglow entry has num_hashes==1 */
137 0 : entry->txn_cnt = executed_txn_cnt;
138 0 : memcpy( entry->hash, ctx->poh_hash.uc, sizeof(fd_hash_t) );
139 :
140 0 : uchar * payload = (uchar *)(entry+1UL);
141 0 : ulong payload_sz = 0UL;
142 0 : for( ulong i=0UL; i<txn_cnt; i++ ) {
143 0 : fd_txn_p_t const * txn = txns + i;
144 0 : if( FD_UNLIKELY( !(txn->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS) ) ) continue;
145 :
146 0 : fd_memcpy( payload+payload_sz, txn->payload, txn->payload_sz );
147 0 : payload_sz += txn->payload_sz;
148 0 : }
149 :
150 0 : return sizeof(fd_entry_batch_header_t)+payload_sz;
151 0 : }
152 :
153 : static ulong
154 : prepare_footer( fd_motor_tile_t * ctx,
155 0 : fd_replay_leader_footer_t const * footer ) {
156 0 : fd_block_marker_t marker[1];
157 0 : marker->kind = FD_BLOCK_MARKER_KIND_FOOTER;
158 0 : marker->footer = footer->footer;
159 :
160 0 : ulong marker_sz = fd_block_marker_ser( marker, (uchar *)fd_chunk_to_laddr( ctx->shred_out->mem, ctx->shred_out->chunk )+sizeof(fd_entry_batch_meta_t) );
161 0 : if( FD_UNLIKELY( !marker_sz ) ) FD_LOG_ERR(( "fd_block_marker_ser(FOOTER) failed" ));
162 0 : return marker_sz;
163 0 : }
164 :
165 : static ulong
166 0 : prepare_alpentick( fd_motor_tile_t * ctx ) {
167 0 : fd_entry_batch_header_t * entry = (fd_entry_batch_header_t *)((uchar *)fd_chunk_to_laddr( ctx->shred_out->mem, ctx->shred_out->chunk )+sizeof(fd_entry_batch_meta_t));
168 0 : entry->hashcnt_delta = 1UL;
169 0 : entry->txn_cnt = 0UL;
170 0 : memcpy( entry->hash, ctx->poh_hash.uc, sizeof(fd_hash_t) );
171 :
172 0 : return sizeof(fd_entry_batch_header_t);
173 0 : }
174 :
175 : static void
176 : publish_shred( fd_motor_tile_t * ctx,
177 : fd_stem_context_t * stem,
178 : ulong payload_sz,
179 0 : int block_complete ) {
180 0 : fd_entry_batch_meta_t * meta = fd_chunk_to_laddr( ctx->shred_out->mem, ctx->shred_out->chunk );
181 0 : meta->parent_offset = ctx->slot - ctx->parent_slot;
182 0 : meta->reference_tick = 0UL; /* Alpenglow blocks have no tick schedule */
183 0 : meta->block_complete = block_complete;
184 :
185 0 : memcpy( meta->parent_block_id, ctx->parent_cmr.uc, sizeof(fd_hash_t) );
186 0 : meta->parent_block_id_valid = 1;
187 :
188 0 : ulong sz = sizeof(fd_entry_batch_meta_t)+payload_sz;
189 0 : ulong sig = fd_disco_poh_sig( ctx->slot, POH_PKT_TYPE_MICROBLOCK, 0UL );
190 0 : ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
191 0 : fd_stem_publish( stem, ctx->shred_out->idx, sig, ctx->shred_out->chunk, sz, 0UL, 0UL, tspub );
192 0 : ctx->shred_out->chunk = fd_dcache_compact_next( ctx->shred_out->chunk, sz, ctx->shred_out->chunk0, ctx->shred_out->wmark );
193 0 : }
194 :
195 : static void
196 : init_block( fd_motor_tile_t * ctx,
197 : fd_stem_context_t * stem,
198 0 : fd_became_leader_t const * became_leader ) {
199 0 : ctx->slot = became_leader->slot;
200 0 : ctx->poh_hash = ctx->parent_alpentick;
201 :
202 0 : if( FD_LIKELY( ctx->timing_tables ) ) {
203 0 : ctx->timing_table_idx ^= 1UL;
204 0 : fd_leader_txn_timing_table_t * table = fd_leader_txn_timing_table( ctx->timing_tables, ctx->timing_table_idx, ctx->timing_table_max );
205 0 : table->slot = ctx->slot;
206 0 : table->cnt = 0UL;
207 0 : }
208 :
209 0 : publish_shred( ctx, stem, prepare_header( ctx ), -1 );
210 0 : }
211 :
212 : static void
213 : fini_block( fd_motor_tile_t * ctx,
214 : fd_stem_context_t * stem,
215 0 : fd_replay_leader_footer_t const * footer ) {
216 0 : publish_shred( ctx, stem, prepare_footer( ctx, footer ), -1 );
217 0 : publish_shred( ctx, stem, prepare_alpentick( ctx ), 1 );
218 0 : }
219 :
220 : static void
221 : done_packing( fd_motor_tile_t * ctx,
222 : fd_stem_context_t * stem,
223 0 : fd_done_packing_t const * msg ) {
224 :
225 0 : fd_sha256_hash( ctx->poh_hash.uc, sizeof(fd_hash_t), ctx->poh_hash.uc ); /* alpentick */
226 :
227 0 : fd_poh_leader_slot_ended_t * dst = fd_chunk_to_laddr( ctx->replay_out->mem, ctx->replay_out->chunk );
228 0 : fd_memset( dst, 0, sizeof(fd_poh_leader_slot_ended_t) );
229 0 : dst->completed = 1;
230 0 : dst->slot = ctx->slot;
231 0 : dst->timing_table_idx = ctx->timing_table_idx;
232 0 : memcpy( dst->blockhash, ctx->poh_hash.uc, sizeof(fd_hash_t) ); /* write the "alpentick" to the existing blockhash field */
233 :
234 0 : dst->microblock_count = msg->microblocks_in_slot;
235 0 : dst->pack_block_cost = msg->limits_usage->block_cost;
236 0 : dst->pack_vote_cost = msg->limits_usage->vote_cost;
237 0 : dst->pack_data_bytes = msg->limits_usage->block_data_bytes;
238 0 : dst->bundle_txn_count = msg->bundle_txn_count;
239 0 : dst->pack_end_reason = msg->end_slot_reason;
240 0 : dst->pack_start_ns = msg->pack_start_ns;
241 0 : dst->pack_end_ns = msg->pack_end_ns;
242 :
243 : /* publish alpentick to replay */
244 :
245 0 : ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
246 0 : fd_stem_publish( stem, ctx->replay_out->idx, 0UL, ctx->replay_out->chunk, sizeof(fd_poh_leader_slot_ended_t), 0UL, 0UL, tspub );
247 0 : ctx->replay_out->chunk = fd_dcache_compact_next( ctx->replay_out->chunk, sizeof(fd_poh_leader_slot_ended_t), ctx->replay_out->chunk0, ctx->replay_out->wmark );
248 0 : }
249 :
250 : static inline fd_poh_out_t
251 : out1( fd_topo_t const * topo,
252 : fd_topo_tile_t const * tile,
253 0 : char const * name ) {
254 0 : ulong idx = ULONG_MAX;
255 :
256 0 : for( ulong i=0UL; i<tile->out_cnt; i++ ) {
257 0 : fd_topo_link_t const * link = &topo->links[ tile->out_link_id[ i ] ];
258 0 : if( !strcmp( link->name, name ) ) {
259 0 : if( FD_UNLIKELY( idx!=ULONG_MAX ) ) FD_LOG_ERR(( "tile %s:%lu had multiple output links named %s but expected one", tile->name, tile->kind_id, name ));
260 0 : idx = i;
261 0 : }
262 0 : }
263 :
264 0 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) FD_LOG_ERR(( "tile %s:%lu had no output link named %s", tile->name, tile->kind_id, name ));
265 :
266 0 : void * mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ idx ] ].dcache_obj_id ].wksp_id ].wksp;
267 0 : ulong chunk0 = fd_dcache_compact_chunk0( mem, topo->links[ tile->out_link_id[ idx ] ].dcache );
268 0 : ulong wmark = fd_dcache_compact_wmark ( mem, topo->links[ tile->out_link_id[ idx ] ].dcache, topo->links[ tile->out_link_id[ idx ] ].mtu );
269 :
270 0 : return (fd_poh_out_t){ .idx = idx, .mem = mem, .chunk0 = chunk0, .wmark = wmark, .chunk = chunk0 };
271 0 : }
272 :
273 : FD_FN_CONST static inline ulong
274 0 : scratch_align( void ) {
275 0 : return 128UL;
276 0 : }
277 :
278 : FD_FN_PURE static inline ulong
279 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
280 0 : (void)tile;
281 0 : ulong l = FD_LAYOUT_INIT;
282 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_motor_tile_t), sizeof(fd_motor_tile_t) );
283 0 : return FD_LAYOUT_FINI( l, scratch_align() );
284 0 : }
285 :
286 : static inline void
287 : after_credit( fd_motor_tile_t * ctx,
288 : fd_stem_context_t * stem,
289 : int * opt_poll_in,
290 0 : int * charge_busy ) {
291 0 : (void)stem;
292 0 : (void)opt_poll_in;
293 0 : (void)charge_busy;
294 :
295 0 : fd_startup_gate_idle( ctx->startup_gate );
296 0 : }
297 :
298 : static int
299 : before_frag( fd_motor_tile_t * ctx,
300 : ulong in_idx,
301 : ulong seq FD_PARAM_UNUSED,
302 0 : ulong sig ) {
303 0 : switch( ctx->in_kind[ in_idx ] ) {
304 0 : case IN_KIND_REPLAY: return !( sig==REPLAY_SIG_RESET ||
305 0 : sig==REPLAY_SIG_BECAME_LEADER ||
306 0 : sig==REPLAY_SIG_LEADER_FOOTER );
307 0 : case IN_KIND_PACK: return fd_disco_execle_sig_slot( sig )!=ctx->slot; /* done packing is the only pack frag that names our slot */
308 0 : case IN_KIND_EXECLE: return fd_disco_execle_sig_slot( sig )!=ctx->slot; /* microblocks of our block */
309 0 : default: return 1;
310 0 : }
311 0 : }
312 :
313 : static inline int
314 : returnable_frag( fd_motor_tile_t * ctx,
315 : ulong in_idx,
316 : ulong seq,
317 : ulong sig,
318 : ulong chunk,
319 : ulong sz,
320 : ulong ctl,
321 : ulong tsorig,
322 : ulong tspub,
323 0 : fd_stem_context_t * stem ) {
324 0 : (void)seq;
325 0 : (void)ctl;
326 0 : (void)tsorig;
327 0 : (void)tspub;
328 :
329 0 : fd_startup_gate_busy( ctx->startup_gate );
330 :
331 0 : if( FD_UNLIKELY( chunk<ctx->in[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz>ctx->in[ in_idx ].mtu ) )
332 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->in[ in_idx ].chunk0, ctx->in[ in_idx ].wmark ));
333 :
334 0 : if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_EXECLE || ctx->in_kind[ in_idx ]==IN_KIND_PACK ) ) {
335 0 : uint pack_idx = (uint)fd_disco_execle_sig_pack_idx( sig );
336 0 : if( FD_UNLIKELY( ((int)(pack_idx-ctx->expect_pack_idx))<0L ) ) FD_LOG_ERR(( "received out of order pack_idx %u (expecting %u)", pack_idx, ctx->expect_pack_idx ));
337 0 : if( FD_UNLIKELY( pack_idx!=ctx->expect_pack_idx ) ) return 1;
338 0 : ctx->expect_pack_idx++;
339 0 : }
340 :
341 0 : switch( ctx->in_kind[ in_idx ] ) {
342 0 : case IN_KIND_REPLAY: {
343 0 : if( FD_UNLIKELY( sig==REPLAY_SIG_BECAME_LEADER ) ) {
344 0 : fd_became_leader_t const * became_leader = fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk );
345 0 : init_block( ctx, stem, became_leader );
346 0 : } else if( FD_UNLIKELY( sig==REPLAY_SIG_LEADER_FOOTER ) ) {
347 0 : fd_replay_leader_footer_t const * footer = fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk );
348 0 : fini_block( ctx, stem, footer );
349 0 : } else if( FD_LIKELY( sig==REPLAY_SIG_RESET ) ) {
350 0 : fd_poh_reset_t const * reset = fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk );
351 0 : ctx->parent_slot = reset->completed_slot;
352 0 : memcpy( ctx->parent_cmr.uc, reset->completed_cmr, sizeof(fd_hash_t) );
353 0 : memcpy( ctx->parent_dmr.uc, reset->completed_dmr, sizeof(fd_hash_t) );
354 0 : memcpy( ctx->parent_alpentick.uc, reset->completed_blockhash, sizeof(fd_hash_t) );
355 0 : }
356 0 : break;
357 0 : }
358 0 : case IN_KIND_PACK: {
359 0 : fd_done_packing_t const * msg = fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk );
360 0 : done_packing( ctx, stem, msg );
361 0 : break;
362 0 : }
363 0 : case IN_KIND_EXECLE: {
364 0 : FD_TEST( sz>=sizeof(fd_microblock_trailer_t) && (sz-sizeof(fd_microblock_trailer_t))%sizeof(fd_txn_p_t)==0UL );
365 0 : ulong txn_cnt = (sz-sizeof(fd_microblock_trailer_t))/sizeof(fd_txn_p_t);
366 0 : fd_txn_p_t const * txns = fd_chunk_to_laddr_const( ctx->in[ in_idx ].mem, chunk );
367 0 : fd_microblock_trailer_t const * trailer = fd_type_pun_const( (uchar const *)txns+sz-sizeof(fd_microblock_trailer_t) );
368 0 : ulong payload_sz = prepare_entry( ctx, trailer, txn_cnt, txns );
369 0 : if( FD_LIKELY( payload_sz ) ) publish_shred( ctx, stem, payload_sz, 0 );
370 0 : break;
371 0 : }
372 0 : default: {
373 0 : FD_LOG_ERR(( "unexpected input kind %d", ctx->in_kind[ in_idx ] ));
374 0 : break;
375 0 : }
376 0 : }
377 :
378 0 : return 0;
379 0 : }
380 :
381 : static void
382 : unprivileged_init( fd_topo_t const * topo,
383 0 : fd_topo_tile_t const * tile ) {
384 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
385 :
386 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
387 0 : fd_motor_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_motor_tile_t ), sizeof( fd_motor_tile_t ) );
388 :
389 0 : ctx->expect_pack_idx = 0U;
390 :
391 0 : FD_CHECK_ERR( tile->in_cnt<=sizeof(ctx->in)/sizeof(ctx->in[0]), "too many input links" );
392 :
393 0 : for( ulong i=0UL; i<tile->in_cnt; i++ ) {
394 0 : fd_topo_link_t const * link = &topo->links[ tile->in_link_id[ i ] ];
395 0 : fd_topo_wksp_t const * link_wksp = &topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ];
396 :
397 0 : ctx->in[ i ].mem = link_wksp->wksp;
398 0 : ctx->in[ i ].chunk0 = fd_dcache_compact_chunk0( ctx->in[ i ].mem, link->dcache );
399 0 : ctx->in[ i ].wmark = fd_dcache_compact_wmark ( ctx->in[ i ].mem, link->dcache, link->mtu );
400 0 : ctx->in[ i ].mtu = link->mtu;
401 :
402 0 : if( !strcmp( link->name, "replay_out" ) ) ctx->in_kind[ i ] = IN_KIND_REPLAY;
403 0 : else if( !strcmp( link->name, "pack_poh" ) ) ctx->in_kind[ i ] = IN_KIND_PACK;
404 0 : else if( !strcmp( link->name, "execle_poh" ) ) ctx->in_kind[ i ] = IN_KIND_EXECLE;
405 0 : else FD_LOG_ERR(( "unexpected input link name %s", link->name ));
406 0 : }
407 :
408 0 : *ctx->replay_out = out1( topo, tile, "poh_replay" );
409 0 : *ctx->shred_out = out1( topo, tile, "poh_shred" );
410 :
411 0 : ulong ldr_tt_obj_id = fd_pod_query_ulong( topo->props, "ldr_tt", ULONG_MAX );
412 0 : ctx->timing_tables = ldr_tt_obj_id==ULONG_MAX ? NULL : fd_topo_obj_laddr( topo, ldr_tt_obj_id );
413 0 : ctx->timing_table_idx = 0UL;
414 0 : ctx->timing_table_max = tile->motor.max_txn_per_slot;
415 :
416 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
417 0 : if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
418 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
419 :
420 0 : fd_startup_gate_init( ctx->startup_gate, topo, tile->in_cnt );
421 0 : }
422 :
423 : static ulong
424 : populate_allowed_seccomp( fd_topo_t const * topo,
425 : fd_topo_tile_t const * tile,
426 : ulong out_cnt,
427 0 : struct sock_filter * out ) {
428 0 : (void)topo;
429 0 : (void)tile;
430 :
431 0 : populate_sock_filter_policy_fd_motor_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
432 0 : return sock_filter_policy_fd_motor_tile_instr_cnt;
433 0 : }
434 :
435 : static ulong
436 : populate_allowed_fds( fd_topo_t const * topo,
437 : fd_topo_tile_t const * tile,
438 : ulong out_fds_cnt,
439 0 : int * out_fds ) {
440 0 : (void)topo;
441 0 : (void)tile;
442 :
443 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
444 :
445 0 : ulong out_cnt = 0UL;
446 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
447 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
448 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
449 0 : return out_cnt;
450 0 : }
451 :
452 0 : #define STEM_BURST (2UL) /* footer + alpentick */
453 :
454 : /* See explanation in fd_pack */
455 0 : #define STEM_LAZY (128L*3000L)
456 :
457 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_motor_tile_t
458 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_motor_tile_t)
459 :
460 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
461 0 : #define STEM_CALLBACK_BEFORE_FRAG before_frag
462 0 : #define STEM_CALLBACK_RETURNABLE_FRAG returnable_frag
463 :
464 : #include "../../disco/stem/fd_stem.c"
465 :
466 : fd_topo_run_tile_t fd_tile_motor = {
467 : .name = "motor",
468 : .populate_allowed_seccomp = populate_allowed_seccomp,
469 : .populate_allowed_fds = populate_allowed_fds,
470 : .scratch_align = scratch_align,
471 : .scratch_footprint = scratch_footprint,
472 : .privileged_init = NULL,
473 : .unprivileged_init = unprivileged_init,
474 : .run = stem_run,
475 : };
|