Line data Source code
1 : #include "fd_sysvar_cache.h" 2 : #include "../fd_acc_mgr.h" 3 : #include "../fd_executor.h" 4 : #include "../fd_system_ids.h" 5 : #include "../context/fd_exec_instr_ctx.h" 6 : #include "../context/fd_exec_txn_ctx.h" 7 : #include "../context/fd_exec_slot_ctx.h" 8 : 9 108786 : #define FD_SYSVAR_CACHE_MAGIC (0x195a0e78828cacd5UL) 10 : 11 : ulong 12 108786 : fd_sysvar_cache_align( void ) { 13 108786 : return alignof(fd_sysvar_cache_t); 14 108786 : } 15 : 16 : ulong 17 108786 : fd_sysvar_cache_footprint( void ) { 18 108786 : return sizeof(fd_sysvar_cache_t); 19 108786 : } 20 : 21 : fd_sysvar_cache_t * 22 : fd_sysvar_cache_new( void * mem, 23 108786 : fd_valloc_t valloc ) { 24 : 25 108786 : if( FD_UNLIKELY( !mem ) ) { 26 0 : FD_LOG_WARNING(( "NULL mem" )); 27 0 : return NULL; 28 0 : } 29 : 30 108786 : fd_sysvar_cache_t * cache = (fd_sysvar_cache_t *)mem; 31 108786 : fd_memset( cache, 0, sizeof(fd_sysvar_cache_t) ); 32 : 33 108786 : cache->valloc = valloc; 34 : 35 108786 : FD_COMPILER_MFENCE(); 36 108786 : cache->magic = FD_SYSVAR_CACHE_MAGIC; 37 108786 : FD_COMPILER_MFENCE(); 38 108786 : return cache; 39 108786 : } 40 : 41 : void * 42 108786 : fd_sysvar_cache_delete( fd_sysvar_cache_t * cache ) { 43 : 44 108786 : if( FD_UNLIKELY( !cache ) ) { 45 0 : FD_LOG_WARNING(( "NULL cache" )); 46 0 : return NULL; 47 0 : } 48 : 49 108786 : if( FD_UNLIKELY( cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) { 50 0 : FD_LOG_WARNING(( "bad magic" )); 51 0 : return NULL; 52 0 : } 53 : 54 108786 : if( FD_UNLIKELY( !cache->valloc.vt ) ) { 55 0 : FD_LOG_WARNING(( "NULL alloc" )); 56 0 : return NULL; 57 0 : } 58 : 59 108786 : FD_COMPILER_MFENCE(); 60 108786 : cache->magic = 0UL; 61 108786 : FD_COMPILER_MFENCE(); 62 : 63 108786 : fd_bincode_destroy_ctx_t ctx = { .valloc = cache->valloc }; 64 : 65 : /* Call destroy on all objects. 66 : This is safe even if these objects logically don't exist 67 : (destory is safe on zero-initialized values and is idempotent) */ 68 108786 : # define X( type, name ) \ 69 979074 : type##_destroy( cache->val_##name, &ctx ); 70 979074 : FD_SYSVAR_CACHE_ITER(X) 71 108786 : # undef X 72 : 73 108786 : return (void *)cache; 74 108786 : } 75 : 76 : /* Provide accessor methods */ 77 : 78 : #define X( type, name ) \ 79 : type##_t const * \ 80 408984 : fd_sysvar_cache_##name( fd_sysvar_cache_t const * cache ) { \ 81 408984 : type##_t const * val = cache->val_##name; \ 82 408984 : return (cache->has_##name) ? val : NULL; \ 83 408984 : } 84 : FD_SYSVAR_CACHE_ITER(X) 85 : #undef X 86 : 87 : /* Restore sysvars */ 88 : 89 : # define X( type, name ) \ 90 : void \ 91 : fd_sysvar_cache_restore_##name( \ 92 : fd_sysvar_cache_t * cache, \ 93 : fd_acc_mgr_t * acc_mgr, \ 94 1081404 : fd_funk_txn_t * funk_txn) { \ 95 1081404 : do { \ 96 1081404 : fd_pubkey_t const * pubkey = &fd_sysvar_##name##_id; \ 97 1081404 : FD_BORROWED_ACCOUNT_DECL( account ); \ 98 1081404 : int view_err = fd_acc_mgr_view( acc_mgr, funk_txn, pubkey, account ); \ 99 1081404 : if( view_err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) break; \ 100 1081404 : \ 101 1081404 : if( view_err!=FD_ACC_MGR_SUCCESS ) { \ 102 0 : char pubkey_cstr[ FD_BASE58_ENCODED_32_SZ ]; \ 103 0 : FD_LOG_ERR(( "fd_acc_mgr_view(%s) failed (%d-%s)", \ 104 0 : fd_acct_addr_cstr( pubkey_cstr, pubkey->key ), \ 105 0 : view_err, fd_acc_mgr_strerror( view_err ) )); \ 106 0 : } \ 107 188892 : \ 108 188892 : if( account->const_meta->info.lamports == 0UL ) break; \ 109 188892 : \ 110 188892 : /* Destroy previous value */ \ 111 188892 : \ 112 188892 : fd_bincode_destroy_ctx_t destroy = { .valloc = cache->valloc }; \ 113 187620 : type##_destroy( cache->val_##name, &destroy ); \ 114 187620 : \ 115 187620 : /* Decode new value \ 116 187620 : type##_decode() does not do heap allocations on failure */ \ 117 187620 : \ 118 187620 : fd_bincode_decode_ctx_t decode = \ 119 187620 : { .data = account->const_data, \ 120 187620 : .dataend = account->const_data + account->const_meta->dlen, \ 121 187620 : .valloc = cache->valloc }; \ 122 187620 : int err = type##_decode( cache->val_##name, &decode ); \ 123 187620 : cache->has_##name = (err==FD_BINCODE_SUCCESS); \ 124 187620 : } while(0); \ 125 1081404 : } 126 : FD_SYSVAR_CACHE_ITER(X) 127 : # undef X 128 : 129 : void 130 : fd_sysvar_cache_restore( fd_sysvar_cache_t * cache, 131 : fd_acc_mgr_t * acc_mgr, 132 120156 : fd_funk_txn_t * funk_txn ) { 133 1081404 : # define X( type, name ) \ 134 1081404 : fd_sysvar_cache_restore_##name( cache, acc_mgr, funk_txn ); 135 1081404 : FD_SYSVAR_CACHE_ITER(X) 136 120156 : # undef X 137 120156 : } 138 : 139 : # define X( type, name ) \ 140 : type##_t const * \ 141 : fd_sysvar_from_instr_acct_##name( fd_exec_instr_ctx_t const * ctx, \ 142 : ulong idx, \ 143 15237 : int * err ) {\ 144 15237 : \ 145 15237 : if( FD_UNLIKELY( idx >= ctx->instr->acct_cnt ) ) { \ 146 45 : *err = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \ 147 45 : return NULL; \ 148 45 : } \ 149 15237 : \ 150 15237 : fd_sysvar_cache_t const * cache = ctx->slot_ctx->sysvar_cache; \ 151 15192 : type##_t const * val = fd_sysvar_cache_##name ( cache ); \ 152 15192 : \ 153 15192 : fd_pubkey_t const * addr_have = &ctx->instr->acct_pubkeys[idx]; \ 154 15192 : fd_pubkey_t const * addr_want = &fd_sysvar_##name##_id; \ 155 15192 : if( 0!=memcmp( addr_have, addr_want, sizeof(fd_pubkey_t) ) ) { \ 156 1170 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG; \ 157 1170 : return NULL; \ 158 1170 : } \ 159 15192 : \ 160 15192 : *err = val ? \ 161 14022 : FD_EXECUTOR_INSTR_SUCCESS : \ 162 14022 : FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; \ 163 14022 : return val; \ 164 15192 : \ 165 15192 : } 166 : FD_SYSVAR_CACHE_ITER(X) 167 : # undef X 168 : 169 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/program-runtime/src/sysvar_cache.rs#L223-L234 */ 170 : int 171 : fd_check_sysvar_account( fd_exec_instr_ctx_t const * ctx, 172 : ulong insn_acc_idx, 173 1740 : fd_pubkey_t const * expected_id ) { 174 1740 : uchar const * instr_acc_idxs = ctx->instr->acct_txn_idxs; 175 1740 : fd_pubkey_t const * txn_accs = ctx->txn_ctx->accounts; 176 : 177 1740 : if( insn_acc_idx>=ctx->instr->acct_cnt ) { 178 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; 179 0 : } 180 : 181 1740 : fd_pubkey_t const * insn_acc_key = &txn_accs[ instr_acc_idxs[ insn_acc_idx ] ]; 182 : 183 1740 : if( memcmp( expected_id, insn_acc_key, sizeof(fd_pubkey_t) ) ) { 184 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG; 185 0 : } 186 1740 : return FD_EXECUTOR_INSTR_SUCCESS; 187 1740 : }