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 : #include "../context/fd_exec_epoch_ctx.h"
8 :
9 : static void
10 0 : write_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_sysvar_epoch_rewards_t * epoch_rewards ) {
11 0 : ulong sz = fd_sysvar_epoch_rewards_size( epoch_rewards );
12 0 : uchar enc[sz];
13 0 : fd_memset( enc, 0, sz );
14 0 : fd_bincode_encode_ctx_t ctx;
15 0 : ctx.data = enc;
16 0 : ctx.dataend = enc + sz;
17 0 : if ( 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, fd_sysvar_owner_id.key, &fd_sysvar_epoch_rewards_id, enc, sz, slot_ctx->slot_bank.slot );
22 0 : }
23 :
24 : fd_sysvar_epoch_rewards_t *
25 : fd_sysvar_epoch_rewards_read( fd_sysvar_epoch_rewards_t * result,
26 : fd_sysvar_cache_t const * sysvar_cache,
27 : fd_acc_mgr_t * acc_mgr,
28 0 : fd_funk_txn_t * funk_txn ) {
29 0 : fd_sysvar_epoch_rewards_t const * ret = (fd_sysvar_epoch_rewards_t const *)fd_sysvar_cache_epoch_rewards( sysvar_cache );
30 0 : if( FD_UNLIKELY( NULL != ret ) ) {
31 0 : fd_memcpy(result, ret, sizeof(fd_sysvar_epoch_rewards_t));
32 0 : return result;
33 0 : }
34 :
35 0 : FD_TXN_ACCOUNT_DECL( acc );
36 0 : int err = fd_acc_mgr_view( acc_mgr, funk_txn, &fd_sysvar_epoch_rewards_id, acc );
37 0 : if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) {
38 0 : return NULL;
39 0 : }
40 :
41 0 : fd_bincode_decode_ctx_t decode = {
42 0 : .data = acc->const_data,
43 0 : .dataend = acc->const_data + acc->const_meta->dlen
44 0 : };
45 :
46 0 : ulong total_sz = 0UL;
47 0 : err = fd_sysvar_epoch_rewards_decode_footprint( &decode, &total_sz );
48 :
49 0 : if( FD_UNLIKELY( err ) ) {
50 0 : return NULL;
51 0 : }
52 :
53 : /* We assume here that the data structure is properly allocated already.
54 : This could potentially be unsafe if not handled correctly by the caller. */
55 0 : fd_sysvar_epoch_rewards_decode( result, &decode );
56 :
57 0 : return result;
58 0 : }
59 :
60 : /* Since there are multiple sysvar epoch rewards updates within a single slot,
61 : we need to ensure that the cache stays updated after each change (versus with other
62 : sysvars which only get updated once per slot and then synced up after) */
63 : void
64 : fd_sysvar_epoch_rewards_distribute( fd_exec_slot_ctx_t * slot_ctx,
65 : ulong distributed,
66 0 : fd_spad_t * runtime_spad ) {
67 0 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
68 0 : if ( FD_UNLIKELY( fd_sysvar_epoch_rewards_read( epoch_rewards,
69 0 : slot_ctx->sysvar_cache,
70 0 : slot_ctx->acc_mgr,
71 0 : slot_ctx->funk_txn ) == NULL ) ) {
72 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" ));
73 0 : }
74 0 : FD_TEST( epoch_rewards->active );
75 :
76 0 : FD_TEST( fd_ulong_sat_add( epoch_rewards->distributed_rewards, distributed ) <= epoch_rewards->total_rewards );
77 :
78 0 : epoch_rewards->distributed_rewards += distributed;
79 :
80 0 : write_epoch_rewards( slot_ctx, epoch_rewards );
81 :
82 : /* Sync the epoch rewards sysvar cache entry with the account */
83 0 : fd_sysvar_cache_restore_epoch_rewards( slot_ctx->sysvar_cache,
84 0 : slot_ctx->acc_mgr,
85 0 : slot_ctx->funk_txn,
86 0 : runtime_spad,
87 0 : slot_ctx->runtime_wksp );
88 0 : }
89 :
90 : void
91 : fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx,
92 0 : fd_spad_t * runtime_spad ) {
93 0 : fd_sysvar_epoch_rewards_t epoch_rewards[1];
94 0 : if ( FD_UNLIKELY( fd_sysvar_epoch_rewards_read( epoch_rewards,
95 0 : slot_ctx->sysvar_cache,
96 0 : slot_ctx->acc_mgr,
97 0 : slot_ctx->funk_txn ) == NULL ) ) {
98 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" ));
99 0 : }
100 :
101 0 : if ( FD_LIKELY( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, partitioned_epoch_rewards_superfeature ) ) ) {
102 0 : FD_TEST( epoch_rewards->total_rewards >= epoch_rewards->distributed_rewards );
103 0 : } else {
104 0 : FD_TEST( epoch_rewards->total_rewards == epoch_rewards->distributed_rewards );
105 0 : }
106 :
107 :
108 0 : epoch_rewards->active = 0;
109 :
110 0 : write_epoch_rewards( slot_ctx, epoch_rewards );
111 :
112 : /* Sync the epoch rewards sysvar cache entry with the account */
113 0 : fd_sysvar_cache_restore_epoch_rewards( slot_ctx->sysvar_cache,
114 0 : slot_ctx->acc_mgr,
115 0 : slot_ctx->funk_txn,
116 0 : runtime_spad,
117 0 : slot_ctx->runtime_wksp );
118 0 : }
119 :
120 : /* Create EpochRewards syavar with calculated rewards
121 :
122 : https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L25 */
123 : void
124 : fd_sysvar_epoch_rewards_init(
125 : fd_exec_slot_ctx_t * slot_ctx,
126 : ulong total_rewards,
127 : ulong distributed_rewards,
128 : ulong distribution_starting_block_height,
129 : ulong num_partitions,
130 : fd_point_value_t point_value,
131 : const fd_hash_t * last_blockhash
132 0 : ) {
133 0 : FD_TEST( total_rewards >= distributed_rewards );
134 :
135 0 : fd_sysvar_epoch_rewards_t epoch_rewards = {
136 0 : .distribution_starting_block_height = distribution_starting_block_height,
137 0 : .num_partitions = num_partitions,
138 0 : .total_points = point_value.points,
139 0 : .total_rewards = total_rewards,
140 0 : .distributed_rewards = distributed_rewards,
141 0 : .active = 1
142 0 : };
143 :
144 : /* On clusters where partitioned_epoch_rewards_superfeature is enabled, we should use point_value.rewards.
145 : On other clusters, including those where enable_partitioned_epoch_reward is enabled, we should use total_rewards.
146 :
147 : https://github.com/anza-xyz/agave/blob/b9c9ecccbb05d9da774d600bdbef2cf210c57fa8/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L36-L43 */
148 0 : if( FD_LIKELY( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, partitioned_epoch_rewards_superfeature ) ) ) {
149 0 : epoch_rewards.total_rewards = point_value.rewards;
150 0 : }
151 :
152 0 : fd_memcpy( &epoch_rewards.parent_blockhash, last_blockhash, FD_HASH_FOOTPRINT );
153 :
154 0 : write_epoch_rewards( slot_ctx, &epoch_rewards );
155 0 : }
|