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