LCOV - code coverage report
Current view: top level - discof/motor - fd_motor_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 254 0.0 %
Date: 2026-09-17 04:28:31 Functions: 0 17 0.0 %

          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             : };

Generated by: LCOV version 1.14