Line data Source code
1 : #include "fd_sysvar_epoch_rewards.h"
2 : #include "fd_sysvar.h"
3 : #include "../fd_system_ids.h"
4 : #include "../../accdb/fd_accdb_sync.h"
5 :
6 : static void
7 : write_epoch_rewards( fd_bank_t * bank,
8 : fd_accdb_user_t * accdb,
9 : fd_funk_txn_xid_t const * xid,
10 : fd_capture_ctx_t * capture_ctx,
11 6 : fd_sysvar_epoch_rewards_t * epoch_rewards ) {
12 6 : ulong sz = fd_sysvar_epoch_rewards_size( epoch_rewards );
13 6 : uchar enc[sz];
14 6 : fd_memset( enc, 0, sz );
15 6 : fd_bincode_encode_ctx_t ctx = {
16 6 : .data = enc,
17 6 : .dataend = enc + sz
18 6 : };
19 6 : if( FD_UNLIKELY( fd_sysvar_epoch_rewards_encode( epoch_rewards, &ctx ) ) ) {
20 0 : FD_LOG_ERR(( "fd_sysvar_epoch_rewards_encode failed" ));
21 0 : }
22 :
23 6 : fd_sysvar_account_update( bank, accdb, xid, capture_ctx, &fd_sysvar_epoch_rewards_id, enc, sz );
24 6 : }
25 :
26 : fd_sysvar_epoch_rewards_t *
27 : fd_sysvar_epoch_rewards_read( fd_accdb_user_t * accdb,
28 : fd_funk_txn_xid_t const * xid,
29 303 : fd_sysvar_epoch_rewards_t * out ) {
30 303 : fd_accdb_ro_t ro[1];
31 303 : if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, &fd_sysvar_epoch_rewards_id ) ) ) {
32 0 : return NULL;
33 0 : }
34 :
35 : /* This check is needed as a quirk of the fuzzer. If a sysvar account
36 : exists in the accounts database, but doesn't have any lamports,
37 : this means that the account does not exist. This wouldn't happen
38 : in a real execution environment. */
39 303 : if( FD_UNLIKELY( fd_accdb_ref_lamports( ro )==0UL ) ) {
40 0 : fd_accdb_close_ro( accdb, ro );
41 0 : return NULL;
42 0 : }
43 :
44 303 : out = fd_bincode_decode_static(
45 303 : sysvar_epoch_rewards, out,
46 303 : fd_accdb_ref_data_const( ro ),
47 303 : fd_accdb_ref_data_sz ( ro ) );
48 303 : fd_accdb_close_ro( accdb, ro );
49 303 : return out;
50 303 : }
51 :
52 : /* Since there are multiple sysvar epoch rewards updates within a single slot,
53 : we need to ensure that the cache stays updated after each change (versus with other
54 : sysvars which only get updated once per slot and then synced up after) */
55 : void
56 : fd_sysvar_epoch_rewards_distribute( fd_bank_t * bank,
57 : fd_accdb_user_t * accdb,
58 : fd_funk_txn_xid_t const * xid,
59 : fd_capture_ctx_t * capture_ctx,
60 2 : ulong distributed ) {
61 2 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
62 2 : if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( accdb, xid, epoch_rewards ) ) ) {
63 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" ));
64 0 : }
65 :
66 2 : if( FD_UNLIKELY( !epoch_rewards->active ) ) {
67 0 : FD_LOG_ERR(( "sysvar epoch rewards is not active" ));
68 0 : }
69 :
70 2 : if( FD_UNLIKELY( fd_ulong_sat_add( epoch_rewards->distributed_rewards, distributed ) > epoch_rewards->total_rewards ) ) {
71 0 : FD_LOG_ERR(( "distributed rewards overflow" ));
72 0 : }
73 :
74 2 : epoch_rewards->distributed_rewards += distributed;
75 :
76 2 : write_epoch_rewards( bank, accdb, xid, capture_ctx, epoch_rewards );
77 2 : }
78 :
79 : void
80 : fd_sysvar_epoch_rewards_set_inactive( fd_bank_t * bank,
81 : fd_accdb_user_t * accdb,
82 : fd_funk_txn_xid_t const * xid,
83 2 : fd_capture_ctx_t * capture_ctx ) {
84 2 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
85 2 : if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( accdb, xid, epoch_rewards ) ) ) {
86 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" ));
87 0 : }
88 :
89 2 : if( FD_UNLIKELY( epoch_rewards->total_rewards < epoch_rewards->distributed_rewards ) ) {
90 0 : FD_LOG_ERR(( "distributed rewards overflow" ));
91 0 : }
92 :
93 2 : epoch_rewards->active = 0;
94 :
95 2 : write_epoch_rewards( bank, accdb, xid, capture_ctx, epoch_rewards );
96 2 : }
97 :
98 : /* Create EpochRewards sysvar with calculated rewards
99 :
100 : https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L25 */
101 : void
102 : fd_sysvar_epoch_rewards_init( fd_bank_t * bank,
103 : fd_accdb_user_t * accdb,
104 : fd_funk_txn_xid_t const * xid,
105 : fd_capture_ctx_t * capture_ctx,
106 : ulong distributed_rewards,
107 : ulong distribution_starting_block_height,
108 : ulong num_partitions,
109 : ulong total_rewards,
110 : uint128 total_points,
111 2 : fd_hash_t const * last_blockhash ) {
112 2 : fd_sysvar_epoch_rewards_t epoch_rewards = {
113 2 : .distribution_starting_block_height = distribution_starting_block_height,
114 2 : .num_partitions = num_partitions,
115 2 : .total_points = { .ud=total_points },
116 2 : .total_rewards = total_rewards,
117 2 : .distributed_rewards = distributed_rewards,
118 2 : .active = 1,
119 2 : .parent_blockhash = *last_blockhash
120 2 : };
121 :
122 2 : if( FD_UNLIKELY( epoch_rewards.total_rewards<distributed_rewards ) ) {
123 0 : FD_LOG_ERR(( "total rewards overflow" ));
124 0 : }
125 :
126 2 : write_epoch_rewards( bank, accdb, xid, capture_ctx, &epoch_rewards );
127 2 : }
|