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 :
8 0 : #define FD_SYSVAR_CACHE_MAGIC (0x195a0e78828cacd5UL)
9 :
10 : ulong
11 0 : fd_sysvar_cache_align( void ) {
12 0 : return alignof(fd_sysvar_cache_t);
13 0 : }
14 :
15 : ulong
16 0 : fd_sysvar_cache_footprint( void ) {
17 0 : return sizeof(fd_sysvar_cache_t);
18 0 : }
19 :
20 : fd_sysvar_cache_t *
21 0 : fd_sysvar_cache_new( void * mem ) {
22 :
23 0 : if( FD_UNLIKELY( !mem ) ) {
24 0 : FD_LOG_WARNING(( "NULL mem" ));
25 0 : return NULL;
26 0 : }
27 :
28 0 : fd_sysvar_cache_t * cache = (fd_sysvar_cache_t *)mem;
29 0 : fd_memset( cache, 0, sizeof(fd_sysvar_cache_t) );
30 :
31 0 : FD_COMPILER_MFENCE();
32 0 : cache->magic = FD_SYSVAR_CACHE_MAGIC;
33 0 : FD_COMPILER_MFENCE();
34 0 : return cache;
35 0 : }
36 :
37 : void *
38 0 : fd_sysvar_cache_delete( fd_sysvar_cache_t * cache ) {
39 :
40 0 : if( FD_UNLIKELY( !cache ) ) {
41 0 : FD_LOG_WARNING(( "NULL cache" ));
42 0 : return NULL;
43 0 : }
44 :
45 0 : if( FD_UNLIKELY( cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) {
46 0 : FD_LOG_WARNING(( "bad magic" ));
47 0 : return NULL;
48 0 : }
49 :
50 0 : FD_COMPILER_MFENCE();
51 0 : cache->magic = 0UL;
52 0 : FD_COMPILER_MFENCE();
53 :
54 : /* Call destroy on all objects.
55 : This is safe even if these objects logically don't exist
56 : (destroy is safe on zero-initialized values and is idempotent) */
57 0 : # define X( type, name, is_global ) \
58 : //type##_destroy( cache->val_##name );
59 0 : FD_SYSVAR_CACHE_ITER(X)
60 0 : # undef X
61 :
62 0 : return (void *)cache;
63 0 : }
64 :
65 : #define HANDLE_GLOBAL_1(type, name, is_global) \
66 : type##_global_t * \
67 0 : fd_sysvar_cache_##name( fd_sysvar_cache_t const * cache, fd_wksp_t * wksp ) { \
68 0 : if( !cache->has_##name ) { return NULL; } \
69 0 : type##_global_t * val = fd_wksp_laddr_fast( wksp, cache->gaddr_##name ); \
70 0 : return val; \
71 0 : }
72 :
73 : #define HANDLE_GLOBAL_0(type, name, is_global) \
74 : type##_t * \
75 0 : fd_sysvar_cache_##name( fd_sysvar_cache_t const * cache, fd_wksp_t * wksp ) { \
76 0 : if( !cache->has_##name ) { return NULL; } \
77 0 : type##_t * val = fd_wksp_laddr_fast( wksp, cache->gaddr_##name ); \
78 0 : return val; \
79 0 : }
80 :
81 : /* Provide accessor methods */
82 : #define X(type, name, global) \
83 : HANDLE_GLOBAL_##global(type, name, global)
84 :
85 : FD_SYSVAR_CACHE_ITER(X)
86 : #undef X
87 : #undef HANDLE_GLOBAL_1
88 : #undef HANDLE_GLOBAL_0
89 :
90 : /* Restore sysvars */
91 :
92 0 : #define HANDLE_GLOBAL_1( type, mem, decode) type##_decode_global( mem, &decode );
93 0 : #define HANDLE_GLOBAL_0( type, mem, decode) type##_decode( mem, &decode );
94 :
95 : # define X( type, name, is_global ) \
96 : void \
97 : fd_sysvar_cache_restore_##name( \
98 : fd_sysvar_cache_t * cache, \
99 : fd_funk_t * funk, \
100 : fd_funk_txn_t * funk_txn, \
101 : fd_spad_t * runtime_spad, \
102 0 : fd_wksp_t * wksp ) { \
103 0 : do { \
104 0 : fd_pubkey_t const * pubkey = &fd_sysvar_##name##_id; \
105 0 : FD_TXN_ACCOUNT_DECL( account ); \
106 0 : int view_err = fd_txn_account_init_from_funk_readonly( account, \
107 0 : pubkey, \
108 0 : funk, \
109 0 : funk_txn ); \
110 0 : if( view_err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) { break; } \
111 0 : \
112 0 : if( view_err!=FD_ACC_MGR_SUCCESS ) { \
113 0 : char pubkey_cstr[ FD_BASE58_ENCODED_32_SZ ]; \
114 0 : FD_LOG_ERR(( "fd_txn_account_init_from_funk_readonly(%s) failed (%d-%s)", \
115 0 : fd_acct_addr_cstr( pubkey_cstr, pubkey->key ), \
116 0 : view_err, fd_acc_mgr_strerror( view_err ) )); \
117 0 : } \
118 0 : \
119 0 : if( account->vt->get_lamports( account ) == 0UL ) { break; } \
120 0 : \
121 0 : /* Decode new value \
122 0 : type##_decode() does not do heap allocations on failure */ \
123 0 : fd_bincode_decode_ctx_t decode = { \
124 0 : .data = account->vt->get_data( account ), \
125 0 : .dataend = account->vt->get_data( account ) + account->vt->get_data_len( account ) \
126 0 : }; \
127 0 : ulong total_sz = 0UL; \
128 0 : int err = type##_decode_footprint( &decode, &total_sz ); \
129 0 : cache->has_##name = (err==FD_BINCODE_SUCCESS); \
130 0 : if( FD_UNLIKELY( err ) ) break; \
131 0 : type##_t * mem = fd_spad_alloc_check( runtime_spad, type##_align(), total_sz ); \
132 0 : HANDLE_GLOBAL_##is_global( type, mem, decode ) \
133 0 : cache->gaddr_##name = fd_wksp_gaddr_fast( wksp, mem ); \
134 0 : } while(0); \
135 0 : }
136 : FD_SYSVAR_CACHE_ITER(X)
137 : # undef X
138 :
139 : #undef HANDLE_GLOBAL_1
140 : #undef HANDLE_GLOBAL_0
141 :
142 : void
143 : fd_sysvar_cache_restore( fd_sysvar_cache_t * cache,
144 : fd_funk_t * funk,
145 : fd_funk_txn_t * funk_txn,
146 : fd_spad_t * runtime_spad,
147 0 : fd_wksp_t * wksp ) {
148 0 : # define X( type, name, is_global ) \
149 0 : fd_sysvar_cache_restore_##name( cache, funk, funk_txn, runtime_spad, wksp );
150 0 : FD_SYSVAR_CACHE_ITER(X)
151 0 : # undef X
152 0 : }
153 :
154 : void
155 0 : fd_sysvar_cache_invalidate( fd_sysvar_cache_t * cache ) {
156 0 : # define X( type, name, is_global ) \
157 0 : cache->has_##name = 0;
158 0 : FD_SYSVAR_CACHE_ITER(X)
159 0 : # undef X
160 0 : }
161 :
162 : /* Define macros with appropriate parameters */
163 : #define HANDLE_GLOBAL_1(type, name, is_global) \
164 : type##_global_t const * \
165 : fd_sysvar_from_instr_acct_##name( fd_exec_instr_ctx_t const * ctx, \
166 : ulong idx, \
167 0 : int * err ) { \
168 0 : \
169 0 : if( FD_UNLIKELY( idx >= ctx->instr->acct_cnt ) ) { \
170 0 : *err = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \
171 0 : return NULL; \
172 0 : } \
173 0 : \
174 0 : fd_sysvar_cache_t const * cache = ctx->txn_ctx->sysvar_cache; \
175 0 : type##_global_t const * val = fd_sysvar_cache_##name( cache, ctx->txn_ctx->runtime_pub_wksp ); \
176 0 : \
177 0 : ushort idx_in_txn = ctx->instr->accounts[idx].index_in_transaction; \
178 0 : fd_pubkey_t const * addr_have = &ctx->txn_ctx->account_keys[ idx_in_txn ]; \
179 0 : fd_pubkey_t const * addr_want = &fd_sysvar_##name##_id; \
180 0 : if( 0!=memcmp( addr_have, addr_want, sizeof(fd_pubkey_t) ) ) { \
181 0 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG; \
182 0 : return NULL; \
183 0 : } \
184 0 : \
185 0 : *err = val ? \
186 0 : FD_EXECUTOR_INSTR_SUCCESS : \
187 0 : FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; \
188 0 : return val; \
189 0 : }
190 :
191 : #define HANDLE_GLOBAL_0(type, name, is_global) \
192 : type##_t const * \
193 : fd_sysvar_from_instr_acct_##name( fd_exec_instr_ctx_t const * ctx, \
194 : ulong idx, \
195 0 : int * err ) { \
196 0 : \
197 0 : if( FD_UNLIKELY( idx >= ctx->instr->acct_cnt ) ) { \
198 0 : *err = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \
199 0 : return NULL; \
200 0 : } \
201 0 : \
202 0 : fd_sysvar_cache_t const * cache = ctx->txn_ctx->sysvar_cache; \
203 0 : type##_t const * val = fd_sysvar_cache_##name( cache, ctx->txn_ctx->runtime_pub_wksp ); \
204 0 : \
205 0 : ushort idx_in_txn = ctx->instr->accounts[idx].index_in_transaction; \
206 0 : fd_pubkey_t const * addr_have = &ctx->txn_ctx->account_keys[ idx_in_txn ]; \
207 0 : fd_pubkey_t const * addr_want = &fd_sysvar_##name##_id; \
208 0 : if( 0!=memcmp( addr_have, addr_want, sizeof(fd_pubkey_t) ) ) { \
209 0 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG; \
210 0 : return NULL; \
211 0 : } \
212 0 : \
213 0 : *err = val ? \
214 0 : FD_EXECUTOR_INSTR_SUCCESS : \
215 0 : FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; \
216 0 : return val; \
217 0 : }
218 :
219 : /* Define the X macro properly */
220 : #define X(type, name, is_global) \
221 : HANDLE_GLOBAL_##is_global(type, name, is_global)
222 :
223 : /* Apply the X macro to iterate through all entries */
224 : FD_SYSVAR_CACHE_ITER(X)
225 :
226 : /* Clean up macros */
227 : #undef X
228 : #undef HANDLE_GLOBAL_0
229 : #undef HANDLE_GLOBAL_1
230 :
231 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/program-runtime/src/sysvar_cache.rs#L223-L234 */
232 : int
233 : fd_check_sysvar_account( fd_exec_instr_ctx_t const * ctx,
234 : ulong insn_acc_idx,
235 0 : fd_pubkey_t const * expected_id ) {
236 0 : fd_pubkey_t const * txn_accs = ctx->txn_ctx->account_keys;
237 :
238 0 : if( insn_acc_idx>=ctx->instr->acct_cnt ) {
239 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
240 0 : }
241 :
242 0 : ushort idx_in_txn = ctx->instr->accounts[ insn_acc_idx ].index_in_transaction;
243 0 : fd_pubkey_t const * insn_acc_key = &txn_accs[ idx_in_txn ];
244 :
245 0 : if( memcmp( expected_id, insn_acc_key, sizeof(fd_pubkey_t) ) ) {
246 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
247 0 : }
248 0 : return FD_EXECUTOR_INSTR_SUCCESS;
249 0 : }
|