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

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

Generated by: LCOV version 1.14