Line data Source code
1 :
2 : #include "fd_bank_abi.h"
3 : #include "../../flamenco/runtime/fd_system_ids_pp.h"
4 : #include "../../flamenco/runtime/fd_system_ids.h"
5 : #include "../../flamenco/types/fd_types.h"
6 :
7 : #define ABI_ALIGN( x ) __attribute__((packed)) __attribute__((aligned(x)))
8 :
9 : #define MAP_PERFECT_NAME fd_bank_abi_builtin_keys_and_sysvars_tbl
10 : #define MAP_PERFECT_LG_TBL_SZ 5
11 : #define MAP_PERFECT_T fd_acct_addr_t
12 0 : #define MAP_PERFECT_HASH_C 1402126759U
13 : #define MAP_PERFECT_KEY b
14 : #define MAP_PERFECT_KEY_T fd_acct_addr_t const *
15 : #define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
16 : #define MAP_PERFECT_COMPLEX_KEY 1
17 0 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
18 :
19 0 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>27)&0x1FU)
20 :
21 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
22 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
23 : PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
24 0 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
25 :
26 : /* This list is exactly what Lab's is_builtin_key_or_sysvar checks. */
27 : /* Sysvars */
28 : #define MAP_PERFECT_0 ( SYSVAR_CLOCK_ID ),
29 : #define MAP_PERFECT_1 ( SYSVAR_EPOCH_SCHED_ID ),
30 : #define MAP_PERFECT_2 ( SYSVAR_FEES_ID ),
31 : #define MAP_PERFECT_3 ( SYSVAR_RECENT_BLKHASH_ID ),
32 : #define MAP_PERFECT_4 ( SYSVAR_RENT_ID ),
33 : #define MAP_PERFECT_5 ( SYSVAR_REWARDS_ID ),
34 : #define MAP_PERFECT_6 ( SYSVAR_SLOT_HASHES_ID ),
35 : #define MAP_PERFECT_7 ( SYSVAR_SLOT_HIST_ID ),
36 : #define MAP_PERFECT_8 ( SYSVAR_STAKE_HIST_ID ),
37 : #define MAP_PERFECT_9 ( SYSVAR_INSTRUCTIONS_ID ),
38 : #define MAP_PERFECT_10 ( SYSVAR_EPOCH_REWARDS_ID ),
39 : #define MAP_PERFECT_11 ( SYSVAR_LAST_RESTART_ID ),
40 : /* Programs */
41 : #define MAP_PERFECT_12 ( CONFIG_PROG_ID ),
42 : #define MAP_PERFECT_13 ( FEATURE_ID ),
43 : #define MAP_PERFECT_14 ( NATIVE_LOADER_ID ),
44 : #define MAP_PERFECT_15 ( STAKE_PROG_ID ),
45 : #define MAP_PERFECT_16 ( STAKE_CONFIG_PROG_ID ),
46 : #define MAP_PERFECT_17 ( VOTE_PROG_ID ),
47 : #define MAP_PERFECT_18 ( SYS_PROG_ID ),
48 : #define MAP_PERFECT_19 ( BPF_LOADER_1_PROG_ID ),
49 : #define MAP_PERFECT_20 ( BPF_LOADER_2_PROG_ID ),
50 : #define MAP_PERFECT_21 ( BPF_UPGRADEABLE_PROG_ID ),
51 :
52 : #include "../../util/tmpl/fd_map_perfect.c"
53 :
54 : typedef struct ABI_ALIGN(1UL) {
55 : uchar key[ 32UL ];
56 : } sanitized_txn_abi_pubkey_t;
57 :
58 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_pubkey_t) == 32UL, "messed up size" );
59 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_pubkey_t) == 1UL, "messed up size" );
60 :
61 : typedef struct ABI_ALIGN(1UL) {
62 : uchar signature[ 64UL ];
63 : } sanitized_txn_abi_signature_t;
64 :
65 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_signature_t) == 64UL, "messed up size" );
66 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_signature_t) == 1UL, "messed up size" );
67 :
68 : typedef struct ABI_ALIGN(8UL) {
69 : ulong accounts_cap;
70 : uchar * accounts;
71 : ulong accounts_cnt;
72 :
73 : ulong data_cap;
74 : uchar * data;
75 : ulong data_cnt;
76 :
77 : uchar program_id_index;
78 : } sanitized_txn_abi_compiled_instruction_t;
79 :
80 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_compiled_instruction_t) == 56UL, "messed up size" );
81 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_compiled_instruction_t) == 8UL, "messed up size" );
82 :
83 : typedef struct ABI_ALIGN(1UL) {
84 : uchar num_required_signatures;
85 : uchar num_readonly_signed_accounts;
86 : uchar num_readonly_unsigned_accounts;
87 : } sanitized_txn_abi_message_header_t;
88 :
89 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_message_header_t) == 3UL, "messed up size" );
90 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_header_t) == 1UL, "messed up size" );
91 :
92 : typedef struct ABI_ALIGN(8UL) {
93 : ulong account_keys_cap;
94 : sanitized_txn_abi_pubkey_t * account_keys;
95 : ulong account_keys_cnt;
96 :
97 : ulong instructions_cap;
98 : sanitized_txn_abi_compiled_instruction_t * instructions;
99 : ulong instructions_cnt;
100 :
101 : uchar recent_blockhash[ 32 ];
102 :
103 : sanitized_txn_abi_message_header_t header;
104 : } sanitized_txn_abi_legacy_message0_t;
105 :
106 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message0_t) == 88UL, "messed up size" );
107 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message0_t) == 8UL, "messed up size" );
108 :
109 : typedef struct ABI_ALIGN(8UL) {
110 : ulong is_writable_account_cache_cap;
111 : uchar * is_writable_account_cache;
112 : ulong is_writable_account_cache_cnt;
113 :
114 : union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
115 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
116 : ulong tag; /* Niche tag encoding. Value 0 is borrowed, nonzero is owned. */
117 : sanitized_txn_abi_legacy_message0_t * borrowed;
118 : };
119 :
120 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
121 : sanitized_txn_abi_legacy_message0_t owned;
122 : };
123 : } message;
124 : } sanitized_txn_abi_legacy_message1_t;
125 :
126 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message1_t) == 112UL, "messed up size" );
127 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message1_t) == 8UL, "messed up size" );
128 :
129 : typedef struct ABI_ALIGN(8UL) {
130 : ulong writable_indexes_cap;
131 : uchar * writable_indexes;
132 : ulong writable_indexes_cnt;
133 :
134 : ulong readonly_indexes_cap;
135 : uchar * readonly_indexes;
136 : ulong readonly_indexes_cnt;
137 :
138 : uchar account_key[ 32 ];
139 : } sanitized_txn_abi_v0_message_address_table_lookup_t;
140 :
141 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 80UL, "messed up size" );
142 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 8UL, "messed up size" );
143 :
144 : typedef struct ABI_ALIGN(8UL) {
145 : ulong account_keys_cap;
146 : sanitized_txn_abi_pubkey_t * account_keys;
147 : ulong account_keys_cnt;
148 :
149 : ulong instructions_cap;
150 : sanitized_txn_abi_compiled_instruction_t * instructions;
151 : ulong instructions_cnt;
152 :
153 : ulong address_table_lookups_cap;
154 : sanitized_txn_abi_v0_message_address_table_lookup_t * address_table_lookups;
155 : ulong address_table_lookups_cnt;
156 :
157 : uchar recent_blockhash[ 32 ];
158 :
159 : sanitized_txn_abi_message_header_t header;
160 : } sanitized_txn_abi_v0_message_t;
161 :
162 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_t) == 112UL, "messed up size" );
163 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_t) == 8UL, "messed up size" );
164 :
165 : typedef struct ABI_ALIGN(8UL) {
166 : ulong writable_cap;
167 : sanitized_txn_abi_pubkey_t * writable;
168 : ulong writable_cnt;
169 :
170 : ulong readable_cap;
171 : sanitized_txn_abi_pubkey_t * readable;
172 : ulong readable_cnt;
173 : } sanitized_txn_abi_v0_loaded_addresses_t;
174 :
175 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_addresses_t) == 48UL, "messed up size" );
176 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_addresses_t) == 8UL, "messed up size" );
177 :
178 : typedef struct ABI_ALIGN(8UL) {
179 : ulong is_writable_account_cache_cap;
180 : uchar * is_writable_account_cache;
181 : ulong is_writable_account_cache_cnt;
182 :
183 : union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
184 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
185 : ulong tag; /* Niche tag encoding. Value 0 is borrowed, nonzero is owned. */
186 : sanitized_txn_abi_v0_message_t * borrowed;
187 : };
188 :
189 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
190 : sanitized_txn_abi_v0_message_t owned;
191 : };
192 : } message;
193 :
194 : union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
195 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
196 : ulong tag; /* Niche tag encoding. Value 0 is borrowed, nonzero is owned. */
197 : sanitized_txn_abi_v0_loaded_addresses_t * borrowed;
198 : };
199 :
200 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
201 : sanitized_txn_abi_v0_loaded_addresses_t owned;
202 : };
203 : } loaded_addresses;
204 : } sanitized_txn_abi_v0_loaded_msg_t;
205 :
206 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_msg_t) == 184UL, "messed up size" );
207 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_msg_t) == 8UL, "messed up size" );
208 :
209 : typedef union ABI_ALIGN(8UL) {
210 : struct ABI_ALIGN(8UL) {
211 : ulong tag; /* Niche tag encoding. Value 0 is legacy, nonzero is v0. */
212 : sanitized_txn_abi_legacy_message1_t legacy;
213 : };
214 :
215 : sanitized_txn_abi_v0_loaded_msg_t v0; /* No tag. First field is always non-NULL, so rustc can disciminate from legacy. */
216 : } sanitized_txn_abi_message_t;
217 :
218 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_message_t) == 184UL, "messed up size" );
219 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_t) == 8UL, "messed up size" );
220 :
221 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_message_t, v0) == 0UL, "messed up size" );
222 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_message_t, legacy) == 8UL, "messed up size" );
223 :
224 : struct ABI_ALIGN(8UL) fd_bank_abi_txn_private {
225 : ulong signatures_cap;
226 : sanitized_txn_abi_signature_t * signatures;
227 : ulong signatures_cnt;
228 :
229 : sanitized_txn_abi_message_t message;
230 :
231 : uchar message_hash[ 32 ];
232 : uchar is_simple_vote_tx;
233 : };
234 :
235 : FD_STATIC_ASSERT( sizeof(struct fd_bank_abi_txn_private) == 248UL, "messed up size" );
236 : FD_STATIC_ASSERT( alignof(struct fd_bank_abi_txn_private) == 8UL, "messed up size" );
237 :
238 : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, signatures) == 8UL, "messed up size" );
239 : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, message) == 24UL, "messed up size" );
240 : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, message_hash) == 208UL, "messed up size" );
241 : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, is_simple_vote_tx) == 240UL, "messed up size" );
242 :
243 : static int
244 : is_key_called_as_program( fd_txn_t const * txn,
245 0 : ushort key_index ) {
246 0 : for( ushort i=0; i<txn->instr_cnt; i++ ) {
247 0 : fd_txn_instr_t const * instr = &txn->instr[ i ];
248 0 : if( FD_UNLIKELY( instr->program_id==key_index ) ) return 1;
249 0 : }
250 0 : return 0;
251 0 : }
252 :
253 : static const uchar BPF_UPGRADEABLE_PROG_ID1[32] = { BPF_UPGRADEABLE_PROG_ID };
254 :
255 : static int
256 : is_upgradeable_loader_present( fd_txn_t const * txn,
257 : uchar const * payload,
258 0 : sanitized_txn_abi_pubkey_t const * loaded_addresses ) {
259 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
260 0 : if( FD_UNLIKELY( !memcmp( payload + txn->acct_addr_off + i*32UL, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
261 0 : }
262 0 : for( ushort i=0; i<txn->addr_table_adtl_cnt; i++ ) {
263 0 : if( FD_UNLIKELY( !memcmp( loaded_addresses + i, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
264 0 : }
265 0 : return 0;
266 0 : }
267 :
268 : extern int
269 : fd_ext_bank_load_account( void const * bank,
270 : int fixed_root,
271 : uchar const * addr,
272 : uchar * owner,
273 : uchar * data,
274 : ulong * data_sz );
275 :
276 : int
277 : fd_bank_abi_resolve_address_lookup_tables( void const * bank,
278 : int fixed_root,
279 : ulong slot,
280 : fd_txn_t const * txn,
281 : uchar const * payload,
282 0 : fd_acct_addr_t * out_lut_accts ) {
283 0 : ulong writable_idx = 0UL;
284 0 : ulong readable_idx = 0UL;
285 0 : for( ulong i=0UL; i<txn->addr_table_lookup_cnt; i++ ) {
286 0 : fd_txn_acct_addr_lut_t const * lut = &fd_txn_get_address_tables_const( txn )[ i ];
287 0 : uchar const * addr = payload + lut->addr_off;
288 :
289 0 : uchar owner[ 32UL ];
290 0 : uchar data[ 1UL+56UL+256UL*32UL ];
291 0 : ulong data_sz = sizeof(data);
292 0 : int result = fd_ext_bank_load_account( bank, fixed_root, addr, owner, data, &data_sz );
293 0 : if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
294 :
295 0 : result = memcmp( owner, fd_solana_address_lookup_table_program_id.key, 32UL );
296 0 : if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_OWNER;
297 :
298 0 : if( FD_UNLIKELY( (data_sz<56UL) | (data_sz>(56UL+256UL*32UL)) ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
299 :
300 0 : fd_address_lookup_table_state_t table[1];
301 0 : fd_bincode_decode_ctx_t bincode = {
302 0 : .data = data,
303 0 : .dataend = data+data_sz,
304 0 : .valloc = {0},
305 0 : };
306 :
307 0 : result = fd_address_lookup_table_state_decode( table, &bincode );
308 0 : if( FD_UNLIKELY( result!=FD_BINCODE_SUCCESS ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
309 :
310 0 : result = fd_address_lookup_table_state_is_lookup_table( table );
311 0 : if( FD_UNLIKELY( !result ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_UNINITIALIZED;
312 :
313 0 : if( FD_UNLIKELY( (data_sz-56UL)%32UL ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
314 :
315 0 : ulong addresses_len = (data_sz-56UL)/32UL;
316 0 : fd_acct_addr_t const * addresses = fd_type_pun_const( data+56UL );
317 :
318 : /* This logic is not currently very precise... an ALUT is allowed if
319 : the deactivation slot is no longer present in the slot hashes
320 : sysvar, which means that the slot was more than 512 *unskipped*
321 : slots prior. In the current case, we are just throwing out a
322 : fraction of transactions that could actually still be valid
323 : (those deactivated between 512 and 512*(1+skip_rate) slots ago. */
324 :
325 0 : ulong deactivation_slot = table->inner.lookup_table.meta.deactivation_slot;
326 0 : if( FD_UNLIKELY( deactivation_slot!=ULONG_MAX && (deactivation_slot+512UL)<slot ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
327 :
328 0 : ulong active_addresses_len = fd_ulong_if( slot>table->inner.lookup_table.meta.last_extended_slot,
329 0 : addresses_len,
330 0 : table->inner.lookup_table.meta.last_extended_slot_start_index );
331 0 : for( ulong j=0UL; j<lut->writable_cnt; j++ ) {
332 0 : uchar idx = payload[ lut->writable_off+j ];
333 0 : if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
334 0 : memcpy( &out_lut_accts[ writable_idx++ ], addresses+idx, sizeof(fd_acct_addr_t) );
335 0 : }
336 0 : for( ulong j=0UL; j<lut->readonly_cnt; j++ ) {
337 0 : uchar idx = payload[ lut->readonly_off+j ];
338 0 : if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
339 0 : memcpy( &out_lut_accts[ txn->addr_table_adtl_writable_cnt+readable_idx++ ], addresses+idx, sizeof(fd_acct_addr_t) );
340 0 : }
341 0 : }
342 :
343 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
344 0 : }
345 :
346 : int
347 : fd_bank_abi_txn_init( fd_bank_abi_txn_t * out_txn,
348 : uchar * out_sidecar,
349 : void const * bank,
350 : ulong slot,
351 : fd_blake3_t * blake3,
352 : uchar * payload,
353 : ulong payload_sz,
354 : fd_txn_t * txn,
355 0 : int is_simple_vote ) {
356 0 : out_txn->signatures_cnt = txn->signature_cnt;
357 0 : out_txn->signatures_cap = txn->signature_cnt;
358 0 : out_txn->signatures = (void*)(payload + txn->signature_off);
359 :
360 0 : fd_blake3_init( blake3 );
361 0 : fd_blake3_append( blake3, "solana-tx-message-v1", 20UL );
362 0 : fd_blake3_append( blake3, payload + txn->message_off, payload_sz - txn->message_off );
363 0 : fd_blake3_fini( blake3, out_txn->message_hash );
364 :
365 0 : out_txn->is_simple_vote_tx = !!is_simple_vote;
366 :
367 0 : if( FD_LIKELY( txn->transaction_version==FD_TXN_VLEGACY ) ) {
368 0 : sanitized_txn_abi_legacy_message1_t * legacy = &out_txn->message.legacy;
369 0 : sanitized_txn_abi_legacy_message0_t * message = &legacy->message.owned;
370 :
371 0 : out_txn->message.tag = 9223372036854775808UL;
372 :
373 0 : legacy->is_writable_account_cache_cnt = txn->acct_addr_cnt;
374 0 : legacy->is_writable_account_cache_cap = txn->acct_addr_cnt;
375 0 : legacy->is_writable_account_cache = out_sidecar;
376 0 : int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, NULL );
377 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
378 0 : int is_writable = fd_txn_is_writable( txn, i ) &&
379 : /* Agave does this check, but we don't need to here because pack
380 : rejects these transactions before they make it to the bank.
381 :
382 : !fd_bank_abi_builtin_keys_and_sysvars_tbl_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
383 0 : (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
384 0 : legacy->is_writable_account_cache[ i ] = !!is_writable;
385 0 : }
386 0 : out_sidecar += txn->acct_addr_cnt;
387 0 : out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
388 :
389 0 : message->account_keys_cnt = txn->acct_addr_cnt;
390 0 : message->account_keys_cap = txn->acct_addr_cnt;
391 0 : message->account_keys = (void*)(payload + txn->acct_addr_off);
392 :
393 0 : message->instructions_cnt = txn->instr_cnt;
394 0 : message->instructions_cap = txn->instr_cnt;
395 0 : message->instructions = (void*)out_sidecar;
396 0 : for( ulong i=0; i<txn->instr_cnt; i++ ) {
397 0 : fd_txn_instr_t * instr = &txn->instr[ i ];
398 0 : sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
399 :
400 0 : out_instr->accounts_cnt = instr->acct_cnt;
401 0 : out_instr->accounts_cap = instr->acct_cnt;
402 0 : out_instr->accounts = payload + instr->acct_off;
403 :
404 0 : out_instr->data_cnt = instr->data_sz;
405 0 : out_instr->data_cap = instr->data_sz;
406 0 : out_instr->data = payload + instr->data_off;
407 :
408 0 : out_instr->program_id_index = instr->program_id;
409 0 : }
410 0 : out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
411 :
412 0 : fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
413 0 : message->header.num_required_signatures = txn->signature_cnt;
414 0 : message->header.num_readonly_signed_accounts = txn->readonly_signed_cnt;
415 0 : message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
416 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
417 0 : } else if( FD_LIKELY( txn->transaction_version==FD_TXN_V0 ) ){
418 0 : sanitized_txn_abi_v0_loaded_msg_t * v0 = &out_txn->message.v0;
419 0 : sanitized_txn_abi_v0_loaded_addresses_t * loaded_addresses = &v0->loaded_addresses.owned;
420 0 : sanitized_txn_abi_v0_message_t * message = &v0->message.owned;
421 :
422 0 : int result = fd_bank_abi_resolve_address_lookup_tables( bank, 1, slot, txn, payload, (fd_acct_addr_t*)out_sidecar );
423 0 : if( FD_UNLIKELY( result!=FD_BANK_ABI_TXN_INIT_SUCCESS ) ) return result;
424 :
425 0 : ulong lut_writable_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_WRITABLE_ALT );
426 0 : loaded_addresses->writable_cnt = lut_writable_acct_cnt;
427 0 : loaded_addresses->writable_cap = lut_writable_acct_cnt;
428 0 : loaded_addresses->writable = (sanitized_txn_abi_pubkey_t*)out_sidecar;
429 0 : out_sidecar += 32UL*lut_writable_acct_cnt;
430 :
431 0 : ulong lut_readonly_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_READONLY_ALT );
432 0 : loaded_addresses->readable_cnt = lut_readonly_acct_cnt;
433 0 : loaded_addresses->readable_cap = lut_readonly_acct_cnt;
434 0 : loaded_addresses->readable = (sanitized_txn_abi_pubkey_t*)out_sidecar;
435 0 : out_sidecar += 32UL*lut_readonly_acct_cnt;
436 :
437 0 : ulong total_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALL );
438 0 : v0->is_writable_account_cache_cnt = total_acct_cnt;
439 0 : v0->is_writable_account_cache_cap = total_acct_cnt;
440 0 : v0->is_writable_account_cache = out_sidecar;
441 :
442 : /* This looks like it will be an OOB read because we are passing
443 : just the writable account hashes, but the readable ones are
444 : immediately after them in memory, so it's ok. */
445 0 : int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, loaded_addresses->writable );
446 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
447 0 : int is_writable = fd_txn_is_writable( txn, i ) &&
448 : /* Agave does this check, but we don't need to here because pack
449 : rejects these transactions before they make it to the bank.
450 :
451 : !fd_bank_abi_builtin_keys_and_sysvars_tbl_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
452 0 : (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
453 0 : v0->is_writable_account_cache[ i ] = !!is_writable;
454 0 : }
455 0 : for( ushort i=0; i<txn->addr_table_adtl_writable_cnt; i++ ) {
456 : /* We do need to check is_builtin_key_or_sysvar here, because pack
457 : has not yet loaded the address LUT accounts, so it doesn't
458 : reject these yet. */
459 0 : int is_writable = !fd_bank_abi_builtin_keys_and_sysvars_tbl_contains( (const fd_acct_addr_t*)(loaded_addresses->writable + i) ) &&
460 0 : (!is_key_called_as_program( txn, (ushort)(txn->acct_addr_cnt+i) ) || _is_upgradeable_loader_present);
461 0 : v0->is_writable_account_cache[ txn->acct_addr_cnt+i ] = !!is_writable;
462 0 : }
463 0 : for( ushort i=0; i<txn->addr_table_adtl_cnt-txn->addr_table_adtl_writable_cnt; i++ ) {
464 0 : v0->is_writable_account_cache[ txn->acct_addr_cnt+txn->addr_table_adtl_writable_cnt+i ] = 0;
465 0 : }
466 :
467 0 : out_sidecar += txn->acct_addr_cnt + txn->addr_table_adtl_cnt;
468 0 : out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
469 :
470 0 : message->account_keys_cnt = txn->acct_addr_cnt;
471 0 : message->account_keys_cap = txn->acct_addr_cnt;
472 0 : message->account_keys = (void*)(payload + txn->acct_addr_off);
473 :
474 0 : message->instructions_cnt = txn->instr_cnt;
475 0 : message->instructions_cap = txn->instr_cnt;
476 0 : message->instructions = (void*)out_sidecar;
477 0 : for( ulong i=0; i<txn->instr_cnt; i++ ) {
478 0 : fd_txn_instr_t * instr = &txn->instr[ i ];
479 0 : sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
480 :
481 0 : out_instr->accounts_cnt = instr->acct_cnt;
482 0 : out_instr->accounts_cap = instr->acct_cnt;
483 0 : out_instr->accounts = payload + instr->acct_off;
484 :
485 0 : out_instr->data_cnt = instr->data_sz;
486 0 : out_instr->data_cap = instr->data_sz;
487 0 : out_instr->data = payload + instr->data_off;
488 :
489 0 : out_instr->program_id_index = instr->program_id;
490 0 : }
491 0 : out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
492 :
493 0 : fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
494 0 : message->header.num_required_signatures = txn->signature_cnt;
495 0 : message->header.num_readonly_signed_accounts = txn->readonly_signed_cnt;
496 0 : message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
497 :
498 0 : message->address_table_lookups_cnt = txn->addr_table_lookup_cnt;
499 0 : message->address_table_lookups_cap = txn->addr_table_lookup_cnt;
500 0 : message->address_table_lookups = (void*)out_sidecar;
501 0 : for( ulong i=0; i<txn->addr_table_lookup_cnt; i++ ) {
502 0 : fd_txn_acct_addr_lut_t const * lookup = fd_txn_get_address_tables_const( txn ) + i;
503 0 : sanitized_txn_abi_v0_message_address_table_lookup_t * out_lookup = &message->address_table_lookups[ i ];
504 :
505 0 : out_lookup->writable_indexes_cnt = lookup->writable_cnt;
506 0 : out_lookup->writable_indexes_cap = lookup->writable_cnt;
507 0 : out_lookup->writable_indexes = payload + lookup->writable_off;
508 :
509 0 : out_lookup->readonly_indexes_cnt = lookup->readonly_cnt;
510 0 : out_lookup->readonly_indexes_cap = lookup->readonly_cnt;
511 0 : out_lookup->readonly_indexes = payload + lookup->readonly_off;
512 :
513 0 : fd_memcpy( out_lookup->account_key, payload + lookup->addr_off, 32UL );
514 0 : }
515 0 : out_sidecar += txn->addr_table_lookup_cnt*sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t);
516 :
517 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
518 0 : } else {
519 : /* A program abort case, unknown transaction version should never make it here. */
520 0 : FD_LOG_ERR(( "unknown transaction version %u", txn->transaction_version ));
521 0 : }
522 0 : }
|