LCOV - code coverage report
Current view: top level - discof/motor - fd_motor_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 261 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 34 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 <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             : };

Generated by: LCOV version 1.14