LCOV - code coverage report
Current view: top level - disco/repair - fd_rserve.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 238 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 19 0.0 %

          Line data    Source code
       1             : #include "fd_rserve.h"
       2             : #include "../../ballet/sha256/fd_sha256.h"
       3             : 
       4             : static void
       5             : fd_rserve_rotation_secret( uchar       out[ 32 ],
       6             :                            uchar const master[ 32 ],
       7           0 :                            ulong       idx ) {
       8           0 :   uchar buf[ 40 ];
       9           0 :   memcpy( buf, master, 32UL );
      10           0 :   FD_STORE( ulong, buf+32UL, idx );
      11           0 :   fd_sha256_hash( buf, sizeof(buf), out );
      12           0 : }
      13             : 
      14             : static void
      15             : fd_rserve_token_compute( uchar               token[ 32 ],
      16             :                          uchar const         secret[ 32 ],
      17             :                          fd_pubkey_t const * from,
      18             :                          uint                ip4,
      19           0 :                          ushort              port ) {
      20           0 :   memcpy( token, "SOLANA_PING_PONG", 16UL );
      21             : 
      22           0 :   uchar buf[ 32UL + 32UL + 4UL + 2UL ];
      23           0 :   memcpy( buf,       secret,   32UL );
      24           0 :   memcpy( buf+32UL,  from->uc, 32UL );
      25           0 :   FD_STORE( uint,   buf+64UL, ip4  );
      26           0 :   FD_STORE( ushort, buf+68UL, port );
      27             : 
      28           0 :   uchar mac[ 32 ];
      29           0 :   fd_sha256_hash( buf, sizeof(buf), mac );
      30           0 :   memcpy( token+16UL, mac, 16UL );
      31           0 : }
      32             : 
      33             : ulong
      34           0 : fd_rserve_footprint( ulong ping_cache_entries ) {
      35           0 :   if( FD_UNLIKELY( !ping_cache_entries ) ) return 0UL;
      36             : 
      37           0 :   ulong ping_max = fd_ulong_pow2_up( ping_cache_entries );
      38             : 
      39           0 :   ulong l = FD_LAYOUT_INIT;
      40           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_rserve_t), sizeof(fd_rserve_t) );
      41           0 :   l = FD_LAYOUT_APPEND( l, ping_pool_align(),    ping_pool_footprint( ping_max ) );
      42           0 :   l = FD_LAYOUT_APPEND( l, ping_map_align(),     ping_map_footprint( ping_map_chain_cnt_est( ping_max ) ) );
      43           0 :   l = FD_LAYOUT_APPEND( l, ping_dlist_align(),   ping_dlist_footprint() );
      44           0 :   return FD_LAYOUT_FINI( l, fd_rserve_align() );
      45           0 : }
      46             : 
      47             : void *
      48             : fd_rserve_new( void * shmem,
      49             :                ulong  ping_cache_entries,
      50             :                ulong  seed,
      51           0 :                uchar const secret[ 32 ] ) {
      52           0 :   if( FD_UNLIKELY( !shmem ) ) {
      53           0 :     FD_LOG_WARNING(( "NULL mem" ));
      54           0 :     return NULL;
      55           0 :   }
      56             : 
      57           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_rserve_align() ) ) ) {
      58           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      59           0 :     return NULL;
      60           0 :   }
      61             : 
      62           0 :   ulong footprint = fd_rserve_footprint( ping_cache_entries );
      63           0 :   if( FD_UNLIKELY( !footprint ) ) {
      64           0 :     FD_LOG_WARNING(( "bad ping cache size (%lu)", ping_cache_entries ));
      65           0 :     return NULL;
      66           0 :   }
      67             : 
      68           0 :   ulong ping_max = fd_ulong_pow2_up( ping_cache_entries );
      69             : 
      70           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      71           0 :   void * rserve_mem     = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_rserve_t), sizeof(fd_rserve_t) );
      72           0 :   void * ping_pool_mem  = FD_SCRATCH_ALLOC_APPEND( l, ping_pool_align(),    ping_pool_footprint( ping_max ) );
      73           0 :   void * ping_map_mem   = FD_SCRATCH_ALLOC_APPEND( l, ping_map_align(),     ping_map_footprint( ping_map_chain_cnt_est( ping_max ) ) );
      74           0 :   void * ping_dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, ping_dlist_align(),   ping_dlist_footprint() );
      75             : 
      76           0 :   fd_rserve_t * rserve = (fd_rserve_t *)rserve_mem;
      77           0 :   ping_pool_new( ping_pool_mem, ping_max );
      78           0 :   rserve->ping_pool  = fd_type_pun( ping_pool_mem );
      79           0 :   rserve->ping_map   = ping_map_join  ( ping_map_new  ( ping_map_mem,   ping_map_chain_cnt_est( ping_max ), seed ) );
      80           0 :   rserve->ping_dlist = ping_dlist_join( ping_dlist_new( ping_dlist_mem ) );
      81             : 
      82             :   /* Initialize rotating token secrets. */
      83           0 :   rserve->seed           = seed;
      84           0 :   rserve->token_idx      = 0UL;
      85           0 :   rserve->last_rotate_ts = 0UL;
      86           0 :   memcpy( rserve->secret_master, secret, 32UL );
      87           0 :   fd_rserve_rotation_secret( rserve->secret_cur, rserve->secret_master, 0UL );
      88           0 :   memcpy( rserve->secret_prev, rserve->secret_cur, 32UL );
      89             : 
      90           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_rserve_align() )==(ulong)shmem + footprint );
      91             : 
      92           0 :   return shmem;
      93           0 : }
      94             : 
      95             : fd_rserve_t *
      96           0 : fd_rserve_join( void * shrserve ) {
      97           0 :   if( FD_UNLIKELY( !shrserve ) ) {
      98           0 :     FD_LOG_WARNING(( "NULL rserve" ));
      99           0 :     return NULL;
     100           0 :   }
     101             : 
     102           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shrserve, fd_rserve_align() ) ) ) {
     103           0 :     FD_LOG_WARNING(( "misaligned rserve" ));
     104           0 :     return NULL;
     105           0 :   }
     106             : 
     107           0 :   fd_rserve_t * rserve = (fd_rserve_t *)shrserve;
     108           0 :   rserve->ping_pool  = ping_pool_join ( rserve->ping_pool  );
     109           0 :   rserve->ping_map   = ping_map_join  ( rserve->ping_map   );
     110           0 :   rserve->ping_dlist = ping_dlist_join( rserve->ping_dlist );
     111             : 
     112           0 :   return (fd_rserve_t *)rserve;
     113           0 : }
     114             : 
     115             : void *
     116           0 : fd_rserve_leave( fd_rserve_t const * rserve ) {
     117           0 :   if( FD_UNLIKELY( !rserve ) ) {
     118           0 :     FD_LOG_WARNING(( "NULL rserve" ));
     119           0 :     return NULL;
     120           0 :   }
     121             : 
     122           0 :   return (void *)rserve;
     123           0 : }
     124             : 
     125             : void *
     126           0 : fd_rserve_delete( void * rserve ) {
     127           0 :   if( FD_UNLIKELY( !rserve ) ) {
     128           0 :     FD_LOG_WARNING(( "NULL rserve" ));
     129           0 :     return NULL;
     130           0 :   }
     131             : 
     132           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)rserve, fd_rserve_align() ) ) ) {
     133           0 :     FD_LOG_WARNING(( "misaligned rserve" ));
     134           0 :     return NULL;
     135           0 :   }
     136             : 
     137           0 :   return rserve;
     138           0 : }
     139             : 
     140             : void
     141             : fd_rserve_ping_token( fd_rserve_t const * rserve,
     142             :                       uchar               token[ 32 ],
     143             :                       fd_pubkey_t const * from,
     144             :                       uint                ip4,
     145           0 :                       ushort              port ) {
     146           0 :   fd_rserve_token_compute( token, rserve->secret_cur, from, ip4, port );
     147           0 : }
     148             : 
     149             : static int
     150             : fd_rserve_secret_pong_verify( uchar const         secret[ 32 ],
     151             :                               uchar const       * pong_hash,
     152             :                               fd_pubkey_t const * from,
     153             :                               uint                ip4,
     154           0 :                               ushort              port ) {
     155           0 :   uchar token   [ 32 ];
     156           0 :   uchar preimage[ 16UL+32UL ];
     157           0 :   uchar expected[ 32 ];
     158             : 
     159           0 :   fd_rserve_token_compute( token, secret, from, ip4, port );
     160           0 :   memcpy( preimage,      "SOLANA_PING_PONG", 16UL );
     161           0 :   memcpy( preimage+16UL, token,              32UL );
     162           0 :   fd_sha256_hash( preimage, sizeof(preimage), expected );
     163           0 :   return !memcmp( expected, pong_hash, 32UL );
     164           0 : }
     165             : 
     166             : int
     167             : fd_rserve_pong_token_verify( fd_rserve_t const * rserve,
     168             :                              uchar const       * pong_hash,
     169             :                              fd_pubkey_t const * from,
     170             :                              uint                ip4,
     171           0 :                              ushort              port ) {
     172           0 :   if( FD_LIKELY( fd_rserve_secret_pong_verify( rserve->secret_cur,  pong_hash, from, ip4, port ) ) ) return 1;
     173           0 :   if( FD_LIKELY( fd_rserve_secret_pong_verify( rserve->secret_prev, pong_hash, from, ip4, port ) ) ) return 1;
     174           0 :   return 0;
     175           0 : }
     176             : 
     177             : void
     178             : fd_rserve_maybe_rotate( fd_rserve_t * rserve,
     179           0 :                         ulong         now_ns ) {
     180           0 :   if( FD_UNLIKELY( now_ns-rserve->last_rotate_ts > FD_RSERVE_TOKEN_ROTATE_NS ) ) {
     181           0 :     rserve->last_rotate_ts = now_ns;
     182           0 :     rserve->token_idx++;
     183           0 :     memcpy( rserve->secret_prev, rserve->secret_cur, 32UL );
     184           0 :     fd_rserve_rotation_secret( rserve->secret_cur, rserve->secret_master, rserve->token_idx );
     185           0 :   }
     186           0 : }
     187             : 
     188             : #define MAP_NAME                           fd_blockdb_map
     189           0 : #define MAP_ELE_T                          fd_blockdb_blk_t
     190             : #define MAP_KEY_T                          fd_blockdb_key_t
     191           0 : #define MAP_KEY                            key
     192           0 : #define MAP_IDX_T                          uint
     193           0 : #define MAP_NEXT                           next
     194           0 : #define MAP_PREV                           prev
     195           0 : #define MAP_KEY_EQ(k0,k1)                  (!memcmp( (k0), (k1), sizeof(fd_blockdb_key_t) ))
     196           0 : #define MAP_KEY_HASH(key,seed)             fd_hash( (seed), (key), sizeof(fd_blockdb_key_t) )
     197             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     198             : #include "../../util/tmpl/fd_map_chain.c"
     199             : 
     200             : ulong
     201           0 : fd_blockdb_footprint( ulong ele_max ) {
     202           0 :   if( FD_UNLIKELY( !ele_max || ele_max>=UINT_MAX ) ) return 0UL;
     203             : 
     204           0 :   ulong l = FD_LAYOUT_INIT;
     205           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_blockdb_t),     sizeof(fd_blockdb_t)                                          );
     206           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_blockdb_blk_t), ele_max*sizeof(fd_blockdb_blk_t)                              );
     207           0 :   l = FD_LAYOUT_APPEND( l, fd_blockdb_map_align(),    fd_blockdb_map_footprint( fd_blockdb_map_chain_cnt_est( ele_max ) ) );
     208           0 :   l = FD_LAYOUT_APPEND( l, FD_BMTREE_COMMIT_ALIGN,    FD_BMTREE_COMMIT_FOOTPRINT( FD_BLOCKDB_TREE_LAYER_MAX )       );
     209           0 :   return FD_LAYOUT_FINI( l, fd_blockdb_align() );
     210           0 : }
     211             : 
     212             : void *
     213             : fd_blockdb_new( void * shmem,
     214             :                 ulong  ele_max,
     215           0 :                 ulong  seed ) {
     216           0 :   if( FD_UNLIKELY( !shmem ) ) {
     217           0 :     FD_LOG_WARNING(( "NULL mem" ));
     218           0 :     return NULL;
     219           0 :   }
     220             : 
     221           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_blockdb_align() ) ) ) {
     222           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     223           0 :     return NULL;
     224           0 :   }
     225             : 
     226           0 :   ulong footprint = fd_blockdb_footprint( ele_max );
     227           0 :   if( FD_UNLIKELY( !footprint ) ) {
     228           0 :     FD_LOG_WARNING(( "bad ele_max (%lu)", ele_max ));
     229           0 :     return NULL;
     230           0 :   }
     231             : 
     232           0 :   ulong chain_cnt = fd_blockdb_map_chain_cnt_est( ele_max );
     233             : 
     234           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     235           0 :   fd_blockdb_t *     blockdb = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_blockdb_t),     sizeof(fd_blockdb_t)                  );
     236           0 :   fd_blockdb_blk_t * ele     = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_blockdb_blk_t), ele_max*sizeof(fd_blockdb_blk_t)      );
     237           0 :   void *             map     = FD_SCRATCH_ALLOC_APPEND( l, fd_blockdb_map_align(),    fd_blockdb_map_footprint( chain_cnt ) );
     238           0 :   void *             tree    = FD_SCRATCH_ALLOC_APPEND( l, FD_BMTREE_COMMIT_ALIGN,    FD_BMTREE_COMMIT_FOOTPRINT( FD_BLOCKDB_TREE_LAYER_MAX ) );
     239           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_blockdb_align() )==(ulong)shmem + footprint );
     240           0 :   FD_TEST( fd_bmtree_depth( FD_FEC_BLK_MAX+1UL )==FD_BLOCKDB_TREE_LAYER_MAX );
     241             : 
     242           0 :   blockdb->ele_max = ele_max;
     243           0 :   blockdb->seq     = 0UL;
     244           0 :   blockdb->ele     = ele;
     245           0 :   blockdb->tree    = tree;
     246           0 :   blockdb->map     = fd_blockdb_map_new( map, chain_cnt, seed );
     247           0 :   if( FD_UNLIKELY( !blockdb->map ) ) return NULL;
     248             : 
     249           0 :   return shmem;
     250           0 : }
     251             : 
     252             : fd_blockdb_t *
     253           0 : fd_blockdb_join( void * shblockdb ) {
     254           0 :   if( FD_UNLIKELY( !shblockdb ) ) {
     255           0 :     FD_LOG_WARNING(( "NULL blockdb" ));
     256           0 :     return NULL;
     257           0 :   }
     258             : 
     259           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shblockdb, fd_blockdb_align() ) ) ) {
     260           0 :     FD_LOG_WARNING(( "misaligned blockdb" ));
     261           0 :     return NULL;
     262           0 :   }
     263             : 
     264           0 :   fd_blockdb_t * blockdb = (fd_blockdb_t *)shblockdb;
     265           0 :   blockdb->map = fd_blockdb_map_join( blockdb->map );
     266           0 :   if( FD_UNLIKELY( !blockdb->map ) ) return NULL;
     267             : 
     268           0 :   return blockdb;
     269           0 : }
     270             : 
     271             : void *
     272           0 : fd_blockdb_leave( fd_blockdb_t const * blockdb ) {
     273           0 :   if( FD_UNLIKELY( !blockdb ) ) {
     274           0 :     FD_LOG_WARNING(( "NULL blockdb" ));
     275           0 :     return NULL;
     276           0 :   }
     277             : 
     278           0 :   return (void *)blockdb;
     279           0 : }
     280             : 
     281             : void *
     282           0 : fd_blockdb_delete( void * shblockdb ) {
     283           0 :   if( FD_UNLIKELY( !shblockdb ) ) {
     284           0 :     FD_LOG_WARNING(( "NULL blockdb" ));
     285           0 :     return NULL;
     286           0 :   }
     287             : 
     288           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shblockdb, fd_blockdb_align() ) ) ) {
     289           0 :     FD_LOG_WARNING(( "misaligned blockdb" ));
     290           0 :     return NULL;
     291           0 :   }
     292             : 
     293           0 :   return shblockdb;
     294           0 : }
     295             : 
     296             : fd_blockdb_blk_t *
     297             : fd_blockdb_insert( fd_blockdb_t *    blockdb,
     298             :                    ulong             slot,
     299             :                    fd_hash_t const * block_id,
     300             :                    ulong             parent_slot,
     301             :                    fd_hash_t const * parent_block_id,
     302             :                    uint              fec_set_cnt,
     303           0 :                    uchar const *     merkle_roots ) {
     304           0 :   if( FD_UNLIKELY( !fec_set_cnt || fec_set_cnt>FD_FEC_BLK_MAX ) ) return NULL;
     305             : 
     306           0 :   fd_blockdb_map_t * map = (fd_blockdb_map_t *)blockdb->map;
     307           0 :   fd_blockdb_key_t   key = { .slot = slot, .block_id = *block_id };
     308             : 
     309           0 :   fd_blockdb_blk_t * blk = fd_blockdb_map_ele_query( map, &key, NULL, blockdb->ele );
     310           0 :   if( FD_LIKELY( !blk ) ) {
     311             :     /* Take the oldest slot, unlinking its previous occupant once the
     312             :        array has wrapped. */
     313           0 :     blk = blockdb->ele + (blockdb->seq % blockdb->ele_max);
     314           0 :     if( FD_LIKELY( blockdb->seq>=blockdb->ele_max ) ) fd_blockdb_map_ele_remove_fast( map, blk, blockdb->ele );
     315           0 :     blockdb->seq++;
     316           0 :     blk->key = key;
     317           0 :     fd_blockdb_map_ele_insert( map, blk, blockdb->ele );
     318           0 :   }
     319             : 
     320           0 :   blk->parent_slot     = parent_slot;
     321           0 :   blk->parent_block_id = *parent_block_id;
     322           0 :   blk->fec_set_cnt     = fec_set_cnt;
     323           0 :   fd_memcpy( blk->merkle_roots, merkle_roots, fec_set_cnt*FD_SHRED_MERKLE_NODE_SZ );
     324           0 :   return blk;
     325           0 : }
     326             : 
     327             : fd_blockdb_blk_t const *
     328             : fd_blockdb_query( fd_blockdb_t const * blockdb,
     329             :                   ulong                slot,
     330           0 :                   fd_hash_t const *    block_id ) {
     331           0 :   fd_blockdb_key_t key = { .slot = slot, .block_id = *block_id };
     332           0 :   return fd_blockdb_map_ele_query_const( (fd_blockdb_map_t const *)blockdb->map, &key, NULL, blockdb->ele );
     333           0 : }
     334             : 
     335             : int
     336             : fd_blockdb_proof( fd_blockdb_t *           blockdb,
     337             :                   fd_blockdb_blk_t const * blk,
     338             :                   ulong                    leaf_idx,
     339           0 :                   uchar                    proof[ FD_BLOCKDB_PROOF_NODE_MAX*FD_SHRED_MERKLE_NODE_SZ ] ) {
     340           0 :   if( FD_UNLIKELY( leaf_idx>blk->fec_set_cnt ) ) return -1;
     341             : 
     342           0 :   fd_bmtree_commit_t * tree = fd_bmtree_commit_init( blockdb->tree, FD_SHRED_MERKLE_NODE_SZ, FD_BMTREE_LONG_PREFIX_SZ, FD_BLOCKDB_TREE_LAYER_MAX );
     343             : 
     344             :   /* Only the first FD_SHRED_MERKLE_NODE_SZ bytes of a node are hashed,
     345             :      so a zero-padded root prefix is an exact leaf. */
     346           0 :   fd_bmtree_node_t leaf[1] = {0};
     347           0 :   for( uint k=0U; k<blk->fec_set_cnt; k++ ) {
     348           0 :     memcpy( leaf->hash, blk->merkle_roots[ k ], FD_SHRED_MERKLE_NODE_SZ );
     349           0 :     fd_bmtree_commit_append( tree, leaf, 1UL );
     350           0 :   }
     351             : 
     352           0 :   fd_sha256_t sha[1];
     353           0 :   fd_sha256_init  ( sha );
     354           0 :   fd_sha256_append( sha, &blk->parent_slot,       sizeof(ulong)     );
     355           0 :   fd_sha256_append( sha, blk->parent_block_id.uc, sizeof(fd_hash_t) );
     356           0 :   fd_sha256_append( sha, &blk->fec_set_cnt,       sizeof(uint)      );
     357           0 :   fd_sha256_fini  ( sha, leaf->hash );
     358           0 :   fd_bmtree_commit_append( tree, leaf, 1UL );
     359             : 
     360           0 :   fd_bmtree_commit_fini( tree );
     361           0 :   return fd_bmtree_get_proof( tree, proof, leaf_idx );
     362           0 : }

Generated by: LCOV version 1.14