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