LCOV - code coverage report
Current view: top level - discoh/resolh - fd_resolh_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 254 0.0 %
Date: 2026-02-13 06:06:24 Functions: 0 11 0.0 %

          Line data    Source code
       1             : #include "../bank/fd_bank_abi.h"
       2             : 
       3             : #include "../../disco/tiles.h"
       4             : #include "../../disco/fd_txn_m.h"
       5             : #include "../../disco/metrics/fd_metrics.h"
       6             : #include "../../flamenco/runtime/fd_system_ids_pp.h"
       7             : 
       8             : #if FD_HAS_AVX
       9             : #include "../../util/simd/fd_avx.h"
      10             : #endif
      11             : 
      12           0 : #define FD_RESOLH_IN_KIND_FRAGMENT (0)
      13           0 : #define FD_RESOLH_IN_KIND_BANK     (1)
      14             : 
      15             : struct blockhash {
      16             :   uchar b[ 32 ];
      17             : };
      18             : 
      19             : typedef struct blockhash blockhash_t;
      20             : 
      21             : struct blockhash_map {
      22             :   blockhash_t key;
      23             :   ulong       slot;
      24             : };
      25             : 
      26             : typedef struct blockhash_map blockhash_map_t;
      27             : 
      28             : static const blockhash_t null_blockhash = { 0 };
      29             : 
      30             : /* The blockhash ring holds recent blockhashes, so we can identify when
      31             :    a transaction arrives, what slot it will expire (and can no longer be
      32             :    packed) in.  This is useful so we don't send transactions to pack
      33             :    that are no longer packable.
      34             : 
      35             :    Unfortunately, poorly written transaction senders frequently send
      36             :    transactions from millions of slots ago, so we need a large ring to
      37             :    be able to determine and evict these.  The highest practically useful
      38             :    value here is around 22, which works out to 19 days of blockhash
      39             :    history.  Beyond this, the validator is likely to be restarted, and
      40             :    lose the history anyway. */
      41             : 
      42           0 : #define BLOCKHASH_LG_RING_CNT 22UL
      43           0 : #define BLOCKHASH_RING_LEN   (1UL<<BLOCKHASH_LG_RING_CNT)
      44             : 
      45             : #define MAP_NAME              map
      46           0 : #define MAP_T                 blockhash_map_t
      47           0 : #define MAP_KEY_T             blockhash_t
      48           0 : #define MAP_LG_SLOT_CNT       (BLOCKHASH_LG_RING_CNT+1UL)
      49           0 : #define MAP_KEY_NULL          null_blockhash
      50             : #if FD_HAS_AVX
      51           0 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
      52             : #else
      53             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_blockhash)
      54             : #endif
      55           0 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, 32UL))
      56             : #define MAP_MEMOIZE           0
      57             : #define MAP_KEY_EQUAL_IS_SLOW 1
      58           0 : #define MAP_KEY_HASH(key)     fd_uint_load_4( (key).b )
      59             : #define MAP_QUERY_OPT         1
      60             : 
      61             : #include "../../util/tmpl/fd_map.c"
      62             : 
      63             : typedef struct {
      64             :   union {
      65             :     ulong pool_next; /* Used when it's released */
      66             :     ulong lru_next;  /* Used when it's acquired */
      67             :   };                 /* .. so it's okay to store them in the same memory */
      68             :   ulong lru_prev;
      69             : 
      70             :   ulong map_next;
      71             :   ulong map_prev;
      72             : 
      73             :   blockhash_t * blockhash;
      74             :   uchar _[ FD_TPU_PARSED_MTU ] __attribute__((aligned(alignof(fd_txn_m_t))));
      75             : } fd_stashed_txn_m_t;
      76             : 
      77             : #define POOL_NAME      pool
      78           0 : #define POOL_T         fd_stashed_txn_m_t
      79           0 : #define POOL_NEXT      pool_next
      80             : #define POOL_IDX_T     ulong
      81             : 
      82             : #include "../../util/tmpl/fd_pool.c"
      83             : 
      84             : /* We'll push at the head, which means the tail is the oldest. */
      85             : #define DLIST_NAME  lru_list
      86             : #define DLIST_ELE_T fd_stashed_txn_m_t
      87           0 : #define DLIST_PREV  lru_prev
      88           0 : #define DLIST_NEXT  lru_next
      89             : 
      90             : #include "../../util/tmpl/fd_dlist.c"
      91             : 
      92             : #define MAP_NAME          map_chain
      93           0 : #define MAP_ELE_T         fd_stashed_txn_m_t
      94             : #define MAP_KEY_T         blockhash_t *
      95           0 : #define MAP_KEY           blockhash
      96           0 : #define MAP_IDX_T         ulong
      97           0 : #define MAP_NEXT          map_next
      98           0 : #define MAP_PREV          map_prev
      99           0 : #define MAP_KEY_HASH(k,s) ((s) ^ fd_ulong_load_8( (*(k))->b ))
     100           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((*(k0))->b, (*(k1))->b, 32UL))
     101             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     102             : #define MAP_MULTI         1
     103             : 
     104             : #include "../../util/tmpl/fd_map_chain.c"
     105             : 
     106             : struct fd_resolh_in {
     107             :   int         kind;
     108             : 
     109             :   fd_wksp_t * mem;
     110             :   ulong       chunk0;
     111             :   ulong       wmark;
     112             :   ulong       mtu;
     113             : };
     114             : 
     115             : typedef struct fd_resolh_in fd_resolh_in_t;
     116             : 
     117             : struct fd_resolh_tile {
     118             :   ulong round_robin_idx;
     119             :   ulong round_robin_cnt;
     120             : 
     121             :   int   bundle_failed;
     122             :   ulong bundle_id;
     123             : 
     124             :   void * root_bank;
     125             :   ulong  root_slot;
     126             : 
     127             :   blockhash_map_t * blockhash_map;
     128             : 
     129             :   ulong flushing_slot;
     130             :   ulong flush_pool_idx;
     131             : 
     132             :   fd_stashed_txn_m_t * pool;
     133             :   map_chain_t *        map_chain;
     134             :   lru_list_t           lru_list[1];
     135             : 
     136             :   ulong completed_slot;
     137             :   ulong blockhash_ring_idx;
     138             :   blockhash_t blockhash_ring[ BLOCKHASH_RING_LEN ];
     139             : 
     140             :   uchar _bank_msg[ sizeof(fd_completed_bank_t) ];
     141             : 
     142             :   struct {
     143             :     ulong lut[ FD_METRICS_COUNTER_RESOLH_LUT_RESOLVED_CNT ];
     144             :     ulong blockhash_expired;
     145             :     ulong blockhash_unknown;
     146             :     ulong bundle_peer_failure_cnt;
     147             :     ulong stash[ FD_METRICS_COUNTER_RESOLH_STASH_OPERATION_CNT ];
     148             :   } metrics;
     149             : 
     150             :   fd_resolh_in_t in[ 64UL ];
     151             : 
     152             :   fd_wksp_t * out_mem;
     153             :   ulong       out_chunk0;
     154             :   ulong       out_wmark;
     155             :   ulong       out_chunk;
     156             : };
     157             : 
     158             : typedef struct fd_resolh_tile fd_resolh_tile_t;
     159             : 
     160             : FD_FN_CONST static inline ulong
     161           0 : scratch_align( void ) {
     162           0 :   return alignof( fd_resolh_tile_t );
     163           0 : }
     164             : 
     165             : FD_FN_PURE static inline ulong
     166           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
     167           0 :   (void)tile;
     168           0 :   ulong l = FD_LAYOUT_INIT;
     169           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_resolh_tile_t ), sizeof( fd_resolh_tile_t )    );
     170           0 :   l = FD_LAYOUT_APPEND( l, pool_align(),                pool_footprint( 1UL<<16UL )   );
     171           0 :   l = FD_LAYOUT_APPEND( l, map_chain_align(),           map_chain_footprint( 8192UL ) );
     172           0 :   l = FD_LAYOUT_APPEND( l, map_align(),                 map_footprint()               );
     173           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
     174           0 : }
     175             : 
     176             : extern void fd_ext_bank_release( void const * bank );
     177             : 
     178             : static ulong _fd_ext_resolh_tile_cnt;
     179             : 
     180             : ulong
     181           0 : fd_ext_resolv_tile_cnt( void ) {
     182           0 :   while(  !FD_VOLATILE( _fd_ext_resolh_tile_cnt ) ) {}
     183           0 :   return _fd_ext_resolh_tile_cnt;
     184           0 : }
     185             : 
     186             : static inline void
     187           0 : metrics_write( fd_resolh_tile_t * ctx ) {
     188           0 :   FD_MCNT_SET( RESOLH, BLOCKHASH_EXPIRED, ctx->metrics.blockhash_expired );
     189           0 :   FD_MCNT_ENUM_COPY( RESOLH, LUT_RESOLVED, ctx->metrics.lut );
     190           0 :   FD_MCNT_ENUM_COPY( RESOLH, STASH_OPERATION, ctx->metrics.stash );
     191           0 :   FD_MCNT_SET( RESOLH, TRANSACTION_BUNDLE_PEER_FAILURE, ctx->metrics.bundle_peer_failure_cnt );
     192           0 : }
     193             : 
     194             : static int
     195             : before_frag( fd_resolh_tile_t * ctx,
     196             :              ulong              in_idx,
     197             :              ulong              seq,
     198           0 :              ulong              sig ) {
     199           0 :   (void)sig;
     200             : 
     201           0 :   if( FD_UNLIKELY( ctx->in[in_idx].kind==FD_RESOLH_IN_KIND_BANK ) ) return 0;
     202             : 
     203           0 :   return (seq % ctx->round_robin_cnt) != ctx->round_robin_idx;
     204           0 : }
     205             : 
     206             : static inline void
     207             : during_frag( fd_resolh_tile_t * ctx,
     208             :              ulong              in_idx,
     209             :              ulong              seq FD_PARAM_UNUSED,
     210             :              ulong              sig FD_PARAM_UNUSED,
     211             :              ulong              chunk,
     212             :              ulong              sz,
     213           0 :              ulong              ctl FD_PARAM_UNUSED ) {
     214             : 
     215           0 :   if( FD_UNLIKELY( chunk<ctx->in[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz>ctx->in[ in_idx ].mtu ) )
     216           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 ));
     217             : 
     218           0 :   switch( ctx->in[in_idx].kind ) {
     219           0 :     case FD_RESOLH_IN_KIND_BANK:
     220           0 :       fd_memcpy( ctx->_bank_msg, fd_chunk_to_laddr_const( ctx->in[in_idx].mem, chunk ), sz );
     221           0 :       break;
     222           0 :     case FD_RESOLH_IN_KIND_FRAGMENT: {
     223           0 :       uchar * src = (uchar *)fd_chunk_to_laddr( ctx->in[in_idx].mem, chunk );
     224           0 :       uchar * dst = (uchar *)fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk );
     225           0 :       fd_memcpy( dst, src, sz );
     226           0 :       break;
     227           0 :     }
     228           0 :     default:
     229           0 :       FD_LOG_ERR(( "unknown in kind %d", ctx->in[in_idx].kind ));
     230           0 :   }
     231           0 : }
     232             : 
     233             : static inline int
     234             : publish_txn( fd_resolh_tile_t *         ctx,
     235             :              fd_stem_context_t *        stem,
     236           0 :              fd_stashed_txn_m_t const * stashed ) {
     237           0 :   fd_txn_m_t *     txnm = (fd_txn_m_t *)fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk );
     238           0 :   fd_memcpy( txnm, stashed->_, fd_txn_m_realized_footprint( (fd_txn_m_t *)stashed->_, 1, 0 ) );
     239             : 
     240           0 :   fd_txn_t const * txnt = fd_txn_m_txn_t( txnm );
     241             : 
     242           0 :   txnm->reference_slot = ctx->flushing_slot;
     243             : 
     244           0 :   if( FD_UNLIKELY( txnt->addr_table_adtl_cnt ) ) {
     245           0 :     if( FD_UNLIKELY( !ctx->root_bank ) ) {
     246           0 :       FD_MCNT_INC( RESOLH, NO_BANK_DROP, 1 );
     247           0 :       return 0;
     248           0 :     } else {
     249           0 :       int result = fd_bank_abi_resolve_address_lookup_tables( ctx->root_bank, 0, ctx->root_slot, txnt, fd_txn_m_payload( txnm ), fd_txn_m_alut( txnm ) );
     250             :       /* result is in [-5, 0]. We want to map -5 to 0, -4 to 1, etc. */
     251           0 :       ctx->metrics.lut[ (ulong)((long)FD_METRICS_COUNTER_RESOLH_LUT_RESOLVED_CNT+result-1L) ]++;
     252             : 
     253           0 :       if( FD_UNLIKELY( result!=FD_BANK_ABI_TXN_INIT_SUCCESS ) ) return 0;
     254           0 :     }
     255           0 :   }
     256             : 
     257           0 :   ulong realized_sz = fd_txn_m_realized_footprint( txnm, 1, 1 );
     258           0 :   ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
     259           0 :   fd_stem_publish( stem, 0UL, txnm->reference_slot, ctx->out_chunk, realized_sz, 0UL, 0UL, tspub );
     260           0 :   ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, realized_sz, ctx->out_chunk0, ctx->out_wmark );
     261             : 
     262           0 :   return 1;
     263           0 : }
     264             : 
     265             : static inline void
     266             : after_credit( fd_resolh_tile_t *  ctx,
     267             :               fd_stem_context_t * stem,
     268             :               int *               opt_poll_in,
     269           0 :               int *               charge_busy ) {
     270           0 :   if( FD_LIKELY( ctx->flush_pool_idx==ULONG_MAX ) ) return;
     271             : 
     272           0 :   *charge_busy = 1;
     273           0 :   *opt_poll_in = 0;
     274             : 
     275           0 :   ulong next = map_chain_idx_next_const( ctx->flush_pool_idx, ULONG_MAX, ctx->pool );
     276           0 :   map_chain_idx_remove_fast( ctx->map_chain, ctx->flush_pool_idx, ctx->pool );
     277           0 :   if( FD_LIKELY( publish_txn( ctx, stem, pool_ele( ctx->pool, ctx->flush_pool_idx ) ) ) ) {
     278           0 :     ctx->metrics.stash[ FD_METRICS_ENUM_RESOLVE_STASH_OPERATION_V_PUBLISHED_IDX ]++;
     279           0 :   } else {
     280           0 :     ctx->metrics.stash[ FD_METRICS_ENUM_RESOLVE_STASH_OPERATION_V_REMOVED_IDX ]++;
     281           0 :   }
     282           0 :   lru_list_idx_remove( ctx->lru_list, ctx->flush_pool_idx, ctx->pool );
     283           0 :   pool_idx_release( ctx->pool, ctx->flush_pool_idx );
     284           0 :   ctx->flush_pool_idx = next;
     285           0 : }
     286             : 
     287             : /* Returns 0 if not a durable nonce transaction and 1 if it may be a
     288             :    durable nonce transaction */
     289             : 
     290             : FD_FN_PURE static inline int
     291             : fd_resolh_is_durable_nonce( fd_txn_t const * txn,
     292           0 :                             uchar    const * payload ) {
     293           0 :   if( FD_UNLIKELY( txn->instr_cnt==0 ) ) return 0;
     294             : 
     295           0 :   fd_txn_instr_t const * ix0 = &txn->instr[ 0 ];
     296           0 :   fd_acct_addr_t const * prog0 = fd_txn_get_acct_addrs( txn, payload ) + ix0->program_id;
     297             :   /* First instruction must be SystemProgram nonceAdvance instruction */
     298           0 :   fd_acct_addr_t const system_program[1] = { { { SYS_PROG_ID } } };
     299           0 :   if( FD_LIKELY( memcmp( prog0, system_program, sizeof(fd_acct_addr_t) ) ) )        return 0;
     300             : 
     301             :   /* instruction with three accounts and a four byte instruction data, a
     302             :      little-endian uint value 4 */
     303           0 :   if( FD_UNLIKELY( (ix0->data_sz!=4) | (ix0->acct_cnt!=3) ) ) return 0;
     304             : 
     305           0 :   return fd_uint_load_4( payload + ix0->data_off )==4U;
     306           0 : }
     307             : 
     308             : static inline void
     309             : after_frag( fd_resolh_tile_t *  ctx,
     310             :             ulong               in_idx,
     311             :             ulong               seq,
     312             :             ulong               sig,
     313             :             ulong               sz,
     314             :             ulong               tsorig,
     315             :             ulong               _tspub,
     316           0 :             fd_stem_context_t * stem ) {
     317           0 :   (void)seq;
     318           0 :   (void)sz;
     319           0 :   (void)_tspub;
     320             : 
     321           0 :   if( FD_UNLIKELY( ctx->in[in_idx].kind==FD_RESOLH_IN_KIND_BANK ) ) {
     322           0 :     switch( sig ) {
     323           0 :       case 0: {
     324           0 :         fd_rooted_bank_t * frag = (fd_rooted_bank_t *)ctx->_bank_msg;
     325           0 :         if( FD_LIKELY( ctx->root_bank ) ) fd_ext_bank_release( ctx->root_bank );
     326             : 
     327           0 :         ctx->root_bank = frag->bank;
     328           0 :         ctx->root_slot = frag->slot;
     329           0 :         break;
     330           0 :       }
     331           0 :       case 1: {
     332           0 :         fd_completed_bank_t * frag = (fd_completed_bank_t *)ctx->_bank_msg;
     333             : 
     334             :         /* blockhash_ring is initalized to all zeros. blockhash=0 is an illegal map query */
     335           0 :         if( FD_UNLIKELY( memcmp( &ctx->blockhash_ring[ ctx->blockhash_ring_idx%BLOCKHASH_RING_LEN ], (uchar[ 32UL ]){ 0UL }, sizeof(blockhash_t) ) ) ) {
     336           0 :           blockhash_map_t * entry = map_query( ctx->blockhash_map, ctx->blockhash_ring[ ctx->blockhash_ring_idx%BLOCKHASH_RING_LEN ], NULL );
     337           0 :           if( FD_LIKELY( entry ) ) map_remove( ctx->blockhash_map, entry );
     338           0 :         }
     339             : 
     340           0 :         memcpy( ctx->blockhash_ring[ ctx->blockhash_ring_idx%BLOCKHASH_RING_LEN ].b, frag->hash, 32UL );
     341           0 :         ctx->blockhash_ring_idx++;
     342             : 
     343           0 :         blockhash_map_t * blockhash = map_insert( ctx->blockhash_map, *(blockhash_t *)frag->hash );
     344           0 :         blockhash->slot = frag->slot;
     345             : 
     346           0 :         blockhash_t * hash = (blockhash_t *)frag->hash;
     347           0 :         ctx->flush_pool_idx  = map_chain_idx_query_const( ctx->map_chain, &hash, ULONG_MAX, ctx->pool );
     348           0 :         ctx->flushing_slot   = frag->slot;
     349             : 
     350           0 :         ctx->completed_slot = frag->slot;
     351           0 :         break;
     352           0 :       }
     353           0 :       default:
     354           0 :         FD_LOG_ERR(( "unknown sig %lu", sig ));
     355           0 :     }
     356           0 :     return;
     357           0 :   }
     358             : 
     359           0 :   fd_txn_m_t *     txnm = (fd_txn_m_t *)fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk );
     360           0 :   FD_TEST( txnm->payload_sz<=FD_TPU_MTU );
     361           0 :   FD_TEST( txnm->txn_t_sz<=FD_TXN_MAX_SZ );
     362           0 :   fd_txn_t const * txnt = fd_txn_m_txn_t( txnm );
     363             : 
     364             :   /* If we find the recent blockhash, life is simple.  We drop
     365             :      transactions that couldn't possibly execute any more, and forward
     366             :      to pack ones that could.
     367             : 
     368             :      If we can't find the recent blockhash ... it means one of four
     369             :      things,
     370             : 
     371             :      (1) The blockhash is really old (more than 19 days) or just
     372             :          non-existent.
     373             :      (2) The blockhash is not that old, but was created before this
     374             :          validator was started.
     375             :      (3) It's really new (we haven't seen the bank yet).
     376             :      (4) It's a durable nonce transaction, or part of a bundle (just let
     377             :          it pass).
     378             : 
     379             :     For durable nonce transactions, there isn't much we can do except
     380             :     pass them along and see if they execute.
     381             : 
     382             :     For the other three cases ... we don't want to flood pack with what
     383             :     might be junk transactions, so we accumulate them into a local
     384             :     buffer.  If we later see the blockhash come to exist, we forward any
     385             :     buffered transactions to back. */
     386             : 
     387           0 :   if( FD_UNLIKELY( txnm->block_engine.bundle_id && (txnm->block_engine.bundle_id!=ctx->bundle_id) ) ) {
     388           0 :     ctx->bundle_failed = 0;
     389           0 :     ctx->bundle_id     = txnm->block_engine.bundle_id;
     390           0 :   }
     391             : 
     392           0 :   if( FD_UNLIKELY( txnm->block_engine.bundle_id && ctx->bundle_failed ) ) {
     393           0 :     ctx->metrics.bundle_peer_failure_cnt++;
     394           0 :     return;
     395           0 :   }
     396             : 
     397           0 :   txnm->reference_slot = ctx->completed_slot;
     398           0 :   blockhash_map_t const * blockhash = map_query_const( ctx->blockhash_map, *(blockhash_t*)( fd_txn_m_payload( txnm )+txnt->recent_blockhash_off ), NULL );
     399           0 :   if( FD_LIKELY( blockhash ) ) {
     400           0 :     txnm->reference_slot = blockhash->slot;
     401           0 :     if( FD_UNLIKELY( txnm->reference_slot+151UL<ctx->completed_slot ) ) {
     402           0 :       if( FD_UNLIKELY( txnm->block_engine.bundle_id ) ) ctx->bundle_failed = 1;
     403           0 :       ctx->metrics.blockhash_expired++;
     404           0 :       return;
     405           0 :     }
     406           0 :   }
     407             : 
     408           0 :   int is_bundle_member = !!txnm->block_engine.bundle_id;
     409           0 :   int is_durable_nonce = fd_resolh_is_durable_nonce( txnt, fd_txn_m_payload( txnm ) );
     410             : 
     411           0 :   if( FD_UNLIKELY( !is_bundle_member && !is_durable_nonce && !blockhash ) ) {
     412           0 :     ulong pool_idx;
     413           0 :     if( FD_UNLIKELY( !pool_free( ctx->pool ) ) ) {
     414           0 :       pool_idx = lru_list_idx_pop_tail( ctx->lru_list, ctx->pool );
     415           0 :       map_chain_idx_remove_fast( ctx->map_chain, pool_idx, ctx->pool );
     416           0 :       ctx->metrics.stash[ FD_METRICS_ENUM_RESOLVE_STASH_OPERATION_V_OVERRUN_IDX ]++;
     417           0 :     } else {
     418           0 :       pool_idx = pool_idx_acquire( ctx->pool );
     419           0 :     }
     420             : 
     421           0 :     fd_stashed_txn_m_t * stash_txn = pool_ele( ctx->pool, pool_idx );
     422             :     /* There's a compiler bug in GCC version 12 (at least 12.1, 12.3 and
     423             :        12.4) that cause it to think stash_txn is a null pointer.  It
     424             :        then complains that the memcpy is bad and refuses to compile the
     425             :        memcpy below.  It is possible for pool_ele to return NULL, but
     426             :        that can't happen because if pool_free is 0, then all the pool
     427             :        elements must be in the LRU list, so idx_pop_tail won't return
     428             :        IDX_NULL; and if pool_free returns non-zero, then
     429             :        pool_idx_acquire won't return POOL_IDX_NULL. */
     430           0 :     FD_COMPILER_FORGET( stash_txn );
     431           0 :     fd_memcpy( stash_txn->_, txnm, fd_txn_m_realized_footprint( txnm, 1, 0 ) );
     432           0 :     stash_txn->blockhash = (blockhash_t *)(fd_txn_m_payload( (fd_txn_m_t *)(stash_txn->_) ) + txnt->recent_blockhash_off);
     433           0 :     ctx->metrics.stash[ FD_METRICS_ENUM_RESOLVE_STASH_OPERATION_V_INSERTED_IDX ]++;
     434             : 
     435           0 :     map_chain_ele_insert( ctx->map_chain, stash_txn, ctx->pool );
     436           0 :     lru_list_idx_push_head( ctx->lru_list, pool_idx, ctx->pool );
     437             : 
     438           0 :     return;
     439           0 :   }
     440             : 
     441           0 :   if( FD_UNLIKELY( txnt->addr_table_adtl_cnt ) ) {
     442           0 :     if( FD_UNLIKELY( !ctx->root_bank ) ) {
     443           0 :       FD_MCNT_INC( RESOLH, NO_BANK_DROP, 1 );
     444           0 :       if( FD_UNLIKELY( txnm->block_engine.bundle_id ) ) ctx->bundle_failed = 1;
     445           0 :       return;
     446           0 :     }
     447             : 
     448           0 :     int result = fd_bank_abi_resolve_address_lookup_tables( ctx->root_bank, 0, ctx->root_slot, txnt, fd_txn_m_payload( txnm ), fd_txn_m_alut( txnm ) );
     449             :     /* result is in [-5, 0]. We want to map -5 to 0, -4 to 1, etc. */
     450           0 :     ctx->metrics.lut[ (ulong)((long)FD_METRICS_COUNTER_RESOLH_LUT_RESOLVED_CNT+result-1L) ]++;
     451             : 
     452           0 :     if( FD_UNLIKELY( result!=FD_BANK_ABI_TXN_INIT_SUCCESS ) ) {
     453           0 :       if( FD_UNLIKELY( txnm->block_engine.bundle_id ) ) ctx->bundle_failed = 1;
     454           0 :       return;
     455           0 :     }
     456           0 :   }
     457             : 
     458           0 :   ulong realized_sz = fd_txn_m_realized_footprint( txnm, 1, 1 );
     459           0 :   ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
     460           0 :   fd_stem_publish( stem, 0UL, txnm->reference_slot, ctx->out_chunk, realized_sz, 0UL, tsorig, tspub );
     461           0 :   ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, realized_sz, ctx->out_chunk0, ctx->out_wmark );
     462           0 : }
     463             : 
     464             : static void
     465             : unprivileged_init( fd_topo_t *      topo,
     466           0 :                    fd_topo_tile_t * tile ) {
     467           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     468             : 
     469           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     470           0 :   fd_resolh_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_resolh_tile_t ), sizeof( fd_resolh_tile_t ) );
     471             : 
     472           0 :   ctx->round_robin_cnt = fd_topo_tile_name_cnt( topo, tile->name );
     473           0 :   ctx->round_robin_idx = tile->kind_id;
     474             : 
     475           0 :   ctx->bundle_failed = 0;
     476           0 :   ctx->bundle_id     = 0UL;
     477             : 
     478           0 :   ctx->completed_slot = 0UL;
     479           0 :   ctx->blockhash_ring_idx = 0UL;
     480             : 
     481           0 :   ctx->flush_pool_idx = ULONG_MAX;
     482             : 
     483           0 :   ctx->pool = pool_join( pool_new( FD_SCRATCH_ALLOC_APPEND( l, pool_align(), pool_footprint( 1UL<<16UL ) ), 1UL<<16UL ) );
     484           0 :   FD_TEST( ctx->pool );
     485             : 
     486           0 :   ctx->map_chain = map_chain_join( map_chain_new( FD_SCRATCH_ALLOC_APPEND( l, map_chain_align(), map_chain_footprint( 8192ULL ) ), 8192UL , 0UL ) );
     487           0 :   FD_TEST( ctx->map_chain );
     488             : 
     489           0 :   FD_TEST( ctx->lru_list==lru_list_join( lru_list_new( ctx->lru_list ) ) );
     490             : 
     491           0 :   if( FD_LIKELY( !tile->kind_id ) ) _fd_ext_resolh_tile_cnt = ctx->round_robin_cnt;
     492             : 
     493           0 :   ctx->root_bank = NULL;
     494             : 
     495           0 :   memset( ctx->blockhash_ring, 0, sizeof( ctx->blockhash_ring ) );
     496           0 :   memset( &ctx->metrics, 0, sizeof( ctx->metrics ) );
     497             : 
     498           0 :   ctx->blockhash_map = map_join( map_new( FD_SCRATCH_ALLOC_APPEND( l, map_align(), map_footprint() ) ) );
     499           0 :   FD_TEST( ctx->blockhash_map );
     500             : 
     501           0 :   FD_TEST( tile->in_cnt<=sizeof( ctx->in )/sizeof( ctx->in[ 0 ] ) );
     502           0 :   for( ulong i=0UL; i<tile->in_cnt; i++ ) {
     503           0 :     fd_topo_link_t * link = &topo->links[ tile->in_link_id[ i ] ];
     504           0 :     fd_topo_wksp_t * link_wksp = &topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ];
     505             : 
     506           0 :     if( FD_LIKELY( !strcmp( link->name, "replay_resol" ) ) ) ctx->in[i].kind = FD_RESOLH_IN_KIND_BANK;
     507           0 :     else                                                     ctx->in[i].kind = FD_RESOLH_IN_KIND_FRAGMENT;
     508             : 
     509           0 :     ctx->in[i].mem    = link_wksp->wksp;
     510           0 :     ctx->in[i].chunk0 = fd_dcache_compact_chunk0( ctx->in[i].mem, link->dcache );
     511           0 :     ctx->in[i].wmark  = fd_dcache_compact_wmark ( ctx->in[i].mem, link->dcache, link->mtu );
     512           0 :     ctx->in[i].mtu    = link->mtu;
     513           0 :   }
     514             : 
     515           0 :   ctx->out_mem    = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
     516           0 :   ctx->out_chunk0 = fd_dcache_compact_chunk0( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache );
     517           0 :   ctx->out_wmark  = fd_dcache_compact_wmark ( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu );
     518           0 :   ctx->out_chunk  = ctx->out_chunk0;
     519             : 
     520           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     521           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     522           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     523           0 : }
     524             : 
     525           0 : #define STEM_BURST (1UL)
     526             : 
     527           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_resolh_tile_t
     528           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_resolh_tile_t)
     529             : 
     530           0 : #define STEM_CALLBACK_METRICS_WRITE metrics_write
     531           0 : #define STEM_CALLBACK_AFTER_CREDIT  after_credit
     532           0 : #define STEM_CALLBACK_BEFORE_FRAG   before_frag
     533           0 : #define STEM_CALLBACK_DURING_FRAG   during_frag
     534           0 : #define STEM_CALLBACK_AFTER_FRAG    after_frag
     535             : 
     536             : #include "../../disco/stem/fd_stem.c"
     537             : 
     538             : fd_topo_run_tile_t fd_tile_resolh = {
     539             :   .name                     = "resolh",
     540             :   .populate_allowed_seccomp = NULL,
     541             :   .populate_allowed_fds     = NULL,
     542             :   .scratch_align            = scratch_align,
     543             :   .scratch_footprint        = scratch_footprint,
     544             :   .unprivileged_init        = unprivileged_init,
     545             :   .run                      = stem_run,
     546             : };

Generated by: LCOV version 1.14