Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_rewards_fd_epoch_inflation_account_h
2 : #define HEADER_fd_src_flamenco_rewards_fd_epoch_inflation_account_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_system_ids.h"
9 : #include "../runtime/sysvar/fd_sysvar_rent.h"
10 :
11 : /* https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/runtime/src/block_component_processor/vote_reward/epoch_inflation_account_state.rs#L14-L175 */
12 3129 : #define FD_EPOCH_INFLATION_STATE_SZ (24UL)
13 27 : #define FD_EPOCH_INFLATION_ACCOUNT_NONE (25UL)
14 24 : #define FD_EPOCH_INFLATION_ACCOUNT_SOME (49UL)
15 :
16 : struct fd_epoch_inflation_state {
17 : ulong max_possible_validator_reward;
18 : ulong slots_per_epoch;
19 : ulong epoch;
20 : };
21 : typedef struct fd_epoch_inflation_state fd_epoch_inflation_state_t;
22 :
23 : struct fd_epoch_inflation_account_state {
24 : fd_epoch_inflation_state_t current;
25 : int has_prev;
26 : fd_epoch_inflation_state_t prev;
27 : };
28 : typedef struct fd_epoch_inflation_account_state fd_epoch_inflation_account_state_t;
29 :
30 : static inline fd_pubkey_t
31 3129 : fd_epoch_inflation_account_address( void ) {
32 3129 : fd_feature_id_t const * feature_id = &ids[ offsetof( fd_features_t, alpenglow )>>3 ];
33 3129 : fd_pubkey_t const * program_id = &feature_id->id;
34 3129 : uchar const seed[] = "vote_reward_account";
35 3129 : uchar const * seeds[1] = { seed };
36 3129 : ulong seed_szs[1] = { sizeof(seed)-1UL };
37 3129 : fd_pubkey_t address[1];
38 3129 : uchar bump_seed;
39 3129 : uint custom_err = 0U;
40 3129 : FD_TEST( !fd_pubkey_find_program_address( program_id, 1UL, seeds, seed_szs, address, &bump_seed, &custom_err ) );
41 3129 : return *address;
42 3129 : }
43 :
44 : static inline fd_epoch_inflation_state_t
45 3084 : fd_epoch_inflation_state_decode( uchar const * data ) {
46 3084 : return (fd_epoch_inflation_state_t) {
47 3084 : .max_possible_validator_reward = FD_LOAD( ulong, data ),
48 3084 : .slots_per_epoch = FD_LOAD( ulong, data+8UL ),
49 3084 : .epoch = FD_LOAD( ulong, data+16UL ),
50 3084 : };
51 3084 : }
52 :
53 : static inline int
54 : fd_epoch_inflation_account_read( fd_bank_t const * bank,
55 : fd_accdb_t * accdb,
56 3081 : fd_epoch_inflation_account_state_t * state ) {
57 3081 : fd_pubkey_t address = fd_epoch_inflation_account_address();
58 3081 : fd_acc_t acc = fd_accdb_read_one( accdb, bank->accdb_fork_id, address.uc );
59 3081 : if( FD_UNLIKELY( !acc.lamports ||
60 3081 : memcmp( acc.owner, fd_solana_system_program_id.uc, sizeof(fd_pubkey_t) ) ||
61 3081 : (acc.data_len!=FD_EPOCH_INFLATION_ACCOUNT_NONE &&
62 3081 : acc.data_len!=FD_EPOCH_INFLATION_ACCOUNT_SOME) ) ) {
63 0 : fd_accdb_unread_one( accdb, &acc );
64 0 : return 0;
65 0 : }
66 :
67 3081 : state->current = fd_epoch_inflation_state_decode( acc.data );
68 3081 : if( FD_UNLIKELY( acc.data[ FD_EPOCH_INFLATION_STATE_SZ ]>1U ) ) {
69 0 : fd_accdb_unread_one( accdb, &acc );
70 0 : return 0;
71 0 : }
72 3081 : state->has_prev = !!acc.data[ FD_EPOCH_INFLATION_STATE_SZ ];
73 3081 : if( FD_UNLIKELY( state->has_prev!=(acc.data_len==FD_EPOCH_INFLATION_ACCOUNT_SOME) ) ) {
74 0 : fd_accdb_unread_one( accdb, &acc );
75 0 : return 0;
76 0 : }
77 3081 : if( state->has_prev ) state->prev = fd_epoch_inflation_state_decode( acc.data+FD_EPOCH_INFLATION_ACCOUNT_NONE );
78 3081 : fd_accdb_unread_one( accdb, &acc );
79 3081 : return 1;
80 3081 : }
81 :
82 : static inline ulong
83 : fd_epoch_inflation_rewards_for_epoch( fd_bank_t const * bank,
84 : fd_accdb_t * accdb,
85 24 : ulong epoch ) {
86 24 : fd_epoch_inflation_account_state_t state[1];
87 24 : if( FD_UNLIKELY( !fd_epoch_inflation_account_read( bank, accdb, state ) ) ) {
88 0 : FD_LOG_CRIT(( "missing epoch inflation account state for Alpenglow reward epoch %lu", epoch ));
89 0 : }
90 24 : if( state->current.epoch==epoch ) return state->current.max_possible_validator_reward;
91 0 : if( state->has_prev && state->prev.epoch==epoch ) return state->prev.max_possible_validator_reward;
92 0 : FD_LOG_CRIT(( "missing epoch inflation state for Alpenglow reward epoch %lu", epoch ));
93 0 : }
94 :
95 : /* fd_epoch_inflation_account_encode writes the account data of state
96 : to data, which has room for FD_EPOCH_INFLATION_ACCOUNT_SOME bytes.
97 : Returns the data size. */
98 :
99 : static inline ulong
100 : fd_epoch_inflation_account_encode( uchar data[ static FD_EPOCH_INFLATION_ACCOUNT_SOME ],
101 48 : fd_epoch_inflation_account_state_t const * state ) {
102 48 : FD_STORE( ulong, data, state->current.max_possible_validator_reward );
103 48 : FD_STORE( ulong, data+8UL, state->current.slots_per_epoch );
104 48 : FD_STORE( ulong, data+16UL, state->current.epoch );
105 48 : data[ FD_EPOCH_INFLATION_STATE_SZ ] = (uchar)!!state->has_prev;
106 48 : if( !state->has_prev ) return FD_EPOCH_INFLATION_ACCOUNT_NONE;
107 24 : FD_STORE( ulong, data+25UL, state->prev.max_possible_validator_reward );
108 24 : FD_STORE( ulong, data+33UL, state->prev.slots_per_epoch );
109 24 : FD_STORE( ulong, data+41UL, state->prev.epoch );
110 24 : return FD_EPOCH_INFLATION_ACCOUNT_SOME;
111 48 : }
112 :
113 : static inline void
114 : fd_epoch_inflation_account_write( fd_bank_t * bank,
115 : fd_accdb_t * accdb,
116 : fd_capture_ctx_t * capture_ctx,
117 24 : fd_epoch_inflation_account_state_t const * state ) {
118 24 : uchar data[ FD_EPOCH_INFLATION_ACCOUNT_SOME ];
119 24 : ulong data_sz = fd_epoch_inflation_account_encode( data, state );
120 :
121 24 : fd_pubkey_t address = fd_epoch_inflation_account_address();
122 24 : fd_accdb_svm_update_t update[1];
123 24 : fd_acc_t acc = fd_accdb_svm_open_rw( bank, accdb, update, &address, 1 );
124 24 : acc.lamports = fd_ulong_max( fd_rent_exempt_minimum_balance( &bank->f.rent, data_sz ), 1UL );
125 24 : fd_memcpy( acc.owner, fd_solana_system_program_id.uc, sizeof(fd_pubkey_t) );
126 24 : acc.executable = 0;
127 24 : acc.data_len = data_sz;
128 24 : fd_memcpy( acc.data, data, data_sz );
129 24 : fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &acc, update );
130 24 : }
131 :
132 : /* https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/runtime/src/block_component_processor/vote_reward/epoch_inflation_account_state.rs#L147-L160 */
133 : static inline void
134 : fd_epoch_inflation_account_update( fd_bank_t * bank,
135 : fd_accdb_t * accdb,
136 : fd_capture_ctx_t * capture_ctx,
137 24 : ulong max_possible_validator_reward ) {
138 24 : fd_epoch_inflation_account_state_t old_state[1];
139 24 : int has_old_state = fd_epoch_inflation_account_read( bank, accdb, old_state );
140 :
141 24 : fd_epoch_inflation_account_state_t new_state = {
142 24 : .current = {
143 24 : .max_possible_validator_reward = max_possible_validator_reward,
144 24 : .slots_per_epoch = bank->f.epoch_schedule.slots_per_epoch,
145 24 : .epoch = bank->f.epoch,
146 24 : },
147 24 : .has_prev = has_old_state,
148 24 : };
149 24 : if( has_old_state ) new_state.prev = old_state->current;
150 24 : fd_epoch_inflation_account_write( bank, accdb, capture_ctx, &new_state );
151 24 : }
152 :
153 : #endif /* HEADER_fd_src_flamenco_rewards_fd_epoch_inflation_account_h */
|