Line data Source code
1 : #include "fd_sysvar_slot_history.h" 2 : #include "fd_sysvar.h" 3 : #include "fd_sysvar_rent.h" 4 : #include "../fd_executor_err.h" 5 : #include "../fd_system_ids.h" 6 : #include "../context/fd_exec_epoch_ctx.h" 7 : 8 : /* FIXME These constants should be header defines */ 9 : 10 : static const ulong slot_history_min_account_size = 131097; 11 : 12 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L37 */ 13 : static const ulong slot_history_max_entries = 1024 * 1024; 14 : 15 : /* TODO: move into seperate bitvec library */ 16 : static const ulong bits_per_block = 8 * sizeof(ulong); 17 : 18 : void 19 : fd_sysvar_slot_history_set( fd_slot_history_t * history, 20 0 : ulong i ) { 21 0 : if( FD_UNLIKELY( i > history->next_slot && i - history->next_slot >= slot_history_max_entries ) ) { 22 0 : FD_LOG_WARNING(( "Ignoring out of bounds (i=%lu next_slot=%lu)", i, history->next_slot )); 23 0 : return; 24 0 : } 25 : 26 : // Skipped slots, delete them from history 27 0 : for( ulong j = history->next_slot; j < i; j++ ) { 28 0 : ulong block_idx = (j / bits_per_block) % (history->bits.bits->blocks_len); 29 0 : history->bits.bits->blocks[ block_idx ] &= ~( 1UL << ( j % bits_per_block ) ); 30 0 : } 31 0 : ulong block_idx = (i / bits_per_block) % (history->bits.bits->blocks_len); 32 0 : history->bits.bits->blocks[ block_idx ] |= ( 1UL << ( i % bits_per_block ) ); 33 0 : } 34 : 35 : static const ulong blocks_len = slot_history_max_entries / bits_per_block; 36 : 37 : int fd_sysvar_slot_history_write_history( fd_exec_slot_ctx_t * slot_ctx, 38 0 : fd_slot_history_t * history ) { 39 0 : ulong sz = fd_slot_history_size( history ); 40 0 : if (sz < slot_history_min_account_size) 41 0 : sz = slot_history_min_account_size; 42 0 : uchar enc[ sz ]; 43 0 : fd_memset( enc, 0, sz ); 44 0 : fd_bincode_encode_ctx_t ctx; 45 0 : ctx.data = enc; 46 0 : ctx.dataend = enc + sz; 47 0 : int err = fd_slot_history_encode( history, &ctx ); 48 0 : if (0 != err) 49 0 : return err; 50 0 : return fd_sysvar_set( slot_ctx, fd_sysvar_owner_id.key, &fd_sysvar_slot_history_id, enc, sz, slot_ctx->slot_bank.slot ); 51 0 : } 52 : 53 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L16 */ 54 : void 55 0 : fd_sysvar_slot_history_init( fd_exec_slot_ctx_t * slot_ctx ) { 56 : /* Create a new slot history instance */ 57 0 : fd_slot_history_t history = {0}; 58 0 : fd_slot_history_inner_t * inner = fd_valloc_malloc( slot_ctx->valloc, 8UL, sizeof(fd_slot_history_inner_t) ); 59 0 : inner->blocks = fd_valloc_malloc( slot_ctx->valloc, 8UL, sizeof(ulong) * blocks_len ); 60 0 : memset( inner->blocks, 0, sizeof(ulong) * blocks_len ); 61 0 : inner->blocks_len = blocks_len; 62 0 : history.bits.bits = inner; 63 0 : history.bits.len = slot_history_max_entries; 64 : 65 : /* TODO: handle slot != 0 init case */ 66 0 : fd_sysvar_slot_history_set( &history, slot_ctx->slot_bank.slot ); 67 0 : history.next_slot = slot_ctx->slot_bank.slot + 1; 68 : 69 0 : fd_sysvar_slot_history_write_history( slot_ctx, &history ); 70 0 : fd_bincode_destroy_ctx_t ctx = { .valloc = slot_ctx->valloc }; 71 0 : fd_slot_history_destroy( &history, &ctx ); 72 0 : } 73 : 74 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2345 */ 75 : int 76 0 : fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx ) { 77 : /* Set current_slot, and update next_slot */ 78 : 79 0 : fd_pubkey_t const * key = &fd_sysvar_slot_history_id; 80 : 81 0 : FD_BORROWED_ACCOUNT_DECL(rec); 82 0 : int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, rec); 83 0 : if (err) 84 0 : FD_LOG_CRIT(( "fd_acc_mgr_view(slot_history) failed: %d", err )); 85 : 86 0 : fd_bincode_decode_ctx_t ctx; 87 0 : ctx.data = rec->const_data; 88 0 : ctx.dataend = rec->const_data + rec->const_meta->dlen; 89 0 : ctx.valloc = slot_ctx->valloc; 90 0 : fd_slot_history_t history[1]; 91 0 : if( fd_slot_history_decode( history, &ctx ) ) 92 0 : FD_LOG_ERR(("fd_slot_history_decode failed")); 93 : 94 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L48 */ 95 0 : fd_sysvar_slot_history_set( history, slot_ctx->slot_bank.slot ); 96 0 : history->next_slot = slot_ctx->slot_bank.slot + 1; 97 : 98 0 : ulong sz = fd_slot_history_size( history ); 99 0 : if( sz < slot_history_min_account_size ) 100 0 : sz = slot_history_min_account_size; 101 : 102 0 : err = fd_acc_mgr_modify( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, 1, sz, rec ); 103 0 : if (err) 104 0 : FD_LOG_CRIT(( "fd_acc_mgr_modify(slot_history) failed: %d", err )); 105 : 106 0 : fd_bincode_encode_ctx_t e_ctx = { 107 0 : .data = rec->data, 108 0 : .dataend = rec->data+sz 109 0 : }; 110 0 : if( fd_slot_history_encode( history, &e_ctx ) ) 111 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; 112 : 113 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); 114 0 : rec->meta->info.lamports = fd_rent_exempt_minimum_balance( &epoch_bank->rent, sz ); 115 : 116 0 : rec->meta->dlen = sz; 117 0 : fd_memcpy( rec->meta->info.owner, fd_sysvar_owner_id.key, sizeof(fd_pubkey_t) ); 118 : 119 0 : fd_bincode_destroy_ctx_t ctx_d = { .valloc = slot_ctx->valloc }; 120 0 : fd_slot_history_destroy( history, &ctx_d ); 121 : 122 0 : return 0; 123 0 : } 124 : 125 : int 126 : fd_sysvar_slot_history_read( fd_exec_slot_ctx_t * slot_ctx, 127 : fd_valloc_t valloc, 128 0 : fd_slot_history_t * out_history) { 129 : /* Set current_slot, and update next_slot */ 130 : 131 0 : fd_pubkey_t const * key = &fd_sysvar_slot_history_id; 132 : 133 0 : FD_BORROWED_ACCOUNT_DECL(rec); 134 0 : int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, rec); 135 0 : if (err) 136 0 : FD_LOG_CRIT(( "fd_acc_mgr_view(slot_history) failed: %d", err )); 137 : 138 0 : fd_bincode_decode_ctx_t ctx; 139 0 : ctx.data = rec->const_data; 140 0 : ctx.dataend = rec->const_data + rec->const_meta->dlen; 141 0 : ctx.valloc = valloc; 142 0 : if( fd_slot_history_decode( out_history, &ctx ) ) 143 0 : FD_LOG_ERR(("fd_slot_history_decode failed")); 144 : 145 0 : return 0; 146 0 : } 147 : 148 : int 149 : fd_sysvar_slot_history_find_slot( fd_slot_history_t const * history, 150 0 : ulong slot ) { 151 0 : if( slot > history->next_slot - 1) { 152 0 : return FD_SLOT_HISTORY_SLOT_FUTURE; 153 0 : } else if ( slot < fd_ulong_sat_sub( history->next_slot, slot_history_max_entries ) ) { 154 0 : return FD_SLOT_HISTORY_SLOT_TOO_OLD; 155 0 : } else { 156 0 : ulong block_idx = (slot / bits_per_block) % (history->bits.bits->blocks_len); 157 0 : if( history->bits.bits->blocks[ block_idx ] & ( 1UL << ( slot % bits_per_block ) ) ) { 158 0 : return FD_SLOT_HISTORY_SLOT_FOUND; 159 0 : } else { 160 0 : return FD_SLOT_HISTORY_SLOT_NOTFOUND; 161 0 : } 162 0 : } 163 0 : }