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_txn_account.h" 5 : #include "../fd_system_ids.h" 6 : #include "../context/fd_exec_slot_ctx.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_account_update( slot_ctx, &fd_sysvar_epoch_rewards_id, enc, sz ); 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_sysvar_epoch_rewards_t * out ) { 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( fd_txn_account_get_lamports( acc )==0UL ) ) { 39 0 : return NULL; 40 0 : } 41 : 42 0 : return fd_bincode_decode_static( 43 0 : sysvar_epoch_rewards, out, 44 0 : fd_txn_account_get_data( acc ), 45 0 : fd_txn_account_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 0 : ulong distributed ) { 55 0 : fd_sysvar_epoch_rewards_t epoch_rewards[1]; 56 0 : if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, epoch_rewards ) ) ) { 57 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); 58 0 : } 59 : 60 0 : if( FD_UNLIKELY( !epoch_rewards->active ) ) { 61 0 : FD_LOG_ERR(( "sysvar epoch rewards is not active" )); 62 0 : } 63 : 64 0 : if( FD_UNLIKELY( fd_ulong_sat_add( epoch_rewards->distributed_rewards, distributed ) > epoch_rewards->total_rewards ) ) { 65 0 : FD_LOG_ERR(( "distributed rewards overflow" )); 66 0 : } 67 : 68 0 : epoch_rewards->distributed_rewards += distributed; 69 : 70 0 : write_epoch_rewards( slot_ctx, epoch_rewards ); 71 0 : } 72 : 73 : void 74 0 : fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx ) { 75 0 : fd_sysvar_epoch_rewards_t epoch_rewards[1]; 76 0 : if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, epoch_rewards ) ) ) { 77 0 : FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); 78 0 : } 79 : 80 0 : if( FD_UNLIKELY( epoch_rewards->total_rewards < epoch_rewards->distributed_rewards ) ) { 81 0 : FD_LOG_ERR(( "distributed rewards overflow" )); 82 0 : } 83 : 84 0 : epoch_rewards->active = 0; 85 : 86 0 : write_epoch_rewards( slot_ctx, epoch_rewards ); 87 0 : } 88 : 89 : /* Create EpochRewards sysvar with calculated rewards 90 : 91 : https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L25 */ 92 : void 93 : fd_sysvar_epoch_rewards_init( fd_exec_slot_ctx_t * slot_ctx, 94 : ulong distributed_rewards, 95 : ulong distribution_starting_block_height, 96 : ulong num_partitions, 97 : ulong total_rewards, 98 : uint128 total_points, 99 0 : fd_hash_t const * last_blockhash ) { 100 0 : fd_sysvar_epoch_rewards_t epoch_rewards = { 101 0 : .distribution_starting_block_height = distribution_starting_block_height, 102 0 : .num_partitions = num_partitions, 103 0 : .total_points = total_points, 104 0 : .total_rewards = total_rewards, 105 0 : .distributed_rewards = distributed_rewards, 106 0 : .active = 1, 107 0 : .parent_blockhash = *last_blockhash 108 0 : }; 109 : 110 0 : if( FD_UNLIKELY( epoch_rewards.total_rewards<distributed_rewards ) ) { 111 0 : FD_LOG_ERR(( "total rewards overflow" )); 112 0 : } 113 : 114 0 : write_epoch_rewards( slot_ctx, &epoch_rewards ); 115 0 : }