Line data Source code
1 : #include "fd_sysvar_stake_history.h" 2 : #include "fd_sysvar.h" 3 : #include "../fd_system_ids.h" 4 : #include "../fd_txn_account.h" 5 : #include "../fd_acc_mgr.h" 6 : #include "../context/fd_exec_slot_ctx.h" 7 : 8 : /* Ensure that the size declared by our header matches the minimum size 9 : of the corresponding fd_types entry. */ 10 : 11 : static void 12 : write_stake_history( fd_exec_slot_ctx_t * slot_ctx, 13 9 : fd_stake_history_t * stake_history ) { 14 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/sysvar/stake_history.rs#L12 */ 15 9 : uchar enc[16392] = {0}; 16 : 17 9 : fd_bincode_encode_ctx_t encode = 18 9 : { .data = enc, 19 9 : .dataend = enc + sizeof(enc) }; 20 9 : if( FD_UNLIKELY( fd_stake_history_encode( stake_history, &encode )!=FD_BINCODE_SUCCESS ) ) 21 0 : FD_LOG_ERR(("fd_stake_history_encode failed")); 22 : 23 9 : fd_sysvar_account_update( slot_ctx, &fd_sysvar_stake_history_id, enc, sizeof(enc) ); 24 9 : } 25 : 26 : fd_stake_history_t * 27 : fd_sysvar_stake_history_read( fd_funk_t * funk, 28 : fd_funk_txn_t * funk_txn, 29 6 : fd_spad_t * spad ) { 30 6 : FD_TXN_ACCOUNT_DECL( stake_rec ); 31 6 : int err = fd_txn_account_init_from_funk_readonly( stake_rec, &fd_sysvar_stake_history_id, funk, funk_txn ); 32 6 : if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) { 33 0 : return NULL; 34 0 : } 35 : 36 : /* This check is needed as a quirk of the fuzzer. If a sysvar account 37 : exists in the accounts database, but doesn't have any lamports, 38 : this means that the account does not exist. This wouldn't happen 39 : in a real execution environment. */ 40 6 : if( FD_UNLIKELY( stake_rec->vt->get_lamports( stake_rec )==0 ) ) { 41 0 : return NULL; 42 0 : } 43 : 44 6 : return fd_bincode_decode_spad( 45 6 : stake_history, spad, 46 6 : stake_rec->vt->get_data( stake_rec ), 47 6 : stake_rec->vt->get_data_len( stake_rec ), 48 6 : &err ); 49 6 : } 50 : 51 : void 52 3 : fd_sysvar_stake_history_init( fd_exec_slot_ctx_t * slot_ctx ) { 53 3 : fd_stake_history_t stake_history; 54 3 : fd_stake_history_new( &stake_history ); 55 3 : write_stake_history( slot_ctx, &stake_history ); 56 3 : } 57 : 58 : void 59 : fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, 60 : fd_epoch_stake_history_entry_pair_t const * pair, 61 6 : fd_spad_t * runtime_spad ) { 62 6 : FD_SPAD_FRAME_BEGIN( runtime_spad ) { 63 : 64 : // Need to make this maybe zero copies of map... 65 6 : fd_stake_history_t * stake_history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); 66 : 67 6 : if( stake_history->fd_stake_history_offset == 0 ) { 68 6 : stake_history->fd_stake_history_offset = stake_history->fd_stake_history_size - 1; 69 6 : } else { 70 0 : stake_history->fd_stake_history_offset--; 71 0 : } 72 : 73 6 : if( stake_history->fd_stake_history_len < stake_history->fd_stake_history_size ) { 74 6 : stake_history->fd_stake_history_len++; 75 6 : } 76 : 77 : // This should be done with a bit mask 78 6 : ulong idx = stake_history->fd_stake_history_offset; 79 : 80 6 : stake_history->fd_stake_history[ idx ].epoch = pair->epoch; 81 6 : stake_history->fd_stake_history[ idx ].entry.activating = pair->entry.activating; 82 6 : stake_history->fd_stake_history[ idx ].entry.effective = pair->entry.effective; 83 6 : stake_history->fd_stake_history[ idx ].entry.deactivating = pair->entry.deactivating; 84 : 85 6 : write_stake_history( slot_ctx, stake_history ); 86 : 87 6 : } FD_SPAD_FRAME_END; 88 6 : }