LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_reward_epoch_delegated_stakes.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 87 93 93.5 %
Date: 2026-11-12 04:25:03 Functions: 3 9 33.3 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_rewards_fd_reward_epoch_delegated_stakes_h
       2             : #define HEADER_fd_src_flamenco_rewards_fd_reward_epoch_delegated_stakes_h
       3             : 
       4             : #include "../features/fd_features.h"
       5             : #include "../runtime/fd_accdb_svm.h"
       6             : #include "../runtime/fd_bank.h"
       7             : #include "../runtime/fd_pubkey_utils.h"
       8             : #include "../runtime/fd_runtime_stack_tmpl.h"
       9             : #include "../runtime/fd_system_ids.h"
      10             : #include "../runtime/sysvar/fd_sysvar_rent.h"
      11             : 
      12         318 : #define FD_REWARD_EPOCH_STAKE_MAX_CNT   (FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS)
      13        1050 : #define FD_REWARD_EPOCH_STAKE_HEADER_SZ (16UL)
      14        1050 : #define FD_REWARD_EPOCH_STAKE_ENTRY_SZ  (40UL)
      15         318 : #define FD_REWARD_EPOCH_STAKE_MAX_SZ    (FD_REWARD_EPOCH_STAKE_HEADER_SZ + FD_REWARD_EPOCH_STAKE_ENTRY_SZ*FD_REWARD_EPOCH_STAKE_MAX_CNT)
      16             : 
      17             : /* https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/runtime/src/alpenglow_epoch_type.rs#L12-L42 */
      18             : struct fd_reward_epoch_stake {
      19             :   fd_pubkey_t vote_pubkey;
      20             :   ulong       delegated_stake;
      21             : };
      22             : typedef struct fd_reward_epoch_stake fd_reward_epoch_stake_t;
      23             : 
      24             : #define SORT_NAME        fd_reward_epoch_stake_sort
      25         156 : #define SORT_KEY_T       fd_reward_epoch_stake_t
      26          78 : #define SORT_BEFORE(a,b) (memcmp( (a).vote_pubkey.uc, (b).vote_pubkey.uc, sizeof(fd_pubkey_t) )<0)
      27             : #include "../../util/tmpl/fd_sort.c"
      28             : 
      29             : static inline fd_pubkey_t
      30         336 : fd_reward_epoch_stakes_account_address( void ) {
      31         336 :   fd_feature_id_t const * feature_id  = &ids[ offsetof( fd_features_t, alpenglow )>>3 ];
      32         336 :   fd_pubkey_t const *     program_id  = &feature_id->id;
      33         336 :   uchar const             seed[]      = "reward_epoch_delegated_stakes";
      34         336 :   uchar const *           seeds[1]    = { seed };
      35         336 :   ulong                   seed_szs[1] = { sizeof(seed)-1UL };
      36         336 :   fd_pubkey_t             address[1];
      37         336 :   uchar                   bump_seed;
      38         336 :   uint                    custom_err  = 0U;
      39         336 :   FD_TEST( !fd_pubkey_find_program_address( program_id, 1UL, seeds, seed_szs,
      40         336 :                                             address, &bump_seed, &custom_err ) );
      41         336 :   return *address;
      42         336 : }
      43             : 
      44             : /* https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/runtime/src/alpenglow_epoch_type.rs#L70-L132 */
      45             : static inline void
      46             : fd_reward_epoch_stakes_set( fd_bank_t *                    bank,
      47             :                             fd_accdb_t *                   accdb,
      48             :                             fd_capture_ctx_t *             capture_ctx,
      49             :                             ulong                          rewarded_epoch,
      50         318 :                             fd_runtime_stack_t *           runtime_stack ) {
      51         318 :   fd_stake_accum_t *     pool = runtime_stack->stakes.stake_accum;
      52         318 :   fd_stake_accum_map_t * map  = runtime_stack->stakes.stake_accum_map;
      53             : 
      54         318 :   fd_reward_epoch_stake_t entries[ FD_REWARD_EPOCH_STAKE_MAX_CNT ];
      55         318 :   ulong                   entries_cnt = 0UL;
      56             : 
      57         318 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
      58         318 :   ushort             fork_id     = bank->vote_stakes_fork_id;
      59             : 
      60         318 :   uchar __attribute__((aligned(FD_VOTE_STAKES_ITER_ALIGN))) vote_iter_mem[ FD_VOTE_STAKES_ITER_FOOTPRINT ];
      61         318 :   for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, vote_iter_mem );
      62         714 :        !fd_vote_stakes_iter_done( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter );
      63         396 :        fd_vote_stakes_iter_next( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter ) ) {
      64         396 :     FD_TEST( entries_cnt<FD_REWARD_EPOCH_STAKE_MAX_CNT );
      65         396 :     fd_vote_stakes_ele_t ele[1];
      66         396 :     fd_vote_stakes_iter_ele( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter, ele );
      67         396 :     entries[ entries_cnt ].vote_pubkey = ele->pubkey;
      68         396 :     fd_stake_accum_t const * accumulated = fd_stake_accum_map_ele_query_const(
      69         396 :         map, &entries[ entries_cnt ].vote_pubkey, NULL, pool );
      70         396 :     FD_TEST( accumulated );
      71         396 :     entries[ entries_cnt ].delegated_stake = accumulated->reward_stake;
      72         396 :     entries_cnt++;
      73         396 :   }
      74         318 :   fd_reward_epoch_stake_sort_inplace( entries, entries_cnt );
      75             : 
      76         318 :   uchar data[ FD_REWARD_EPOCH_STAKE_MAX_SZ ];
      77         318 :   FD_STORE( ulong, data,     rewarded_epoch );
      78         318 :   FD_STORE( ulong, data+8UL, entries_cnt     );
      79         714 :   for( ulong i=0UL; i<entries_cnt; i++ ) {
      80         396 :     uchar * dst = data+FD_REWARD_EPOCH_STAKE_HEADER_SZ+i*FD_REWARD_EPOCH_STAKE_ENTRY_SZ;
      81         396 :     fd_memcpy( dst, entries[i].vote_pubkey.uc, sizeof(fd_pubkey_t) );
      82         396 :     FD_STORE( ulong, dst+32UL, entries[i].delegated_stake );
      83         396 :   }
      84         318 :   ulong data_sz = FD_REWARD_EPOCH_STAKE_HEADER_SZ+entries_cnt*FD_REWARD_EPOCH_STAKE_ENTRY_SZ;
      85             : 
      86         318 :   fd_pubkey_t           address = fd_reward_epoch_stakes_account_address();
      87         318 :   fd_accdb_svm_update_t update[1];
      88         318 :   fd_acc_t              acc     = fd_accdb_svm_open_rw( bank, accdb, update, &address, 1 );
      89         318 :   acc.lamports = fd_ulong_max( fd_rent_exempt_minimum_balance( &bank->f.rent, FD_REWARD_EPOCH_STAKE_MAX_SZ ), 1UL );
      90         318 :   fd_memcpy( acc.owner, fd_solana_system_program_id.uc, sizeof(fd_pubkey_t) );
      91         318 :   acc.executable = 0;
      92         318 :   acc.data_len   = data_sz;
      93         318 :   fd_memcpy( acc.data, data, data_sz );
      94         318 :   fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &acc, update );
      95         318 : }
      96             : 
      97             : static inline void
      98             : fd_reward_epoch_stakes_restore( fd_bank_t *          bank,
      99             :                                 fd_accdb_t *         accdb,
     100             :                                 ulong                rewarded_epoch,
     101          18 :                                 fd_runtime_stack_t * runtime_stack ) {
     102          18 :   fd_pubkey_t address = fd_reward_epoch_stakes_account_address();
     103          18 :   fd_acc_t    acc     = fd_accdb_read_one( accdb, bank->accdb_fork_id, address.uc );
     104          18 :   if( FD_UNLIKELY( !acc.lamports ||
     105          18 :                    memcmp( acc.owner, fd_solana_system_program_id.uc, sizeof(fd_pubkey_t) ) ||
     106          18 :                    acc.data_len<FD_REWARD_EPOCH_STAKE_HEADER_SZ ||
     107          18 :                    (acc.data_len-FD_REWARD_EPOCH_STAKE_HEADER_SZ)%FD_REWARD_EPOCH_STAKE_ENTRY_SZ ) ) {
     108           0 :     FD_LOG_CRIT(( "missing reward epoch delegated stakes for Alpenglow epoch %lu", rewarded_epoch ));
     109           0 :   }
     110             : 
     111          18 :   ulong epoch = FD_LOAD( ulong, acc.data );
     112          18 :   ulong cnt   = FD_LOAD( ulong, acc.data+8UL );
     113          18 :   if( FD_UNLIKELY( epoch!=rewarded_epoch ||
     114          18 :                    cnt>FD_REWARD_EPOCH_STAKE_MAX_CNT ||
     115          18 :                    cnt>runtime_stack->max_staked_vote_accounts ||
     116          18 :                    acc.data_len!=FD_REWARD_EPOCH_STAKE_HEADER_SZ+cnt*FD_REWARD_EPOCH_STAKE_ENTRY_SZ ) ) {
     117           0 :     FD_LOG_CRIT(( "invalid reward epoch delegated stakes for Alpenglow epoch %lu", rewarded_epoch ));
     118           0 :   }
     119             : 
     120          18 :   fd_stake_accum_t *     pool = runtime_stack->stakes.stake_accum;
     121          18 :   fd_stake_accum_map_t * map  = runtime_stack->stakes.stake_accum_map;
     122          18 :   fd_stake_accum_map_reset( map );
     123          36 :   for( ulong i=0UL; i<cnt; i++ ) {
     124          18 :     uchar const *      src = acc.data+FD_REWARD_EPOCH_STAKE_HEADER_SZ+i*FD_REWARD_EPOCH_STAKE_ENTRY_SZ;
     125          18 :     fd_stake_accum_t * ele = &pool[i];
     126          18 :     fd_memcpy( ele->pubkey.uc, src, sizeof(fd_pubkey_t) );
     127          18 :     ele->stake        = 0UL;
     128          18 :     ele->reward_stake = FD_LOAD( ulong, src+32UL );
     129          18 :     if( FD_UNLIKELY( fd_stake_accum_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) {
     130           0 :       FD_LOG_CRIT(( "duplicate vote account in reward epoch delegated stakes" ));
     131           0 :     }
     132          18 :     fd_stake_accum_map_ele_insert( map, ele, pool );
     133          18 :   }
     134          18 :   fd_accdb_unread_one( accdb, &acc );
     135          18 : }
     136             : 
     137             : #endif /* HEADER_fd_src_flamenco_rewards_fd_reward_epoch_delegated_stakes_h */

Generated by: LCOV version 1.14