Line data Source code
1 : #include "fd_sysvar_epoch_rewards.h"
2 : #include "../../events/fd_event_runtime.h"
3 : #include "fd_sysvar.h"
4 : #include "../fd_system_ids.h"
5 : #include "../fd_accdb_svm.h"
6 : #include "fd_sysvar_rent.h"
7 :
8 : static int
9 652 : validate( fd_sysvar_epoch_rewards_t const * epoch_rewards ) {
10 652 : return epoch_rewards->active!=0 && epoch_rewards->active!=1;
11 :
12 652 : }
13 :
14 : static void
15 : write_epoch_rewards( fd_bank_t * bank,
16 : fd_accdb_t * accdb,
17 : fd_capture_ctx_t * capture_ctx,
18 115 : fd_sysvar_epoch_rewards_t * epoch_rewards ) {
19 115 : fd_sysvar_account_update( bank, accdb, capture_ctx, &fd_sysvar_epoch_rewards_id, epoch_rewards, FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ );
20 115 : }
21 :
22 : /* write_epoch_rewards with the balance set to the rent exempt minimum,
23 : burning any surplus.
24 : Agave: create_account with RENT_UNADJUSTED_INITIAL_BALANCE followed by
25 : adjust_sysvar_balance_for_rent. */
26 : static void
27 : write_epoch_rewards_reset_balance( fd_bank_t * bank,
28 : fd_accdb_t * accdb,
29 : fd_capture_ctx_t * capture_ctx,
30 0 : fd_sysvar_epoch_rewards_t * epoch_rewards ) {
31 0 : fd_accdb_svm_update_t update[1];
32 0 : fd_acc_t acc = fd_accdb_svm_open_rw( bank, accdb, update, &fd_sysvar_epoch_rewards_id, 1 );
33 0 : fd_memcpy( acc.owner, &fd_sysvar_owner_id, 32UL );
34 0 : acc.executable = 0;
35 0 : fd_memcpy( acc.data, epoch_rewards, FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ );
36 0 : acc.data_len = FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ;
37 0 : acc.lamports = fd_ulong_max( fd_rent_exempt_minimum_balance( &bank->f.rent, acc.data_len ), FD_SYSVAR_RENT_UNADJUSTED_INITIAL_BALANCE );
38 0 : fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &acc, update );
39 0 : }
40 :
41 : fd_sysvar_epoch_rewards_t *
42 : fd_sysvar_epoch_rewards_read( fd_accdb_t * accdb,
43 : fd_accdb_fork_id_t fork_id,
44 698 : fd_sysvar_epoch_rewards_t * out ) {
45 698 : fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, fd_sysvar_epoch_rewards_id.uc );
46 698 : if( FD_UNLIKELY( !acc.lamports ) ) {
47 46 : fd_accdb_unread_one( accdb, &acc );
48 46 : return NULL;
49 46 : }
50 652 : if( FD_UNLIKELY( acc.data_len!=FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ ) ) {
51 0 : fd_accdb_unread_one( accdb, &acc );
52 0 : return NULL;
53 0 : }
54 :
55 652 : fd_memcpy( out, acc.data, FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ );
56 :
57 652 : fd_accdb_unread_one( accdb, &acc );
58 652 : if( FD_UNLIKELY( validate( out ) ) ) return NULL;
59 652 : return out;
60 652 : }
61 :
62 : /* Since there are multiple sysvar epoch rewards updates within a single slot,
63 : we need to ensure that the cache stays updated after each change (versus with other
64 : sysvars which only get updated once per slot and then synced up after) */
65 : void
66 : fd_sysvar_epoch_rewards_distribute( fd_bank_t * bank,
67 : fd_accdb_t * accdb,
68 : fd_capture_ctx_t * capture_ctx,
69 : ulong distributed,
70 41 : ulong debit_block_reward_lamports ) {
71 41 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
72 41 : FD_TEST( fd_sysvar_epoch_rewards_read( accdb, bank->accdb_fork_id, epoch_rewards ) );
73 41 : FD_TEST( epoch_rewards->active );
74 :
75 41 : ulong new_distributed = fd_ulong_sat_add( epoch_rewards->distributed_rewards, distributed );
76 41 : FD_TEST( new_distributed<=epoch_rewards->total_rewards );
77 41 : epoch_rewards->distributed_rewards += distributed;
78 :
79 41 : write_epoch_rewards( bank, accdb, capture_ctx, epoch_rewards );
80 :
81 41 : if( FD_UNLIKELY( !debit_block_reward_lamports ) ) return;
82 :
83 0 : fd_accdb_svm_update_t update[1];
84 0 : fd_acc_t acc = fd_accdb_svm_open_rw( bank, accdb, update, &fd_sysvar_epoch_rewards_id, 0 );
85 : /* https://github.com/anza-xyz/agave/blob/v4.4.0-alpha.5/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L101 */
86 0 : FD_TEST( acc.lamports>=debit_block_reward_lamports );
87 0 : acc.lamports -= debit_block_reward_lamports;
88 : /* https://github.com/anza-xyz/agave/blob/v4.4.0-alpha.5/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L102-L105 */
89 0 : FD_TEST( acc.lamports>=fd_rent_exempt_minimum_balance( &bank->f.rent, acc.data_len ) );
90 0 : fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &acc, update );
91 0 : }
92 :
93 : void
94 : fd_sysvar_epoch_rewards_set_inactive( fd_bank_t * bank,
95 : fd_accdb_t * accdb,
96 42 : fd_capture_ctx_t * capture_ctx ) {
97 42 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
98 42 : FD_TEST( fd_sysvar_epoch_rewards_read( accdb, bank->accdb_fork_id, epoch_rewards ) );
99 42 : FD_TEST( epoch_rewards->total_rewards>=epoch_rewards->distributed_rewards );
100 :
101 42 : epoch_rewards->active = 0;
102 :
103 42 : if( FD_FEATURE_ACTIVE_BANK( bank, block_revenue_sharing ) ) {
104 : /* Don't inherit the balance to ensure that any remaining lamports
105 : get burned: the balance is reset to the rent-exempt minimum and
106 : capitalization is updated.
107 : https://github.com/anza-xyz/agave/blob/v4.4.0-alpha.5/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L120-L135 */
108 0 : write_epoch_rewards_reset_balance( bank, accdb, capture_ctx, epoch_rewards );
109 42 : } else {
110 42 : write_epoch_rewards( bank, accdb, capture_ctx, epoch_rewards );
111 42 : }
112 42 : }
113 :
114 : /* Create EpochRewards sysvar with calculated rewards
115 :
116 : https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L25 */
117 : void
118 : fd_sysvar_epoch_rewards_init( fd_bank_t * bank,
119 : fd_accdb_t * accdb,
120 : fd_capture_ctx_t * capture_ctx,
121 : ulong distributed_rewards,
122 : ulong distribution_starting_block_height,
123 : ulong num_partitions,
124 : ulong total_rewards,
125 : uint128 total_points,
126 : fd_hash_t const * last_blockhash,
127 32 : ulong block_rewards ) {
128 32 : fd_sysvar_epoch_rewards_t epoch_rewards = {
129 32 : .distribution_starting_block_height = distribution_starting_block_height,
130 32 : .num_partitions = num_partitions,
131 32 : .total_points = { .ud=total_points },
132 32 : .total_rewards = total_rewards,
133 32 : .distributed_rewards = distributed_rewards,
134 32 : .active = 1,
135 32 : .parent_blockhash = *last_blockhash
136 32 : };
137 :
138 32 : FD_TEST( epoch_rewards.total_rewards>=epoch_rewards.distributed_rewards );
139 32 : if( FD_UNLIKELY( fd_bank_report_runtime_diffs( bank ) ) ) fd_event_runtime_epoch_rewards( &epoch_rewards );
140 32 : write_epoch_rewards( bank, accdb, capture_ctx, &epoch_rewards );
141 :
142 : /* https://github.com/anza-xyz/agave/blob/v4.4.0-alpha.5/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L58-L69 */
143 32 : if( block_rewards ) {
144 4 : fd_accdb_svm_credit( bank, accdb, capture_ctx, &fd_sysvar_epoch_rewards_id, block_rewards, 0 );
145 4 : }
146 32 : }
|