LCOV - code coverage report
Current view: top level - discof/tower - fd_tower_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 251 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : 
       3             : #include "../../choreo/fd_choreo.h"
       4             : #include "../../util/pod/fd_pod_format.h"
       5             : #include "../../disco/keyguard/fd_keyload.h"
       6             : #include "../../disco/topo/fd_topo.h"
       7             : #include "../../funk/fd_funk.h"
       8             : #include "../../flamenco/fd_flamenco_base.h"
       9             : #include "generated/fd_tower_tile_seccomp.h"
      10             : 
      11           0 : #define IN_KIND_GOSSIP ( 0)
      12           0 : #define IN_KIND_REPLAY ( 1)
      13           0 : #define IN_KIND_SHRED  ( 2)
      14           0 : #define IN_KIND_SIGN   ( 3)
      15             : #define MAX_IN_LINKS   (16)
      16             : 
      17             : #define SIGN_OUT_IDX (0)
      18             : 
      19             : #define VOTER_MAX       ( 4096UL )
      20             : #define VOTER_FOOTPRINT ( 40UL ) /* serialized footprint */
      21             : 
      22             : typedef struct {
      23             :   fd_wksp_t * mem;
      24             :   ulong       chunk0;
      25             :   ulong       wmark;
      26             :   ulong       mtu;
      27             : } in_ctx_t;
      28             : 
      29             : typedef struct {
      30             :   fd_pubkey_t       identity_key[1];
      31             :   fd_pubkey_t       vote_acc[1];
      32             :   fd_funk_rec_key_t funk_key;
      33             :   ulong             seed;
      34             : 
      35             :   uchar    in_kind [MAX_IN_LINKS];
      36             :   in_ctx_t in_links[MAX_IN_LINKS];
      37             : 
      38             :   ulong replay_out_idx;
      39             : 
      40             :   ulong       send_out_idx;
      41             :   fd_wksp_t * send_out_mem;
      42             :   ulong       send_out_chunk0;
      43             :   ulong       send_out_wmark;
      44             :   ulong       send_out_chunk;
      45             : 
      46             :   fd_epoch_t * epoch;
      47             :   fd_ghost_t * ghost;
      48             :   fd_tower_t * tower;
      49             : 
      50             :   ulong        root;
      51             :   ulong        processed; /* highest processed slot (replayed & counted votes) */
      52             :   ulong        confirmed; /* highest confirmed slot (2/3 of stake has voted) */
      53             :   ulong        finalized; /* highest finalized slot (2/3 of stake has rooted) */
      54             : 
      55             :   fd_hash_t                   bank_hash;   /* bank hash of the slot received from replay */
      56             :   fd_hash_t                   block_hash;  /* last microblock header hash of slot received from replay */
      57             :   fd_hash_t                   slot_hash;   /* hash_id of the slot received from replay (block id)*/
      58             :   fd_hash_t                   parent_hash; /* parent hash_id of the slot received from replay */
      59             : 
      60             :   fd_gossip_duplicate_shred_t duplicate_shred;
      61             :   uchar                       duplicate_shred_chunk[FD_EQVOC_PROOF_CHUNK_SZ];
      62             :   uchar *                     epoch_voters_buf;
      63             :   char                        funk_file[PATH_MAX];
      64             :   fd_funk_t                   funk[1];
      65             :   fd_gossip_vote_t            gossip_vote;
      66             :   fd_lockout_offset_t         lockouts[FD_TOWER_VOTE_MAX];
      67             :   fd_tower_t *                scratch;
      68             :   uchar *                     vote_ix_buf;
      69             : } ctx_t;
      70             : 
      71             : static void
      72           0 : update_epoch( ctx_t * ctx, ulong sz ) {
      73           0 :   fd_voter_t * epoch_voters = fd_epoch_voters( ctx->epoch );
      74           0 :   ctx->epoch->total_stake   = 0;
      75             : 
      76           0 :   ulong off = 0;
      77           0 :   while( FD_LIKELY( off < sz ) ) {
      78           0 :     fd_pubkey_t pubkey = *(fd_pubkey_t *)fd_type_pun( ctx->epoch_voters_buf + off );
      79           0 :     off += sizeof(fd_pubkey_t);
      80             : 
      81           0 :     ulong stake = *(ulong *)fd_type_pun( ctx->epoch_voters_buf + off );
      82           0 :     off += sizeof(ulong);
      83             : 
      84           0 : #   if FD_EPOCH_USE_HANDHOLDING
      85           0 :     FD_TEST( !fd_epoch_voters_query( epoch_voters, pubkey, NULL ) );
      86           0 :     FD_TEST( fd_epoch_voters_key_cnt( epoch_voters ) < fd_epoch_voters_key_max( epoch_voters ) );
      87           0 : #   endif
      88             : 
      89           0 :     fd_voter_t * voter = fd_epoch_voters_insert( epoch_voters, pubkey );
      90           0 :     voter->rec.uc[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_FUNK_KEY_TYPE_ACC;
      91             : 
      92           0 : #   if FD_EPOCH_USE_HANDHOLDING
      93           0 :     FD_TEST( 0 == memcmp( &voter->key, &pubkey, sizeof(fd_pubkey_t) ) );
      94           0 :     FD_TEST( fd_epoch_voters_query( epoch_voters, voter->key, NULL ) );
      95           0 : #   endif
      96             : 
      97           0 :     voter->stake            = stake;
      98           0 :     voter->replay_vote.slot = FD_SLOT_NULL;
      99           0 :     voter->gossip_vote.slot = FD_SLOT_NULL;
     100           0 :     voter->rooted_vote.slot = FD_SLOT_NULL;
     101             : 
     102           0 :     ctx->epoch->total_stake += stake;
     103           0 :   }
     104           0 : }
     105             : 
     106             : static void
     107           0 : update_ghost( ctx_t * ctx, fd_funk_txn_t * txn ) {
     108           0 :   fd_funk_t *  funk  = ctx->funk;
     109           0 :   fd_epoch_t * epoch = ctx->epoch;
     110           0 :   fd_ghost_t * ghost = ctx->ghost;
     111             : 
     112           0 :   fd_voter_t * epoch_voters = fd_epoch_voters( epoch );
     113           0 :   for( ulong i = 0; i < fd_epoch_voters_slot_cnt( epoch_voters ); i++ ) {
     114           0 :     if( FD_LIKELY( fd_epoch_voters_key_inval( epoch_voters[i].key ) ) ) continue /* most slots are empty */;
     115             : 
     116             :     /* TODO we can optimize this funk query to only check through the
     117             :        last slot on this fork this function was called on. currently
     118             :        rec_query_global traverses all the way back to the root. */
     119             : 
     120           0 :     fd_voter_t *             voter = &epoch_voters[i];
     121             : 
     122             :     /* Fetch the vote account's vote slot and root slot from the vote
     123             :        account, re-trying if there is a Funk conflict. */
     124             : 
     125           0 :     ulong vote = FD_SLOT_NULL;
     126           0 :     ulong root = FD_SLOT_NULL;
     127             : 
     128           0 :     for(;;) {
     129           0 :       fd_funk_rec_query_t   query;
     130           0 :       fd_funk_rec_t const * rec = fd_funk_rec_query_try_global( funk, txn, &voter->rec, NULL, &query );
     131           0 :       if( FD_UNLIKELY( !rec ) ) break;
     132           0 :       fd_voter_state_t const * state = fd_voter_state( funk, rec );
     133           0 :       if( FD_UNLIKELY( !state ) ) break;
     134           0 :       vote = fd_voter_state_vote( state );
     135           0 :       root = fd_voter_state_root( state );
     136           0 :       if( FD_LIKELY( fd_funk_rec_query_test( &query ) == FD_FUNK_SUCCESS ) ) break;
     137           0 :     }
     138             : 
     139             :     /* Only process votes for slots >= root. Ghost requires vote slot
     140             :         to already exist in the ghost tree. */
     141           0 :     if( FD_LIKELY( vote != FD_SLOT_NULL && vote >= fd_ghost_root( ghost )->slot ) ) {
     142             :       /* Check if it has crossed the equivocation safety and optimistic
     143             :          confirmation thresholds. */
     144             : 
     145           0 :       fd_ghost_ele_t const * ele = fd_ghost_query_const( ghost, fd_ghost_hash( ghost, vote ) );
     146             : 
     147             :       /* Error if the node's vote slot is not in ghost. This is an
     148             :          invariant violation, because we know their tower must be on the
     149             :          same fork as this current one that we're processing, and so by
     150             :          definition their vote slot must be in our ghost (ie. we can't
     151             :          have rooted past it or be on a different fork). */
     152             : 
     153           0 :       if( FD_UNLIKELY( !ele ) ) FD_LOG_ERR(( "[%s] voter %s's vote slot %lu was not in ghost", __func__, FD_BASE58_ENC_32_ALLOCA(&voter->key), vote ));
     154             : 
     155           0 :       fd_ghost_replay_vote( ghost, voter, &ele->key );
     156           0 :       double pct = (double)ele->replay_stake / (double)epoch->total_stake;
     157           0 :       if( FD_UNLIKELY( pct > FD_CONFIRMED_PCT ) ) ctx->confirmed = fd_ulong_max( ctx->confirmed, ele->slot );
     158           0 :     }
     159             : 
     160             :     /* Check if this voter's root >= ghost root. We can't process
     161             :         other voters' roots that precede the ghost root. */
     162             : 
     163           0 :     if( FD_LIKELY( root != FD_SLOT_NULL && root >= fd_ghost_root( ghost )->slot ) ) {
     164           0 :       fd_ghost_ele_t const * ele = fd_ghost_query( ghost, fd_ghost_hash( ghost, root ) );
     165             : 
     166             :       /* Error if the node's root slot is not in ghost. This is an
     167             :          invariant violation, because we know their tower must be on the
     168             :          same fork as this current one that we're processing, and so by
     169             :          definition their root slot must be in our ghost (ie. we can't
     170             :          have rooted past it or be on a different fork). */
     171             : 
     172           0 :       if( FD_UNLIKELY( !ele ) ) FD_LOG_ERR(( "[%s] voter %s's root slot %lu was not in ghost", __func__, FD_BASE58_ENC_32_ALLOCA(&voter->key), root ));
     173             : 
     174           0 :       fd_ghost_rooted_vote( ghost, voter, root );
     175           0 :       double pct = (double)ele->rooted_stake / (double)epoch->total_stake;
     176           0 :       if( FD_UNLIKELY( pct > FD_FINALIZED_PCT ) ) ctx->finalized = fd_ulong_max( ctx->finalized, ele->slot );
     177           0 :     }
     178           0 :   }
     179           0 : }
     180             : 
     181             : 
     182             : FD_FN_CONST static inline ulong
     183           0 : scratch_align( void ) {
     184           0 :   return 128UL;
     185           0 : }
     186             : 
     187             : FD_FN_PURE static inline ulong
     188           0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     189           0 :   return FD_LAYOUT_FINI(
     190           0 :     FD_LAYOUT_APPEND(
     191           0 :     FD_LAYOUT_APPEND(
     192           0 :     FD_LAYOUT_APPEND(
     193           0 :     FD_LAYOUT_APPEND(
     194           0 :     FD_LAYOUT_APPEND(
     195           0 :     FD_LAYOUT_APPEND(
     196           0 :     FD_LAYOUT_INIT,
     197           0 :       alignof(ctx_t),      sizeof(ctx_t)                      ),
     198           0 :       fd_epoch_align(),    fd_epoch_footprint( FD_VOTER_MAX ) ),
     199           0 :       fd_ghost_align(),    fd_ghost_footprint( FD_BLOCK_MAX ) ),
     200           0 :       fd_tower_align(),    fd_tower_footprint()               ), /* our tower */
     201           0 :       fd_tower_align(),    fd_tower_footprint()               ), /* scratch */
     202           0 :       128UL,               VOTER_FOOTPRINT * VOTER_MAX        ), /* scratch */
     203           0 :     scratch_align() );
     204           0 : }
     205             : 
     206             : static void
     207             : during_frag( ctx_t * ctx,
     208             :              ulong   in_idx,
     209             :              ulong   seq FD_PARAM_UNUSED,
     210             :              ulong   sig,
     211             :              ulong   chunk,
     212             :              ulong   sz,
     213           0 :              ulong   ctl FD_PARAM_UNUSED ) {
     214           0 :   uint             in_kind = ctx->in_kind[in_idx];
     215           0 :   in_ctx_t const * in_ctx  = &ctx->in_links[in_idx];
     216           0 :   switch( in_kind ) {
     217             : 
     218           0 :     case IN_KIND_GOSSIP: {
     219           0 :       uchar const * chunk_laddr = fd_chunk_to_laddr_const( in_ctx->mem, chunk );
     220           0 :       switch(sig) {
     221           0 :         case fd_crds_data_enum_vote: {
     222           0 :           memcpy( &ctx->vote_ix_buf[0], chunk_laddr, sz );
     223           0 :           break;
     224           0 :         }
     225           0 :         case fd_crds_data_enum_duplicate_shred: {
     226           0 :           memcpy( &ctx->duplicate_shred, chunk_laddr, sizeof(fd_gossip_duplicate_shred_t) );
     227           0 :           memcpy( ctx->duplicate_shred_chunk, chunk_laddr + sizeof(fd_gossip_duplicate_shred_t), FD_EQVOC_PROOF_CHUNK_SZ );
     228           0 :           break;
     229           0 :         }
     230           0 :         default: {
     231           0 :           FD_LOG_ERR(( "unexpected crds discriminant %lu", sig ));
     232           0 :           break;
     233           0 :         }
     234           0 :       }
     235           0 :       break;
     236           0 :     }
     237             : 
     238           0 :     case IN_KIND_REPLAY: {
     239           0 :       in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
     240           0 :       ulong parent_slot = fd_ulong_extract_lsb( sig, 32 );
     241           0 :       uchar const * chunk_laddr = fd_chunk_to_laddr_const( in_ctx->mem, chunk );
     242           0 :       if( FD_UNLIKELY( parent_slot == UINT_MAX /* no parent, so snapshot slot */ ) ) {
     243           0 :         memcpy   ( ctx->slot_hash.uc,     chunk_laddr,                     sizeof(fd_hash_t) );
     244           0 :         fd_memcpy( ctx->epoch_voters_buf, chunk_laddr + sizeof(fd_hash_t), sz - sizeof(fd_hash_t) );
     245           0 :       } else {
     246           0 :         memcpy( ctx->bank_hash.uc,   chunk_laddr,                     sizeof(fd_hash_t) );
     247           0 :         memcpy( ctx->block_hash.uc,  chunk_laddr+1*sizeof(fd_hash_t), sizeof(fd_hash_t) );
     248           0 :         memcpy( ctx->slot_hash.uc,   chunk_laddr+2*sizeof(fd_hash_t), sizeof(fd_hash_t) );
     249           0 :         memcpy( ctx->parent_hash.uc, chunk_laddr+3*sizeof(fd_hash_t), sizeof(fd_hash_t) );
     250             :         /* FIXME: worth making a repair->replay packed msg to directly cast? */
     251           0 :       }
     252           0 :       break;
     253           0 :     }
     254             : 
     255           0 :     case IN_KIND_SHRED:
     256           0 :       break;
     257             : 
     258           0 :     case IN_KIND_SIGN:
     259           0 :       break;
     260             : 
     261           0 :     default:
     262           0 :       FD_LOG_ERR(( "Unknown in_kind %u", in_kind ));
     263           0 :   }
     264           0 : }
     265             : 
     266             : static void
     267             : after_frag( ctx_t *             ctx,
     268             :             ulong               in_idx,
     269             :             ulong               seq     FD_PARAM_UNUSED,
     270             :             ulong               sig,
     271             :             ulong               sz,
     272             :             ulong               tsorig,
     273             :             ulong               tspub   FD_PARAM_UNUSED,
     274           0 :             fd_stem_context_t * stem ) {
     275           0 :   uint in_kind = ctx->in_kind[in_idx];
     276           0 :   if( FD_UNLIKELY( in_kind != IN_KIND_REPLAY ) ) return;
     277             : 
     278           0 :   ulong slot        = fd_ulong_extract( sig, 32, 63 );
     279           0 :   ulong parent_slot = fd_ulong_extract_lsb( sig, 32 );
     280             : 
     281           0 :   if( FD_UNLIKELY( (uint)parent_slot == UINT_MAX ) ) { /* snapshot slot */
     282           0 :     FD_TEST( ctx->funk );
     283           0 :     FD_TEST( fd_funk_txn_map( ctx->funk ) );
     284           0 :     update_epoch( ctx, sz - sizeof(fd_hash_t) );
     285           0 :     fd_ghost_init( ctx->ghost, slot, &ctx->slot_hash );
     286           0 :     return;
     287           0 :   }
     288             : 
     289           0 :   fd_funk_txn_xid_t   txn_xid  = { .ul = { slot, slot } };
     290           0 :   fd_funk_txn_map_t * txn_map  = fd_funk_txn_map( ctx->funk );
     291           0 :   fd_funk_txn_start_read( ctx->funk );
     292           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_query( &txn_xid, txn_map );
     293           0 :   if( FD_UNLIKELY( !funk_txn ) ) FD_LOG_ERR(( "Could not find valid funk transaction" ));
     294           0 :   fd_funk_txn_end_read( ctx->funk );
     295             : 
     296             :   /* Initialize the tower */
     297             : 
     298           0 :   if( FD_UNLIKELY( fd_tower_votes_empty( ctx->tower ) ) ) fd_tower_from_vote_acc( ctx->tower, ctx->funk, funk_txn, &ctx->funk_key );
     299             : 
     300           0 :   fd_ghost_ele_t const * ghost_ele  = fd_ghost_insert( ctx->ghost, &ctx->parent_hash, slot, &ctx->slot_hash, ctx->epoch->total_stake );
     301           0 :   FD_TEST( ghost_ele );
     302           0 :   update_ghost( ctx, funk_txn );
     303             : 
     304           0 :   ulong vote_slot = fd_tower_vote_slot( ctx->tower, ctx->epoch, ctx->funk, funk_txn, ctx->ghost, ctx->scratch );
     305           0 :   if( FD_UNLIKELY( vote_slot == FD_SLOT_NULL ) ) return; /* nothing to vote on */
     306             : 
     307           0 :   ulong root = fd_tower_vote( ctx->tower, vote_slot );
     308           0 :   if( FD_LIKELY( root != FD_SLOT_NULL ) ) {
     309           0 :     fd_hash_t const * root_bid = fd_ghost_hash( ctx->ghost, root );
     310           0 :     if( FD_UNLIKELY( !root_bid ) ) {
     311           0 :       FD_LOG_WARNING(( "Lowest vote slot %lu is not in ghost, skipping publish", root ));
     312           0 :     } else {
     313           0 :       fd_ghost_publish( ctx->ghost, root_bid );
     314           0 :       fd_stem_publish( stem, ctx->replay_out_idx, root, 0UL, 0UL, 0UL, tsorig, fd_frag_meta_ts_comp( fd_tickcount() ) );
     315           0 :     }
     316           0 :     ctx->root = root;
     317           0 :   }
     318             : 
     319             :   /* Send our updated tower to the cluster. */
     320             : 
     321           0 :   fd_txn_p_t * vote_txn = (fd_txn_p_t *)fd_chunk_to_laddr( ctx->send_out_mem, ctx->send_out_chunk );
     322           0 :   fd_tower_to_vote_txn( ctx->tower, ctx->root, ctx->lockouts, &ctx->bank_hash, &ctx->block_hash, ctx->identity_key, ctx->identity_key, ctx->vote_acc, vote_txn );
     323           0 :   FD_TEST( !fd_tower_votes_empty( ctx->tower ) );
     324           0 :   FD_TEST( vote_txn->payload_sz > 0UL );
     325           0 :   fd_stem_publish( stem, ctx->send_out_idx, vote_slot, ctx->send_out_chunk, sizeof(fd_txn_p_t), 0UL, tsorig, fd_frag_meta_ts_comp( fd_tickcount() ) );
     326             : 
     327           0 :   fd_ghost_print( ctx->ghost, ctx->epoch->total_stake, fd_ghost_root( ctx->ghost ) );
     328           0 :   fd_tower_print( ctx->tower, ctx->root );
     329           0 : }
     330             : 
     331             : static void
     332             : unprivileged_init( fd_topo_t *      topo,
     333           0 :                    fd_topo_tile_t * tile ) {
     334           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     335             : 
     336           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     337           0 :   ctx_t * ctx        = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t)        );
     338           0 :   void * epoch_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_align(),             fd_epoch_footprint( FD_VOTER_MAX ) );
     339           0 :   void * ghost_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_ghost_align(),             fd_ghost_footprint( FD_BLOCK_MAX ) );
     340           0 :   void * tower_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_align(),             fd_tower_footprint()               );
     341           0 :   void * scratch_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_align(),             fd_tower_footprint()               );
     342           0 :   void * voter_mem   = FD_SCRATCH_ALLOC_APPEND( l, 128UL,                        VOTER_FOOTPRINT * VOTER_MAX        );
     343           0 :   ulong scratch_top  = FD_SCRATCH_ALLOC_FINI  ( l, scratch_align()                                                  );
     344           0 :   FD_TEST( scratch_top == (ulong)scratch + scratch_footprint( tile ) );
     345             : 
     346           0 :   ctx->epoch   = fd_epoch_join( fd_epoch_new( epoch_mem, FD_VOTER_MAX       ) );
     347           0 :   ctx->ghost   = fd_ghost_join( fd_ghost_new( ghost_mem, FD_BLOCK_MAX, 42UL ) );
     348           0 :   ctx->tower   = fd_tower_join( fd_tower_new( tower_mem                     ) );
     349           0 :   ctx->scratch = fd_tower_join( fd_tower_new( scratch_mem                   ) );
     350             : 
     351           0 :   if( FD_UNLIKELY( !fd_funk_join( ctx->funk, fd_topo_obj_laddr( topo, tile->tower.funk_obj_id ) ) ) ) {
     352           0 :     FD_LOG_ERR(( "Failed to join database cache" ));
     353           0 :   }
     354             : 
     355           0 :   ctx->epoch_voters_buf = voter_mem;
     356             : 
     357           0 :   memcpy( ctx->identity_key->uc, fd_keyload_load( tile->tower.identity_key_path, 1 ), sizeof(fd_pubkey_t) );
     358             : 
     359           0 :   if( FD_UNLIKELY( !fd_base58_decode_32( tile->tower.vote_acc_path, ctx->vote_acc->uc ) ) ) {
     360           0 :     const uchar * vote_key = fd_keyload_load( tile->tower.vote_acc_path, 1 );
     361           0 :     memcpy( ctx->vote_acc->uc, vote_key, sizeof(fd_pubkey_t) );
     362           0 :   }
     363             : 
     364           0 :   memset( ctx->funk_key.uc, 0, sizeof(fd_funk_rec_key_t) );
     365           0 :   memcpy( ctx->funk_key.uc, ctx->vote_acc->uc, sizeof(fd_pubkey_t) );
     366           0 :   ctx->funk_key.uc[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_FUNK_KEY_TYPE_ACC;
     367             : 
     368           0 :   if( FD_UNLIKELY( tile->in_cnt > MAX_IN_LINKS ) ) FD_LOG_ERR(( "repair tile has too many input links" ));
     369             : 
     370           0 :   for( uint in_idx=0U; in_idx<(tile->in_cnt); in_idx++ ) {
     371           0 :     fd_topo_link_t * link = &topo->links[ tile->in_link_id[ in_idx ] ];
     372           0 :     if(        0==strcmp( link->name, "gossip_tower" ) ) {
     373           0 :       ctx->in_kind[ in_idx ] = IN_KIND_GOSSIP;
     374           0 :     } else if( 0==strcmp( link->name, "replay_tower" ) ) {
     375           0 :       ctx->in_kind[ in_idx ] = IN_KIND_REPLAY;
     376           0 :     } else if( 0==strcmp( link->name, "stake_out" ) ) {
     377           0 :       ctx->in_kind[ in_idx ] = IN_KIND_SHRED;
     378           0 :     } else {
     379           0 :       FD_LOG_ERR(( "tower tile has unexpected input link %s", link->name ));
     380           0 :     }
     381           0 :     ctx->in_links[ in_idx ].mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     382           0 :     ctx->in_links[ in_idx ].chunk0 = fd_dcache_compact_chunk0( ctx->in_links[ in_idx ].mem, link->dcache );
     383           0 :     ctx->in_links[ in_idx ].wmark  = fd_dcache_compact_wmark ( ctx->in_links[ in_idx ].mem, link->dcache, link->mtu );
     384           0 :     ctx->in_links[ in_idx ].mtu    = link->mtu;
     385           0 :   }
     386             : 
     387           0 :   ctx->replay_out_idx = fd_topo_find_tile_out_link( topo, tile, "tower_replay", 0 );
     388           0 :   FD_TEST( ctx->replay_out_idx!= ULONG_MAX );
     389             : 
     390           0 :   ctx->send_out_idx = fd_topo_find_tile_out_link( topo, tile, "tower_send", 0 );
     391           0 :   FD_TEST( ctx->send_out_idx!=ULONG_MAX );
     392           0 :   fd_topo_link_t * send_out = &topo->links[ tile->out_link_id[ ctx->send_out_idx ] ];
     393           0 :   ctx->send_out_mem         = topo->workspaces[ topo->objs[ send_out->dcache_obj_id ].wksp_id ].wksp;
     394           0 :   ctx->send_out_chunk0      = fd_dcache_compact_chunk0( ctx->send_out_mem, send_out->dcache );
     395           0 :   ctx->send_out_wmark       = fd_dcache_compact_wmark ( ctx->send_out_mem, send_out->dcache, send_out->mtu );
     396           0 :   ctx->send_out_chunk       = ctx->send_out_chunk0;
     397           0 :   FD_TEST( fd_dcache_compact_is_safe( ctx->send_out_mem, send_out->dcache, send_out->mtu, send_out->depth ) );
     398           0 : }
     399             : 
     400             : static ulong
     401             : populate_allowed_seccomp( fd_topo_t const *      topo,
     402             :                           fd_topo_tile_t const * tile,
     403             :                           ulong                  out_cnt,
     404           0 :                           struct sock_filter *   out ) {
     405           0 :   (void)topo;
     406           0 :   (void)tile;
     407             : 
     408           0 :   populate_sock_filter_policy_fd_tower_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
     409           0 :   return sock_filter_policy_fd_tower_tile_instr_cnt;
     410           0 : }
     411             : 
     412             : static ulong
     413             : populate_allowed_fds( fd_topo_t const *      topo,
     414             :                       fd_topo_tile_t const * tile,
     415             :                       ulong                  out_fds_cnt,
     416           0 :                       int *                  out_fds ) {
     417           0 :   (void)topo;
     418           0 :   (void)tile;
     419             : 
     420           0 :   if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     421             : 
     422           0 :   ulong out_cnt = 0UL;
     423           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     424           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     425           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     426           0 :   return out_cnt;
     427           0 : }
     428             : 
     429           0 : #define STEM_BURST (1UL)
     430             : 
     431           0 : #define STEM_CALLBACK_CONTEXT_TYPE  ctx_t
     432           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(ctx_t)
     433           0 : #define STEM_CALLBACK_DURING_FRAG   during_frag
     434           0 : #define STEM_CALLBACK_AFTER_FRAG    after_frag
     435             : 
     436             : #include "../../disco/stem/fd_stem.c"
     437             : 
     438             : fd_topo_run_tile_t fd_tile_tower = {
     439             :     .name                     = "tower",
     440             :     .populate_allowed_seccomp = populate_allowed_seccomp,
     441             :     .populate_allowed_fds     = populate_allowed_fds,
     442             :     .scratch_align            = scratch_align,
     443             :     .scratch_footprint        = scratch_footprint,
     444             :     .unprivileged_init        = unprivileged_init,
     445             :     .run                      = stem_run,
     446             : };

Generated by: LCOV version 1.14