LCOV - code coverage report
Current view: top level - discof/backup - fd_ssmanifest_encoder.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 289 298 97.0 %
Date: 2026-08-14 04:54:57 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* Serialize a chunk of values.
       2             :    Each call may only produce up to FD_SSMANIFEST_BUF_MIN bytes worth of
       3             :    serialized data.  Therefore, we split the serializer into multiple
       4             :    states. */
       5             : 
       6         210 : ENCODE_FN {
       7         210 :   fd_bank_t const * bank = enc->bank;
       8             : 
       9         210 :   PREP
      10             : 
      11         210 :   switch( enc->state ) {
      12           6 :   case STATE_BLOCKHASH_QUEUE: {
      13           3 :     fd_blockhashes_t const *    bhq = &bank->f.block_hash_queue;
      14           3 :     fd_blockhash_info_t const * deq = bhq->d.deque;
      15           3 :     ulong total    = fd_blockhash_deq_cnt( deq );
      16           6 :     ulong to_write = fd_ulong_min( total, FD_BLOCKHASHES_MAX );
      17           3 :     ulong to_skip  = total - to_write;
      18           6 :     PUSH_VAL( ulong, to_write-1UL ); /* last hash index */
      19           3 :     fd_hash_t const * last_hash = fd_blockhashes_peek_last_hash( bhq );
      20           6 :     PUSH_VAL( uchar, !!last_hash );
      21           6 :     if( last_hash ) PUSH_VAL( fd_hash_t, *last_hash );
      22             : 
      23           6 :     PUSH_VAL( ulong, to_write );
      24          12 :     for( ulong i=0UL; i<to_write; i++ ) {
      25           6 :       fd_blockhash_info_t const * ele = fd_blockhash_deq_peek_index_const( deq, to_skip+i );
      26           6 :       PUSH_VAL( fd_hash_t, ele->hash );
      27           6 :       PUSH_VAL( ulong,     ele->lamports_per_signature );
      28           6 :       PUSH_VAL( ulong,     i );
      29           6 :       PUSH_VAL( ulong,     0UL ); /* timestamp, ignored */
      30           3 :     }
      31           6 :     PUSH_VAL( ulong, FD_BLOCKHASHES_MAX-1UL ); /* max_age */
      32           6 :     enc->state = STATE_HASHES;
      33           3 :     break;
      34           3 :   }
      35           6 :   case STATE_HASHES: {
      36           6 :     PUSH_VAL( ulong,     0UL ); /* ancestors */
      37           6 :     PUSH_VAL( fd_hash_t, bank->f.bank_hash      );
      38           6 :     PUSH_VAL( fd_hash_t, bank->f.prev_bank_hash );
      39           6 :     PUSH_VAL( ulong,     bank->f.parent_slot    );
      40           6 :     enc->state = STATE_HARD_FORKS;
      41           3 :     break;
      42           3 :   }
      43           6 :   case STATE_HARD_FORKS: {
      44           6 :     PUSH_VAL( ulong, bank->f.hard_fork_cnt );
      45           6 :     for( ulong i=0UL; i<bank->f.hard_fork_cnt; i++ ) {
      46           0 :       PUSH_VAL( ulong, bank->f.hard_forks[ i ].slot );
      47           0 :       PUSH_VAL( ulong, bank->f.hard_forks[ i ].cnt  );
      48           0 :     }
      49           6 :     enc->state = STATE_COUNTERS;
      50           3 :     break;
      51           3 :   }
      52           6 :   case STATE_COUNTERS: {
      53           6 :     PUSH_VAL( ulong,  bank->f.parent_txn_count + bank->f.txn_count                );
      54           6 :     PUSH_VAL( ulong,  bank->f.tick_height                                         );
      55           6 :     PUSH_VAL( ulong,  bank->f.signature_count                                     );
      56           6 :     PUSH_VAL( ulong,  bank->f.capitalization                                      );
      57           6 :     PUSH_VAL( ulong,  bank->f.max_tick_height                                     );
      58           6 :     PUSH_VAL( uchar,  1                                                           );
      59           6 :     PUSH_VAL( ulong,  bank->f.slot_params.hashes_per_tick                         );
      60           6 :     PUSH_VAL( ulong,  bank->f.ticks_per_slot                                      );
      61           6 :     PUSH_VAL( fd_w_u128_t, (fd_w_u128_t){ .ud = bank->f.slot_params.ns_per_slot } );
      62           6 :     PUSH_VAL( ulong,  bank->f.genesis_creation_time                               );
      63           6 :     PUSH_VAL( double, bank->f.slot_params.slots_per_year                          );
      64           6 :     PUSH_VAL( ulong,  0UL ); /* accounts_data_len, unused */
      65           6 :     PUSH_VAL( ulong,  bank->f.slot                                                );
      66           6 :     PUSH_VAL( ulong,  bank->f.epoch                                               );
      67           6 :     PUSH_VAL( ulong,  bank->f.block_height                                        );
      68           6 :     PUSH_VAL( fd_pubkey_t, (fd_pubkey_t){0} ); /* leader_id, unused */
      69           6 :     PUSH_VAL( ulong, 0UL ); /* unused_collector_fees */
      70           6 :     PUSH_VAL( ulong, 0UL ); /* unused_fee_calculator */
      71             : 
      72           3 :     fd_fee_rate_governor_t const * frg = &bank->f.fee_rate_governor;
      73           6 :     PUSH_VAL( ulong, frg->target_lamports_per_signature );
      74           6 :     PUSH_VAL( ulong, frg->target_signatures_per_slot    );
      75           6 :     PUSH_VAL( ulong, frg->min_lamports_per_signature    );
      76           6 :     PUSH_VAL( ulong, frg->max_lamports_per_signature    );
      77           6 :     PUSH_VAL( uchar, frg->burn_percent                  );
      78           6 :     PUSH_VAL( ulong, 0UL );
      79           6 :     PUSH_VAL( ulong, bank->f.epoch );
      80             : 
      81           3 :     fd_epoch_schedule_t const * es = &bank->f.epoch_schedule;
      82           3 :     fd_rent_t const * rent = &bank->f.rent;
      83           6 :     PUSH_VAL( ulong,  es->slots_per_epoch                );
      84           6 :     PUSH_VAL( ulong,  es->leader_schedule_slot_offset    );
      85           6 :     PUSH_VAL( uchar,  es->warmup                         );
      86           6 :     PUSH_VAL( ulong,  es->first_normal_epoch             );
      87           6 :     PUSH_VAL( ulong,  es->first_normal_slot              );
      88           6 :     PUSH_VAL( double, bank->f.slot_params.slots_per_year );
      89           6 :     PUSH_VAL( ulong,  rent->lamports_per_uint8_year      );
      90           6 :     PUSH_VAL( double, rent->exemption_threshold          );
      91           6 :     PUSH_VAL( uchar,  rent->burn_percent                 );
      92           6 :     PUSH_VAL( ulong,  es->slots_per_epoch                );
      93           6 :     PUSH_VAL( ulong,  es->leader_schedule_slot_offset    );
      94           6 :     PUSH_VAL( uchar,  es->warmup                         );
      95           6 :     PUSH_VAL( ulong,  es->first_normal_epoch             );
      96           6 :     PUSH_VAL( ulong,  es->first_normal_slot              );
      97             : 
      98           3 :     fd_inflation_t const * inf = &bank->f.inflation;
      99           6 :     PUSH_VAL( double, inf->initial        );
     100           6 :     PUSH_VAL( double, inf->terminal       );
     101           6 :     PUSH_VAL( double, inf->taper          );
     102           6 :     PUSH_VAL( double, inf->foundation     );
     103           6 :     PUSH_VAL( double, inf->foundation_term );
     104           6 :     PUSH_VAL( double, inf->unused          );
     105             : 
     106           6 :     enc->state = STATE_VOTE_ACCOUNTS;
     107           3 :     break;
     108           3 :   }
     109           6 :   case STATE_VOTE_ACCOUNTS: {
     110           6 :     PUSH_VAL( ulong, 0UL ); /* zero vote_accounts */
     111           6 :     PUSH_VAL( ulong, 0UL ); /* zero stake delegations */
     112           6 :     PUSH_VAL( ulong, 0UL ); /* unused */
     113           6 :     PUSH_VAL( ulong, bank->f.epoch );
     114           6 :     enc->state = STATE_STAKE_HISTORY;
     115           3 :     break;
     116           3 :   }
     117           0 :   case STATE_STAKE_DELEGATION: { FD_LOG_ERR(( "TODO")); }
     118           0 :   case STATE_STAKE_EPOCH: { FD_LOG_ERR(( "TODO")); }
     119           6 :   case STATE_STAKE_HISTORY: {
     120           6 :     PUSH_VAL( ulong, 0UL ); /* zero stake history entries */
     121           6 :     enc->state = STATE_BANK_TRAILER;
     122           3 :     break;
     123           3 :   }
     124           6 :   case STATE_BANK_TRAILER: {
     125           6 :     PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused1 */
     126           6 :     PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused2 */
     127           6 :     PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused3 */
     128           6 :     PUSH_VAL( ulong, 0UL ); /* unused_epoch_stakes */
     129           6 :     PUSH_VAL( uchar, 0   ); /* is_delta */
     130           6 :     PUSH_VAL( ulong, 0UL ); /* zero account_storage_entries */
     131           6 :     enc->state = STATE_BANK_HASH_INFO;
     132           3 :     break;
     133           3 :   }
     134           0 :   case STATE_ACCOUNT_STORAGE_ENTRY: { FD_LOG_ERR(( "TODO")); }
     135           6 :   case STATE_BANK_HASH_INFO: {
     136             :     /* AccountsDbFields */
     137           6 :     PUSH_VAL( ulong, 0UL          ); /* write_version, unused */
     138           6 :     PUSH_VAL( ulong, bank->f.slot ); /* slot */
     139           6 :     PUSH_VAL( fd_hash_t, (fd_hash_t){0} ); /* unused_accounts_delta_hash */
     140           6 :     PUSH_VAL( fd_hash_t, (fd_hash_t){0} ); /* unused_accounts_hash */
     141           6 :     PUSH_VAL( ulong, 0UL ); /* num_updated_accounts, unused */
     142           6 :     PUSH_VAL( ulong, 0UL ); /* num_removed_accounts, unused */
     143           6 :     PUSH_VAL( ulong, 0UL ); /* num_lamports_stored, unused */
     144           6 :     PUSH_VAL( ulong, 0UL ); /* total_data_len, unused */
     145           6 :     PUSH_VAL( ulong, 0UL ); /* num_executable_accounts, unused */
     146           6 :     PUSH_VAL( ulong, 0UL ); /* historical_roots, unused */
     147           6 :     PUSH_VAL( ulong, 0UL ); /* historical_roots_with_hash, unused */
     148             :     /* ExtraFieldsToSerialize */
     149           6 :     PUSH_VAL( ulong, bank->f.rbh_lamports_per_sig );
     150           6 :     PUSH_VAL( uchar, 0 ); /* unused_incremental_snapshot_persistence */
     151           6 :     PUSH_VAL( uchar, 0 ); /* unused_epoch_accounts_hash */
     152             : 
     153           3 :     ulong epoch = bank->f.epoch;
     154           6 :     ulong epoch_cnt = (epoch > 0UL) ? 3UL : 2UL;
     155           6 :     PUSH_VAL( ulong, epoch_cnt );
     156           3 :     enc->epoch_cnt = (uchar)epoch_cnt;
     157           3 :     enc->epoch_idx = 0;
     158           6 :     enc->state = STATE_EPOCH_STAKES;
     159           3 :     break;
     160           3 :   }
     161          18 :   case STATE_EPOCH_STAKES: {
     162           9 :     ulong epoch = bank->f.epoch;
     163          18 :     ulong epoch_stakes_base = (epoch > 0UL) ? (epoch - 1UL) : 0UL;
     164           9 :     ulong epoch_key = epoch_stakes_base + (ulong)enc->epoch_idx;
     165             : 
     166             :     /* entry_type: 0=T-3 commission, 1=T-2 stakes, 2=T-1 stakes+credits */
     167          18 :     uint entry_type = (epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
     168           9 :     fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
     169           9 :     ulong              fork_id     = bank->vote_stakes_fork_id;
     170             : 
     171           9 :     uint vote_cnt;
     172          18 :     if( entry_type==2U ) {
     173           6 :       vote_cnt = (uint)fd_vote_stakes_cnt_t_1( vote_stakes, fork_id );
     174           6 :       fd_vote_stakes_t_1_iter_init( vote_stakes, fork_id, enc->vote_stakes_iter_mem );
     175          12 :     } else if( entry_type==1U ) {
     176           6 :       vote_cnt = (uint)fd_vote_stakes_cnt_t_2( vote_stakes, fork_id );
     177           6 :       fd_vote_stakes_t_2_iter_init( vote_stakes, fork_id, enc->vote_stakes_iter_mem );
     178           6 :     } else {
     179           6 :       vote_cnt = (uint)*fd_bank_epoch_credits_len( enc->bank );
     180           6 :     }
     181           9 :     enc->vote_cnt    = vote_cnt;
     182           9 :     enc->vote_idx    = 0;
     183           9 :     enc->total_stake = 0UL;
     184             : 
     185          18 :     PUSH_VAL( ulong, epoch_key );
     186          18 :     PUSH_VAL( uint,  0U ); /* variant = 0 (VersionedEpochStakes::Current) */
     187          18 :     PUSH_VAL( ulong, (ulong)vote_cnt );
     188             : 
     189          18 :     enc->state = (vote_cnt > 0U) ? STATE_EPOCH_STAKES_STAKES : STATE_EPOCH_STAKES_EPOCH;
     190           9 :     break;
     191           9 :   }
     192          54 :   case STATE_EPOCH_STAKES_STAKES: {
     193          54 :     ulong epoch = bank->f.epoch;
     194          54 :     uint entry_type = (epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
     195             : 
     196          54 :     fd_pubkey_t pubkey       = {0};
     197          54 :     ulong       stake        = 0UL;
     198          54 :     fd_pubkey_t node_account = {0};
     199          54 :     ushort      commission   = 0;
     200          54 :     ulong       ec_cnt       = 0UL;
     201          54 :     fd_epoch_credits_t const * ec = NULL;
     202             : 
     203          54 :     fd_collector_overrides_t * overrides = fd_bank_collector_overrides( bank );
     204          54 :     ushort co_root = fd_collector_overrides_get_root_idx( overrides );
     205          54 :     ulong  co_epoch = ULONG_MAX; /* no collector lookup */
     206          54 :     fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
     207          54 :     ulong              fork_id     = bank->vote_stakes_fork_id;
     208             : 
     209          54 :     if( entry_type==2U ) {
     210          18 :       fd_vote_stakes_t_1_iter_t * iter = fd_type_pun( enc->vote_stakes_iter_mem );
     211          18 :       FD_TEST( !fd_vote_stakes_t_1_iter_done( vote_stakes, fork_id, iter ) );
     212          18 :       fd_vote_stakes_t_1_iter_ele( vote_stakes, fork_id, iter, &pubkey, &node_account, &stake, &commission );
     213          18 :       ec = find_epoch_credits( enc->bank, &pubkey );
     214          18 :       FD_TEST( ec );
     215          18 :       ec_cnt = ec->cnt;
     216          18 :       co_epoch = bank->f.epoch;
     217          36 :     } else if( entry_type==1U ) {
     218          18 :       fd_vote_stakes_t_2_iter_t * iter = fd_type_pun( enc->vote_stakes_iter_mem );
     219          18 :       FD_TEST( !fd_vote_stakes_t_2_iter_done( vote_stakes, fork_id, iter ) );
     220          18 :       fd_vote_stakes_t_2_iter_ele( vote_stakes, fork_id, iter, &pubkey, &node_account, &stake, NULL, NULL, &commission, NULL );
     221          18 :       co_epoch = fd_ulong_sat_sub( bank->f.epoch, 1UL );
     222          18 :     } else {
     223             :       /* The bank epoch credits will have the resolved commission for
     224             :          the vote account.  This means that the commission stored will
     225             :          be the t-3 commission if it existed or the t-2/t-1 commission
     226             :          otherwise as the fallback (see delay_commission_update feature
     227             :          for more details).  This means that the serialized commission
     228             :          for the epoch may be inaccurate but the commission produced
     229             :          will still produce a correct commission for the purposes of
     230             :          rewards.  That is to say that the commission for each vote
     231             :          account will be accurate. */
     232          18 :       ec = &fd_bank_epoch_credits( enc->bank )[ enc->vote_idx ];
     233          18 :       fd_memcpy( &pubkey, ec->pubkey, 32UL );
     234          18 :       commission = ec->commission;
     235          18 :     }
     236             : 
     237             :     /* SIMD-0232 collectors: defaults unless overridden. */
     238          54 :     fd_pubkey_t inflation_collector = {0};
     239          27 :     fd_pubkey_t block_collector     = {0};
     240          54 :     if( FD_LIKELY( co_epoch!=ULONG_MAX ) ) {
     241          36 :       inflation_collector = pubkey;
     242          36 :       block_collector     = node_account;
     243          36 :       fd_collector_overrides_query( overrides, co_root, co_epoch, &pubkey, &inflation_collector, &block_collector );
     244          36 :     }
     245             : 
     246          27 :     enc->total_stake += stake;
     247          27 :     ulong data_length = 186UL + 24UL * ec_cnt;
     248             : 
     249             :     /* Vote account key + stake */
     250          54 :     PUSH_VAL( fd_pubkey_t, pubkey );
     251          54 :     PUSH_VAL( ulong,       stake  );
     252             : 
     253             :     /* AccountSharedData: lamports, data_length */
     254          54 :     PUSH_VAL( ulong, 0UL         );
     255          54 :     PUSH_VAL( ulong, data_length );
     256             : 
     257             :     /* VoteStateV4 */
     258          54 :     PUSH_VAL( uint,       3U           ); /* variant = V4 */
     259          54 :     PUSH_VAL( fd_pubkey_t, node_account ); /* node_pubkey */
     260          54 :     PUSH_VAL( fd_pubkey_t, (fd_pubkey_t){0} ); /* authorized_withdrawer */
     261          54 :     PUSH_VAL( fd_pubkey_t, inflation_collector ); /* inflation_rewards_collector */
     262          54 :     PUSH_VAL( fd_pubkey_t, block_collector     ); /* block_revenue_collector */
     263          54 :     PUSH_VAL( ushort, commission ); /* inflation_rewards_commission_bps */
     264          54 :     PUSH_VAL( ushort, (ushort)0 ); /* block_revenue_commission_bps */
     265          54 :     PUSH_VAL( ulong,  0UL      ); /* pending_delegator_rewards */
     266          54 :     PUSH_VAL( uchar,  0        ); /* bls_pubkey_compressed = None */
     267          54 :     PUSH_VAL( ulong,  0UL      ); /* votes_length = 0 */
     268          54 :     PUSH_VAL( uchar,  0        ); /* root_slot = None */
     269          54 :     PUSH_VAL( ulong,  0UL      ); /* authorized_voters_length = 0 */
     270             : 
     271             :     /* Epoch credits */
     272          54 :     PUSH_VAL( ulong, ec_cnt );
     273         108 :     for( ulong j=0UL; j<ec_cnt; j++ ) {
     274          54 :       PUSH_VAL( ulong, (ulong)ec->epoch[j] );
     275          54 :       PUSH_VAL( ulong, ec->base_credits + (ulong)ec->credits_delta[j] );
     276          54 :       PUSH_VAL( ulong, ec->base_credits + (ulong)ec->prev_credits_delta[j] );
     277          27 :     }
     278             : 
     279          54 :     PUSH_VAL( ulong, 0UL ); /* last_timestamp_slot */
     280          54 :     PUSH_VAL( ulong, 0UL ); /* last_timestamp_timestamp */
     281             : 
     282             :     /* AccountSharedData trailer */
     283          54 :     PUSH_VAL( fd_pubkey_t, fd_solana_vote_program_id ); /* owner */
     284          54 :     PUSH_VAL( uchar,       1                         ); /* executable */
     285          54 :     PUSH_VAL( ulong,       0UL                       ); /* rent_epoch */
     286             : 
     287          27 :     enc->vote_idx++;
     288          54 :     if( entry_type==2U ) {
     289          18 :       fd_vote_stakes_t_1_iter_next( vote_stakes, fork_id, fd_type_pun( enc->vote_stakes_iter_mem ) );
     290          36 :     } else if( entry_type==1U ) {
     291          18 :       fd_vote_stakes_t_2_iter_next( vote_stakes, fork_id, fd_type_pun( enc->vote_stakes_iter_mem ) );
     292          18 :     }
     293          54 :     if( enc->vote_idx >= enc->vote_cnt ) enc->state = STATE_EPOCH_STAKES_EPOCH;
     294          27 :     break;
     295          27 :   }
     296          18 :   case STATE_EPOCH_STAKES_EPOCH: {
     297           9 :     ulong epoch = bank->f.epoch;
     298          18 :     ulong epoch_stakes_base = (epoch > 0UL) ? (epoch - 1UL) : 0UL;
     299           9 :     ulong epoch_key = epoch_stakes_base + (ulong)enc->epoch_idx;
     300             : 
     301          18 :     PUSH_VAL( ulong, 0UL       ); /* stake_delegations_length = 0 */
     302          18 :     PUSH_VAL( ulong, 0UL       ); /* unused */
     303          18 :     PUSH_VAL( ulong, epoch_key ); /* epoch */
     304          18 :     PUSH_VAL( ulong, 0UL       ); /* stake_history_length = 0 */
     305          18 :     enc->state = STATE_EPOCH_TOTAL_STAKE;
     306           9 :     break;
     307           9 :   }
     308           0 :   case STATE_EPOCH_STAKE_HISTORY: { __builtin_unreachable(); }
     309          18 :   case STATE_EPOCH_TOTAL_STAKE: {
     310          18 :     uint entry_type = (bank->f.epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
     311          18 :     ulong total_stake = (entry_type==2U) ? bank->f.total_epoch_stake : enc->total_stake;
     312          18 :     PUSH_VAL( ulong, total_stake );
     313          18 :     enc->state = STATE_NODE_VOTE_ACCOUNTS;
     314           9 :     break;
     315           9 :   }
     316          18 :   case STATE_NODE_VOTE_ACCOUNTS: {
     317          18 :     PUSH_VAL( ulong, 0UL ); /* node_id_to_vote_accounts_length = 0 */
     318          18 :     enc->state = STATE_AUTH_VOTER;
     319           9 :     break;
     320           9 :   }
     321          18 :   case STATE_AUTH_VOTER: {
     322          18 :     PUSH_VAL( ulong, 0UL ); /* epoch_authorized_voters_length = 0 */
     323           9 :     enc->epoch_idx++;
     324          18 :     enc->state = (enc->epoch_idx < enc->epoch_cnt) ? STATE_EPOCH_STAKES : STATE_LTHASH;
     325           9 :     break;
     326           9 :   }
     327           6 :   case STATE_LTHASH: {
     328           6 :     PUSH_VAL( uchar, 1 );
     329           6 :     PUSH_VAL( fd_lthash_value_t, bank->f.lthash );
     330           6 :     enc->state = STATE_BLOCK_ID;
     331           3 :     break;
     332           3 :   }
     333           6 :   case STATE_BLOCK_ID: {
     334           3 :     int has_block_id = !fd_hash_check_zero( &bank->f.block_id );
     335           6 :     PUSH_VAL( uchar, (uchar)has_block_id );
     336           6 :     if( has_block_id ) PUSH_VAL( fd_hash_t, bank->f.block_id );
     337           6 :     enc->state = STATE_DONE;
     338           3 :     break;
     339           3 :   }
     340           6 :   case STATE_DONE:
     341           6 :     return 0UL;
     342           0 :   default:
     343           0 :     FD_LOG_CRIT(( "invalid state reached (%u)", enc->state ));
     344         210 :   }
     345             : 
     346         204 :   return RET_EXPR;
     347         210 : }
     348             : 
     349             : #undef PREP
     350             : #undef ENCODE_FN
     351             : #undef PUSH_VAL
     352             : #undef RET_EXPR

Generated by: LCOV version 1.14