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