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