LCOV - code coverage report
Current view: top level - discof/backup - fd_ssmanifest_writer.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 104 111 93.7 %
Date: 2026-11-12 04:25:03 Functions: 4 5 80.0 %

          Line data    Source code
       1             : #include "fd_ssmanifest_writer.h"
       2             : #include "../../flamenco/runtime/fd_system_ids.h"
       3             : #include "../../flamenco/runtime/program/vote/fd_vote_state_versioned.h"
       4             : #include "../../ballet/bls/fd_bls.h"
       5             : 
       6             : #define SORT_NAME        sort_epoch_vote_by_node
       7         228 : #define SORT_KEY_T       fd_ssmanifest_epoch_vote_t
       8         144 : #define SORT_BEFORE(a,b) (0>memcmp( (a).node.uc, (b).node.uc, sizeof(fd_pubkey_t) ))
       9             : #include "../../util/tmpl/fd_sort.c"
      10             : 
      11          60 : #define STATE_BLOCKHASH_QUEUE        1
      12          48 : #define STATE_HASHES                 2
      13          48 : #define STATE_HARD_FORKS             3
      14          48 : #define STATE_COUNTERS               4
      15          48 : #define STATE_VOTE_ACCOUNTS          5
      16           0 : #define STATE_STAKE_DELEGATION       6
      17           0 : #define STATE_STAKE_EPOCH            7
      18          48 : #define STATE_STAKE_HISTORY          8
      19          48 : #define STATE_BANK_TRAILER           9
      20           0 : #define STATE_ACCOUNT_STORAGE_ENTRY 10
      21          48 : #define STATE_BANK_HASH_INFO        11
      22         240 : #define STATE_EPOCH_STAKES          12
      23         552 : #define STATE_EPOCH_STAKES_STAKES   13
      24         360 : #define STATE_EPOCH_STAKES_EPOCH    14
      25         240 : #define STATE_EPOCH_TOTAL_STAKE     15
      26         240 : #define STATE_NODE_VOTE_ACCOUNTS    16
      27         240 : #define STATE_AUTH_VOTER            17
      28         168 : #define STATE_LTHASH                18
      29          48 : #define STATE_BLOCK_ID              19
      30          48 : #define STATE_DONE                  20
      31          24 : #define STATE_INIT STATE_BLOCKHASH_QUEUE
      32             : 
      33             : /* Epoch stakes entries are keyed max(E-3,0)..E+1, as agave retains.
      34             :    Key E+1 is the t-1 set with credits, E the t-2 set, E-1..E-3 the
      35             :    t-3..t-5 sets. */
      36             : 
      37             : static inline ulong
      38             : epoch_stakes_key( fd_bank_t const * bank,
      39        1104 :                   ulong             epoch_idx ) {
      40        1104 :   ulong epoch = bank->f.epoch;
      41        1104 :   return ( epoch>3UL ? epoch-3UL : 0UL ) + epoch_idx;
      42        1104 : }
      43             : 
      44             : static inline int
      45             : epoch_stakes_iter_kind( fd_bank_t const * bank,
      46         732 :                         ulong             epoch_idx ) {
      47         732 :   return (int)( bank->f.epoch + 2UL - epoch_stakes_key( bank, epoch_idx ) );
      48         732 : }
      49             : 
      50             : static fd_epoch_credits_t const *
      51             : find_epoch_credits( fd_bank_t *          bank,
      52          72 :                     fd_pubkey_t const * pubkey ) {
      53          72 :   ulong                      epoch_credits_len;
      54          72 :   fd_epoch_credits_t const * epoch_credits_arr = fd_epoch_credits_store_peek( fd_bank_epoch_credits( bank ), bank->epoch_credits_fork_id, &epoch_credits_len );
      55         144 :   for( ulong i=0UL; i<epoch_credits_len; i++ ) {
      56         144 :     fd_epoch_credits_t const * epoch_credits = &epoch_credits_arr[ i ];
      57         144 :     if( fd_memeq( epoch_credits->pubkey, pubkey, sizeof(fd_pubkey_t) ) ) return epoch_credits;
      58         144 :   }
      59           0 :   return NULL;
      60          72 : }
      61             : 
      62             : /* Size estimate */
      63             : 
      64             : #define ENCODE_FN     static ulong manifest_estimate( fd_ssmanifest_writer_t * enc )
      65         648 : #define PREP          ulong sz = 0UL;
      66        7020 : #define PUSH_VAL(t,n) do { sz += sizeof(t); (void)(n); } while(0)
      67         636 : #define RET_EXPR      sz
      68             : #include "fd_ssmanifest_encoder.c"
      69             : 
      70             : fd_ssmanifest_writer_t *
      71             : fd_ssmanifest_writer_init( fd_ssmanifest_writer_t * enc,
      72             :                            fd_bank_t *              bank,
      73             :                            fd_pubkey_t const *      leader,
      74             :                            fd_accdb_t *             accdb,
      75             :                            fd_accdb_fork_id_t       accdb_fork_id,
      76          12 :                            uchar *                  acc_data ) {
      77          12 :   enc->state       = STATE_BLOCKHASH_QUEUE;
      78          12 :   enc->bank        = bank;
      79          12 :   enc->leader      = *leader;
      80          12 :   enc->epoch_idx   = 0;
      81          12 :   enc->epoch_cnt   = 0;
      82          12 :   enc->vote_cnt    = 0;
      83          12 :   enc->vote_idx    = 0;
      84          12 :   enc->total_stake = 0UL;
      85             : 
      86          12 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
      87          12 :   ushort             fork_id     = bank->vote_stakes_fork_id;
      88          12 :   ulong              epoch_cnt   = fd_ulong_min( bank->f.epoch, 3UL ) + 2UL;
      89          72 :   for( ulong epoch_idx=0UL; epoch_idx<epoch_cnt; epoch_idx++ ) {
      90          60 :     fd_ssmanifest_epoch_map_t * map = &enc->epoch_map[ epoch_idx ];
      91          60 :     ulong epoch_key = epoch_stakes_key( bank, epoch_idx );
      92          60 :     int   iter_kind = epoch_stakes_iter_kind( bank, epoch_idx );
      93             : 
      94             :     /* Agave only reads the maps of the previous, current and next
      95             :        epoch.  Older sets keep empty maps. */
      96          60 :     map->vote_cnt = 0UL;
      97          60 :     map->node_cnt = 0UL;
      98          60 :     if( iter_kind>FD_VOTE_STAKES_ITER_T_3 ) continue;
      99             : 
     100          36 :     for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, iter_kind, enc->vote_stakes_iter_mem );
     101         180 :          !fd_vote_stakes_iter_done( vote_stakes, fork_id, iter_kind, iter );
     102         144 :          fd_vote_stakes_iter_next( vote_stakes, fork_id, iter_kind, iter ) ) {
     103         144 :       fd_ssmanifest_epoch_vote_t * ele = &map->vote[ map->vote_cnt ];
     104         144 :       fd_vote_stakes_ele_t vs_ele[1];
     105         144 :       fd_vote_stakes_iter_ele( vote_stakes, fork_id, iter_kind, iter, vs_ele );
     106         144 :       ele->vote  = vs_ele->pubkey;
     107         144 :       ele->node  = vs_ele->node_account;
     108         144 :       ele->stake = vs_ele->stake;
     109             : 
     110         144 :       ulong lamports;
     111         144 :       int   executable;
     112         144 :       uchar owner[ 32UL ];
     113         144 :       ulong data_len;
     114         144 :       fd_accdb_read_one_nocache( accdb, accdb_fork_id, ele->vote.uc, &lamports, &executable, owner, acc_data, &data_len );
     115         144 :       if( FD_UNLIKELY( !lamports ||
     116         144 :                        !fd_vsv_is_correct_size_owner_and_init( owner, acc_data, data_len ) ||
     117         144 :                        fd_vote_account_authorized_voter( acc_data, data_len, epoch_key, &ele->voter ) ) ) {
     118          24 :         continue;
     119          24 :       }
     120         120 :       map->vote_cnt++;
     121         120 :     }
     122             : 
     123          36 :     sort_epoch_vote_by_node_inplace( map->vote, map->vote_cnt );
     124         156 :     for( ulong i=0UL; i<map->vote_cnt; i++ ) {
     125         120 :       int new_node = ( i==0UL ) || !fd_memeq( map->vote[ i ].node.uc, map->vote[ i-1UL ].node.uc, sizeof(fd_pubkey_t) );
     126         120 :       if( new_node ) {
     127         108 :         map->node_cnt++;
     128         108 :       }
     129         120 :     }
     130          36 :   }
     131             : 
     132          12 :   enc->serialized_sz = 0UL;
     133         648 :   for(;;) {
     134         648 :     ulong chunk = manifest_estimate( enc );
     135         648 :     if( FD_UNLIKELY( !chunk ) ) break;
     136         636 :     enc->serialized_sz += chunk;
     137         636 :   }
     138          12 :   return enc;
     139          12 : }
     140             : 
     141             : /* Actual encoder */
     142             : 
     143             : __attribute__((cold,noreturn))
     144             : static void fail( fd_ssmanifest_writer_t const * enc,
     145             :                   ulong buf_sz,
     146           0 :                   ulong line_nr ) {
     147           0 :   FD_LOG_ERR(( "buffer overflow (state=%u, buf_sz=%lu, line_nr=%lu)", enc->state, buf_sz, line_nr ));
     148           0 : }
     149             : 
     150             : #define ENCODE_FN                                                         \
     151             :   ulong                                                                   \
     152             :   fd_snap_manifest_serialize( fd_ssmanifest_writer_t * enc,               \
     153             :                               uchar out_buf[ FD_SSMANIFEST_BUF_MIN ],     \
     154             :                               ulong buf_sz )
     155             : #define PREP                                                              \
     156         648 :   uchar * p  = out_buf;                                                   \
     157         648 :   uchar * p1 = out_buf+buf_sz;
     158             : #define PUSH_VAL( t, n )                                                  \
     159        7020 :   FD_STORE( t, __extension__({                                            \
     160        7020 :     /* compile time bounds check elide */                                 \
     161        7020 :     if( FD_UNLIKELY( p+sizeof(t) > p1 ) ) fail( enc, buf_sz, __LINE__ );  \
     162        7020 :     uchar * ret = p;                                                      \
     163        7020 :     p += sizeof(t);                                                       \
     164        7020 :     ret;                                                                  \
     165        7020 :   }), (n) )
     166         636 : #define RET_EXPR (ulong)( p - out_buf )
     167             : #include "fd_ssmanifest_encoder.c"

Generated by: LCOV version 1.14