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