Line data Source code
1 : #include "fd_bank_abi.h"
2 : #include "../../ballet/txn/fd_txn_v1.h"
3 : #include "../../flamenco/runtime/fd_system_ids_pp.h"
4 : #include "../../flamenco/runtime/fd_system_ids.h"
5 : #include "../../flamenco/runtime/fd_alut.h"
6 : #include "../../disco/pack/fd_pack_unwritable.h"
7 : #include "../../disco/pack/fd_compute_budget_program.h"
8 :
9 : #include <stddef.h>
10 :
11 : #define ABI_ALIGN( x ) __attribute__((packed)) __attribute__((aligned(x)))
12 :
13 : /* Lots of these types contain Rust structs with vectors in them. The
14 : capacity field of Rust Vec<> objects is declared with
15 : type Cap = core::num::niche_types::UsizeNoHighBit;
16 : The compiler takes advantage of this to use that high bit in
17 : discriminating between members of Rust structs. */
18 0 : #define ABI_HIGH_BIT 9223372036854775808UL
19 : FD_STATIC_ASSERT( ABI_HIGH_BIT==0x8000000000000000UL, bank_abi_tag );
20 :
21 : typedef struct ABI_ALIGN(1UL) {
22 : uchar key[ 32UL ];
23 : } sanitized_txn_abi_pubkey_t;
24 :
25 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_pubkey_t) == 32UL, "messed up size" );
26 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_pubkey_t) == 1UL, "messed up size" );
27 :
28 : typedef struct ABI_ALIGN(1UL) {
29 : uchar signature[ 64UL ];
30 : } sanitized_txn_abi_signature_t;
31 :
32 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_signature_t) == 64UL, "messed up size" );
33 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_signature_t) == 1UL, "messed up size" );
34 :
35 : typedef struct ABI_ALIGN(8UL) {
36 : ulong accounts_cap;
37 : uchar * accounts;
38 : ulong accounts_cnt;
39 :
40 : ulong data_cap;
41 : uchar * data;
42 : ulong data_cnt;
43 :
44 : uchar program_id_index;
45 : } sanitized_txn_abi_compiled_instruction_t;
46 :
47 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_compiled_instruction_t) == 56UL, bank_abi );
48 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_compiled_instruction_t) == 8UL, bank_abi );
49 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, accounts_cap)==0, bank_abi );
50 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, data_cap)==24, bank_abi );
51 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, program_id_index)==48, bank_abi );
52 :
53 : typedef struct ABI_ALIGN(1UL) {
54 : uchar num_required_signatures;
55 : uchar num_readonly_signed_accounts;
56 : uchar num_readonly_unsigned_accounts;
57 : } sanitized_txn_abi_message_header_t;
58 :
59 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_message_header_t) == 3UL, "messed up size" );
60 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_header_t) == 1UL, "messed up size" );
61 :
62 : typedef struct ABI_ALIGN(8UL) {
63 : ulong account_keys_cap;
64 : sanitized_txn_abi_pubkey_t * account_keys;
65 : ulong account_keys_cnt;
66 :
67 : ulong instructions_cap;
68 : sanitized_txn_abi_compiled_instruction_t * instructions;
69 : ulong instructions_cnt;
70 :
71 : uchar recent_blockhash[ 32 ];
72 :
73 : sanitized_txn_abi_message_header_t header;
74 : } sanitized_txn_abi_legacy_message0_t;
75 :
76 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, account_keys_cap)==0, bank_abi );
77 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, instructions_cap)==24, bank_abi );
78 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, recent_blockhash)==48, bank_abi );
79 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, header)==80, bank_abi );
80 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message0_t) == 88UL, bank_abi );
81 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message0_t) == 8UL, bank_abi );
82 :
83 : typedef struct ABI_ALIGN(8UL) {
84 : ulong is_writable_account_cache_cap;
85 : uchar * is_writable_account_cache;
86 : ulong is_writable_account_cache_cnt;
87 :
88 : union ABI_ALIGN(8UL) {
89 : ulong discr;
90 :
91 : /* when discr==ULONG_MAX */
92 : struct ABI_ALIGN(8UL) {
93 : uchar _padding[8];
94 : sanitized_txn_abi_legacy_message0_t * borrowed;
95 : };
96 :
97 : /* else */
98 : sanitized_txn_abi_legacy_message0_t owned;
99 : } message;
100 : } sanitized_txn_abi_legacy_message1_t;
101 :
102 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message1_t, message)==24UL, bank_abi );
103 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message1_t) == 112UL, bank_abi );
104 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message1_t) == 8UL, bank_abi );
105 :
106 : typedef struct ABI_ALIGN(8UL) {
107 : ulong writable_indexes_cap;
108 : uchar * writable_indexes;
109 : ulong writable_indexes_cnt;
110 :
111 : ulong readonly_indexes_cap;
112 : uchar * readonly_indexes;
113 : ulong readonly_indexes_cnt;
114 :
115 : uchar account_key[ 32 ];
116 : } sanitized_txn_abi_v0_message_address_table_lookup_t;
117 :
118 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 80UL, "messed up size" );
119 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 8UL, "messed up size" );
120 :
121 : typedef struct ABI_ALIGN(8UL) {
122 : ulong account_keys_cap;
123 : sanitized_txn_abi_pubkey_t * account_keys;
124 : ulong account_keys_cnt;
125 :
126 : ulong instructions_cap;
127 : sanitized_txn_abi_compiled_instruction_t * instructions;
128 : ulong instructions_cnt;
129 :
130 : ulong address_table_lookups_cap;
131 : sanitized_txn_abi_v0_message_address_table_lookup_t * address_table_lookups;
132 : ulong address_table_lookups_cnt;
133 :
134 : uchar recent_blockhash[ 32 ];
135 :
136 : sanitized_txn_abi_message_header_t header;
137 : } sanitized_txn_abi_v0_message_t;
138 :
139 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_t) == 112UL, "messed up size" );
140 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_t) == 8UL, "messed up size" );
141 :
142 : typedef struct ABI_ALIGN(8UL) {
143 : ulong writable_cap;
144 : sanitized_txn_abi_pubkey_t * writable;
145 : ulong writable_cnt;
146 :
147 : ulong readable_cap;
148 : sanitized_txn_abi_pubkey_t * readable;
149 : ulong readable_cnt;
150 : } sanitized_txn_abi_v0_loaded_addresses_t;
151 :
152 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_addresses_t) == 48UL, "messed up size" );
153 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_addresses_t) == 8UL, "messed up size" );
154 :
155 : typedef struct ABI_ALIGN(8UL) {
156 : ulong is_writable_account_cache_cap;
157 : uchar * is_writable_account_cache;
158 : ulong is_writable_account_cache_cnt;
159 :
160 : union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
161 : ulong discr;
162 :
163 : /* when discr==ULONG_MAX */
164 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
165 : uchar _padding[8];
166 : sanitized_txn_abi_v0_message_t * borrowed;
167 : };
168 :
169 : /* else */
170 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
171 : sanitized_txn_abi_v0_message_t owned;
172 : };
173 : } message;
174 :
175 : union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
176 : ulong discr;
177 :
178 : /* when discr==ULONG_MAX */
179 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
180 : uchar _padding[8];
181 : sanitized_txn_abi_v0_loaded_addresses_t * borrowed;
182 : };
183 :
184 : /* else */
185 : struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
186 : sanitized_txn_abi_v0_loaded_addresses_t owned;
187 : };
188 : } loaded_addresses;
189 : } sanitized_txn_abi_v0_loaded_msg_t;
190 :
191 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, is_writable_account_cache_cap)==0, bank_abi );
192 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, message)==24, bank_abi );
193 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, loaded_addresses)==136, bank_abi );
194 : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_msg_t)==184UL, bank_abi );
195 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_msg_t)==8UL, bank_abi );
196 :
197 : typedef union {
198 : ulong discr;
199 : /* When discr==1 */
200 : struct {
201 : uchar _padding[8];
202 : ulong _0;
203 : };
204 : /* when discr==0 */
205 : /* None */
206 : } option_u64_t;
207 : FD_STATIC_ASSERT( sizeof (option_u64_t)==16UL, bank_abi );
208 : FD_STATIC_ASSERT( alignof(option_u64_t)==8UL, bank_abi );
209 :
210 : typedef union {
211 : uint discr;
212 : /* When discr==1 */
213 : struct {
214 : uchar _padding[4];
215 : uint _0;
216 : };
217 : /* when discr==0 */
218 : /* None */
219 : } option_u32_t;
220 : FD_STATIC_ASSERT( sizeof (option_u32_t)==8UL, bank_abi );
221 : FD_STATIC_ASSERT( alignof(option_u32_t)==4UL, bank_abi );
222 :
223 : typedef struct ABI_ALIGN(8UL) {
224 : option_u64_t priority_fee;
225 : option_u32_t compute_unit_limit;
226 : option_u32_t loaded_accounts_data_size_limit;
227 : option_u32_t heap_size;
228 :
229 : ulong account_keys_cap;
230 : sanitized_txn_abi_pubkey_t * account_keys;
231 : ulong account_keys_cnt;
232 :
233 : ulong instructions_cap;
234 : sanitized_txn_abi_compiled_instruction_t * instructions;
235 : ulong instructions_cnt;
236 :
237 : uchar lifetime_specifier[ 32 ];
238 :
239 : sanitized_txn_abi_message_header_t header;
240 : } sanitized_txn_abi_v1_message_t;
241 :
242 : FD_STATIC_ASSERT( sizeof (sanitized_txn_abi_v1_message_t)==128UL, bank_abi );
243 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v1_message_t)==8UL, bank_abi );
244 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, priority_fee )== 0, bank_abi );
245 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, priority_fee._0 )== 8, bank_abi );
246 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, compute_unit_limit )== 16, bank_abi );
247 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, compute_unit_limit._0 )== 20, bank_abi );
248 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, loaded_accounts_data_size_limit )== 24, bank_abi );
249 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, loaded_accounts_data_size_limit._0 )== 28, bank_abi );
250 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, heap_size )== 32, bank_abi );
251 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, heap_size._0 )== 36, bank_abi );
252 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, account_keys_cap )== 40, bank_abi );
253 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, instructions_cap )== 64, bank_abi );
254 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, lifetime_specifier )== 88, bank_abi );
255 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_message_t, header )==120, bank_abi );
256 :
257 : /* Rust's niche filling optimization stores the tag for
258 : Cow<v1::Message>::Borrowed inside the Owned payload, in the Option
259 : tag of the v1::Message's first field, priority_fee.
260 :
261 : The discriminant for Cow<v1::Message>::Borrowed is therefore the
262 : first bit pattern that the Option tag can never hold: 2. */
263 : #define ABI_V1_COW_BORROWED_DISCR (2UL)
264 :
265 : typedef struct ABI_ALIGN(8UL) {
266 : union ABI_ALIGN(8UL) {
267 : ulong discr;
268 :
269 : /* when discr==ABI_V1_COW_BORROWED_DISCR */
270 : struct ABI_ALIGN(8UL) {
271 : uchar _padding[8];
272 : sanitized_txn_abi_v1_message_t * borrowed;
273 : };
274 :
275 : /* else */
276 : sanitized_txn_abi_v1_message_t owned;
277 : } message;
278 :
279 : ulong is_writable_account_cache_cap;
280 : uchar * is_writable_account_cache;
281 : ulong is_writable_account_cache_cnt;
282 : } sanitized_txn_abi_v1_cached_msg_t;
283 :
284 : FD_STATIC_ASSERT( sizeof (sanitized_txn_abi_v1_cached_msg_t)==152UL, bank_abi );
285 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v1_cached_msg_t)==8UL, bank_abi );
286 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_cached_msg_t, message )== 0, bank_abi );
287 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v1_cached_msg_t, is_writable_account_cache_cap)==128, bank_abi );
288 :
289 : /* Rust's niche filling optimization stores the tag for
290 : SanitizedMessage::V1 inside the V0 payload, in the Vec capacity of
291 : the v0::LoadedMessage's first field, is_writable_account_cache.
292 :
293 : The discriminant for SanitizedMessage::V1 is therefore the first bit
294 : pattern that the Vec capacity can never hold, ABI_HIGH_BIT, plus its
295 : variant index: 2. */
296 0 : #define ABI_V1_MSG_DISCR (ABI_HIGH_BIT|2UL)
297 :
298 : typedef union ABI_ALIGN(8UL) {
299 : ulong discr;
300 :
301 : /* when discr==ABI_HIGH_BIT */
302 : struct ABI_ALIGN(8UL) {
303 : uchar _padding[8];
304 : sanitized_txn_abi_legacy_message1_t legacy;
305 : };
306 :
307 : /* when discr==ABI_V1_MSG_DISCR */
308 : struct ABI_ALIGN(8UL) {
309 : uchar _padding_v1[8];
310 : sanitized_txn_abi_v1_cached_msg_t v1;
311 : };
312 :
313 : /* else */
314 : /* No tag. Rust Vec's cap field (the first field in v0) is
315 : core::num::niche_types::UsizeNoHighBit, so this is never ambiguous. */
316 : sanitized_txn_abi_v0_loaded_msg_t v0;
317 : } sanitized_txn_abi_message_t;
318 :
319 : FD_STATIC_ASSERT( sizeof (sanitized_txn_abi_message_t) == 184UL, bank_abi );
320 : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_t) == 8UL, bank_abi );
321 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_message_t, legacy)==8UL, bank_abi );
322 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_message_t, v1 )==8UL, bank_abi );
323 : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_message_t, v0 )==0UL, bank_abi );
324 :
325 :
326 : typedef union {
327 : ulong discr;
328 : /* When discr==1 */
329 : struct {
330 : uchar _padding[8];
331 : uchar _0;
332 : ulong _1;
333 : };
334 : /* when discr==0 */
335 : /* None */
336 : } option_u8_u64_t;
337 : FD_STATIC_ASSERT( sizeof (option_u8_u64_t)==24UL, bank_abi );
338 : FD_STATIC_ASSERT( alignof(option_u8_u64_t)==8UL, bank_abi );
339 :
340 :
341 : typedef union {
342 : uint discr;
343 : /* When discr==1 */
344 : struct {
345 : uchar _padding[4];
346 : uchar _0;
347 : uint _1;
348 : };
349 : /* when discr==0 */
350 : /* None */
351 : } option_u8_u32_t;
352 : FD_STATIC_ASSERT( sizeof (option_u8_u32_t)==12UL, bank_abi );
353 : FD_STATIC_ASSERT( alignof(option_u8_u32_t)==4UL, bank_abi );
354 :
355 :
356 0 : #define ABI_V1_CONFIG_DISCR (2UL)
357 :
358 : struct ABI_ALIGN(8UL) fd_bank_abi_txn_private {
359 : struct ABI_ALIGN(8UL) {
360 : union ABI_ALIGN(8UL) {
361 : ulong discr;
362 :
363 : /* when discr==ABI_V1_CONFIG_DISCR */
364 : struct ABI_ALIGN(8UL) {
365 : uchar _padding[8];
366 : ulong priority_fee_lamports;
367 : uint updated_heap_bytes;
368 : uint compute_unit_limit;
369 : uint loaded_accounts_data_size_limit;
370 : } v1_transaction_config;
371 :
372 : /* else */
373 : struct ABI_ALIGN(8UL) {
374 : option_u8_u64_t requested_compute_unit_price;
375 : option_u8_u32_t requested_compute_unit_limit;
376 : option_u8_u32_t requested_heap_size;
377 : option_u8_u32_t requested_loaded_accounts_data_size_limit;
378 :
379 : ushort num_non_compute_budget_instructions;
380 : ushort num_non_migratable_builtin_instructions;
381 : ushort num_non_builtin_instructions;
382 : ushort migrating_builtin[1]; /* the vote program */
383 : } compute_budget_instruction_details;
384 : } versioned_transaction_config; /* VersionedTransactionConfiguration */
385 :
386 : uchar _message_hash[ 32 ]; /* with the same value as message_hash */
387 :
388 : struct ABI_ALIGN(8UL) {
389 : ulong num_transaction_signatures;
390 : ulong num_secp256k1_instruction_signatures;
391 : ulong num_ed25519_instruction_signatures;
392 : ulong num_secp256r1_instruction_signatures;
393 : }; /* TransactionSignatureDetails */
394 :
395 : ushort instruction_data_len;
396 : uchar is_simple_vote_transaction; /* same as is_simple_vote_tx */
397 : }; /* parts of the TransactionMeta */
398 :
399 : struct ABI_ALIGN(8UL) {
400 : ulong signatures_cap;
401 : sanitized_txn_abi_signature_t * signatures;
402 : ulong signatures_cnt;
403 :
404 : sanitized_txn_abi_message_t message;
405 :
406 : uchar message_hash[ 32 ];
407 : uchar is_simple_vote_tx;
408 : }; /* parts of the SanitizedTransaction */
409 : };
410 :
411 : FD_STATIC_ASSERT( sizeof (struct fd_bank_abi_txn_private)==FD_BANK_ABI_TXN_FOOTPRINT, bank_abi );
412 : FD_STATIC_ASSERT( sizeof (struct fd_bank_abi_txn_private)==392UL, bank_abi );
413 : FD_STATIC_ASSERT( alignof(struct fd_bank_abi_txn_private)==8UL, bank_abi );
414 :
415 : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, signatures_cap )==144UL, bank_abi );
416 :
417 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.requested_compute_unit_price)==0, bank_abi );
418 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.requested_compute_unit_limit)==24, bank_abi );
419 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.requested_heap_size)==36, bank_abi );
420 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.requested_loaded_accounts_data_size_limit)==48, bank_abi );
421 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.num_non_compute_budget_instructions)==60, bank_abi );
422 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.num_non_migratable_builtin_instructions)==62, bank_abi );
423 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.compute_budget_instruction_details.num_non_builtin_instructions)==64, bank_abi );
424 :
425 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.discr)==0, bank_abi );
426 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.v1_transaction_config.priority_fee_lamports)==8, bank_abi );
427 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.v1_transaction_config.updated_heap_bytes)==16, bank_abi );
428 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.v1_transaction_config.compute_unit_limit)==20, bank_abi );
429 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, versioned_transaction_config.v1_transaction_config.loaded_accounts_data_size_limit)==24, bank_abi );
430 :
431 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, is_simple_vote_tx)==0x180, bank_abi );
432 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, is_simple_vote_transaction)==0x8a, bank_abi );
433 :
434 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, message) -offsetof(struct fd_bank_abi_txn_private, signatures_cap)==24, bank_abi );
435 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, message_hash) -offsetof(struct fd_bank_abi_txn_private, signatures_cap)==208, bank_abi );
436 : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, is_simple_vote_tx)-offsetof(struct fd_bank_abi_txn_private, signatures_cap)==240, bank_abi );
437 :
438 : static int
439 : is_key_called_as_program( fd_txn_t const * txn,
440 0 : ushort key_index ) {
441 0 : for( ushort i=0; i<txn->instr_cnt; i++ ) {
442 0 : fd_txn_instr_t const * instr = &txn->instr[ i ];
443 0 : if( FD_UNLIKELY( instr->program_id==key_index ) ) return 1;
444 0 : }
445 0 : return 0;
446 0 : }
447 :
448 : static const uchar BPF_UPGRADEABLE_PROG_ID1[32] = { BPF_UPGRADEABLE_PROG_ID };
449 :
450 : static int
451 : is_upgradeable_loader_present( fd_txn_t const * txn,
452 : uchar const * payload,
453 0 : sanitized_txn_abi_pubkey_t const * loaded_addresses ) {
454 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
455 0 : if( FD_UNLIKELY( !memcmp( payload + txn->acct_addr_off + i*32UL, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
456 0 : }
457 0 : for( ushort i=0; i<txn->addr_table_adtl_cnt; i++ ) {
458 0 : if( FD_UNLIKELY( !memcmp( loaded_addresses + i, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
459 0 : }
460 0 : return 0;
461 0 : }
462 :
463 : extern int
464 : fd_ext_bank_load_account( void const * bank,
465 : int fixed_root,
466 : uchar const * addr,
467 : uchar * owner,
468 : uchar * data,
469 : ulong * data_sz );
470 :
471 : int
472 : fd_bank_abi_resolve_address_lookup_tables( void const * bank,
473 : int fixed_root,
474 : ulong slot,
475 : fd_txn_t const * txn,
476 : uchar const * payload,
477 0 : fd_acct_addr_t * out_lut_accts ) {
478 0 : ulong writable_idx = 0UL;
479 0 : ulong readable_idx = 0UL;
480 0 : for( ulong i=0UL; i<txn->addr_table_lookup_cnt; i++ ) {
481 0 : fd_txn_acct_addr_lut_t const * lut = &fd_txn_get_address_tables_const( txn )[ i ];
482 0 : uchar const * addr = payload + lut->addr_off;
483 :
484 0 : uchar owner[ 32UL ];
485 0 : uchar data[ 1UL+56UL+256UL*32UL ];
486 0 : ulong data_sz = sizeof(data);
487 0 : int result = fd_ext_bank_load_account( bank, fixed_root, addr, owner, data, &data_sz );
488 0 : if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
489 :
490 0 : result = memcmp( owner, fd_solana_address_lookup_table_program_id.key, 32UL );
491 0 : if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_OWNER;
492 :
493 0 : if( FD_UNLIKELY( (data_sz<56UL) | (data_sz>(56UL+256UL*32UL)) ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
494 :
495 0 : fd_alut_meta_t meta;
496 0 : result = fd_alut_state_decode( data, data_sz, &meta );
497 0 : if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
498 :
499 0 : if( FD_UNLIKELY( meta.discriminant!=FD_ALUT_STATE_DISC_LOOKUP_TABLE ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_UNINITIALIZED;
500 :
501 0 : if( FD_UNLIKELY( (data_sz-56UL)%32UL ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
502 :
503 0 : ulong addresses_len = (data_sz-56UL)/32UL;
504 0 : fd_acct_addr_t const * addresses = fd_type_pun_const( data+56UL );
505 :
506 : /* This logic is not currently very precise... an ALUT is allowed if
507 : the deactivation slot is no longer present in the slot hashes
508 : sysvar, which means that the slot was more than 512 *unskipped*
509 : slots prior. In the current case, we are just throwing out a
510 : fraction of transactions that could actually still be valid
511 : (those deactivated between 512 and 512*(1+skip_rate) slots ago. */
512 :
513 0 : ulong deactivation_slot = meta.deactivation_slot;
514 0 : if( FD_UNLIKELY( deactivation_slot!=ULONG_MAX && (deactivation_slot+512UL)<slot ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
515 :
516 0 : ulong active_addresses_len = fd_ulong_if( slot>meta.last_extended_slot,
517 0 : addresses_len,
518 0 : meta.last_extended_slot_start_index );
519 0 : for( ulong j=0UL; j<lut->writable_cnt; j++ ) {
520 0 : uchar idx = payload[ lut->writable_off+j ];
521 0 : if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
522 0 : out_lut_accts[ writable_idx++ ] = addresses[ idx ];
523 0 : }
524 0 : for( ulong j=0UL; j<lut->readonly_cnt; j++ ) {
525 0 : uchar idx = payload[ lut->readonly_off+j ];
526 0 : if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
527 0 : out_lut_accts[ txn->addr_table_adtl_writable_cnt+readable_idx++ ] = addresses[ idx ];
528 0 : }
529 0 : }
530 :
531 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
532 0 : }
533 :
534 0 : #define CATEGORY_NON_BUILTIN 0
535 0 : #define CATEGORY_NON_MIGRATABLE 1
536 0 : #define CATEGORY_MIGRATING(x) (2+(x))
537 : typedef struct {
538 : uchar b[FD_TXN_ACCT_ADDR_SZ];
539 : int category;
540 : } fd_bank_abi_prog_map_t;
541 :
542 : #define MAP_PERFECT_NAME prog_map
543 : #define MAP_PERFECT_LG_TBL_SZ 4
544 : #define MAP_PERFECT_T fd_bank_abi_prog_map_t
545 : #define MAP_PERFECT_KEY b
546 : #define MAP_PERFECT_KEY_T fd_acct_addr_t const *
547 : #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)
548 : #define MAP_PERFECT_COMPLEX_KEY 1
549 0 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
550 :
551 0 : #define PERFECT_HASH( u ) ((((3776U*(u))>>28)-1U)&0xFU)
552 :
553 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
554 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
555 : PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
556 0 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
557 :
558 : #define MAP_PERFECT_0 ( KECCAK_SECP_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
559 : #define MAP_PERFECT_1 ( ED25519_SV_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
560 : #define MAP_PERFECT_2 ( SECP256R1_PROG_ID ), .category=CATEGORY_NON_BUILTIN /* strange, but true */
561 : #define MAP_PERFECT_3 ( VOTE_PROG_ID ), .category=CATEGORY_MIGRATING(0) /* SIMD-0387 */
562 : #define MAP_PERFECT_4 ( SYS_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
563 : #define MAP_PERFECT_5 ( COMPUTE_BUDGET_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
564 : #define MAP_PERFECT_6 ( BPF_UPGRADEABLE_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
565 : #define MAP_PERFECT_7 ( BPF_LOADER_1_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
566 : #define MAP_PERFECT_8 ( BPF_LOADER_2_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
567 : #define MAP_PERFECT_9 ( LOADER_V4_PROG_ID ), .category=CATEGORY_NON_MIGRATABLE
568 :
569 :
570 : #include "../../util/tmpl/fd_map_perfect.c"
571 :
572 : /* Redefine it so we can use it below */
573 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
574 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
575 0 : PERFECT_HASH( ((uint)a08 | ((uint)a09<<8) | ((uint)a10<<16) | ((uint)a11<<24)) )
576 0 : #define HASH( x ) MAP_PERFECT_HASH_PP( x )
577 :
578 : FD_STATIC_ASSERT( HASH( KECCAK_SECP_PROG_ID )<3, precompile_table );
579 : FD_STATIC_ASSERT( HASH( ED25519_SV_PROG_ID )<3, precompile_table );
580 : FD_STATIC_ASSERT( HASH( SECP256R1_PROG_ID )<3, precompile_table );
581 :
582 : int
583 : fd_bank_abi_txn_init( fd_bank_abi_txn_t * out_txn,
584 : uchar * out_sidecar,
585 : void const * bank,
586 : ulong slot,
587 : fd_blake3_t * blake3,
588 : uchar * payload,
589 : ulong payload_sz,
590 : fd_txn_t * txn,
591 0 : int is_simple_vote ) {
592 0 : out_txn->signatures_cnt = txn->signature_cnt;
593 0 : out_txn->signatures_cap = txn->signature_cnt;
594 0 : out_txn->signatures = (void*)(payload + txn->signature_off);
595 :
596 0 : fd_blake3_init( blake3 );
597 0 : fd_blake3_append( blake3, "solana-tx-message-v1", 20UL );
598 0 : fd_blake3_append( blake3, payload + txn->message_off, fd_txn_msg_sz( txn, payload_sz ) );
599 0 : fd_blake3_fini( blake3, out_txn->message_hash );
600 0 : memcpy( out_txn->_message_hash, out_txn->message_hash, 32UL );
601 :
602 0 : out_txn->is_simple_vote_tx = !!is_simple_vote;
603 0 : out_txn->is_simple_vote_transaction = !!is_simple_vote;
604 :
605 :
606 0 : ulong sig_counters[4] = { 0UL };
607 0 : ulong instr_cnt[3] = { 0UL }; /* non-builtin, non-migrating, vote program */
608 :
609 0 : fd_compute_budget_program_state_t cbp_state[1];
610 0 : fd_compute_budget_program_init( cbp_state );
611 :
612 0 : ulong instr_data_sz = 0UL;
613 0 : fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
614 0 : const fd_bank_abi_prog_map_t non_builtin[1] = { { .category = CATEGORY_NON_BUILTIN } };
615 0 : for( ulong i=0UL; i<txn->instr_cnt; i++ ) {
616 0 : ulong prog_id_idx = (ulong)txn->instr[i].program_id;
617 0 : fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
618 :
619 : /* Lookup prog_id in hash table. If it's a miss, it'll return
620 : UINT_MAX which gets clamped to 3. Otherwise, it'll be 0, 1, or
621 : 2. */
622 0 : uint hash_or_def = prog_map_hash_or_default( prog_id );
623 0 : sig_counters[ fd_uint_min( 3UL, hash_or_def ) ] +=
624 0 : (txn->instr[i].data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
625 :
626 0 : instr_cnt[ prog_map_query( prog_id, non_builtin )->category ]++;
627 0 : instr_data_sz += txn->instr[i].data_sz;
628 :
629 : /* Parse compute budget instructions for legacy/v0 transactions.
630 : These are ignored for V1 transactions. */
631 0 : if( FD_UNLIKELY( txn->transaction_version!=FD_TXN_V1 &&
632 0 : hash_or_def==HASH( COMPUTE_BUDGET_PROG_ID ) ) ) {
633 0 : fd_compute_budget_program_parse( payload+txn->instr[i].data_off, txn->instr[i].data_sz, cbp_state );
634 0 : }
635 0 : }
636 0 : out_txn->instruction_data_len = (ushort)instr_data_sz; /* fd_txn_parse ensures this is less than MTU, so the cast is safe */
637 0 : out_txn->num_transaction_signatures = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_SIGNER );
638 0 : out_txn->num_secp256k1_instruction_signatures = sig_counters[ HASH( KECCAK_SECP_PROG_ID ) ];
639 0 : out_txn->num_ed25519_instruction_signatures = sig_counters[ HASH( ED25519_SV_PROG_ID ) ];
640 0 : out_txn->num_secp256r1_instruction_signatures = sig_counters[ HASH( SECP256R1_PROG_ID ) ];
641 :
642 : /* VersionedTransactionConfiguration::LegacyAndV0(ComputeBudgetInstructionDetails)
643 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/runtime-transaction/src/transaction_meta.rs#L131-L137 */
644 0 : if( FD_LIKELY( txn->transaction_version!=FD_TXN_V1 ) ) {
645 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.num_non_compute_budget_instructions = (ushort)(txn->instr_cnt - cbp_state->compute_budget_instr_cnt);
646 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.num_non_migratable_builtin_instructions = (ushort)instr_cnt[ CATEGORY_NON_MIGRATABLE ];
647 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.num_non_builtin_instructions = (ushort)instr_cnt[ CATEGORY_NON_BUILTIN ];
648 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.migrating_builtin[0] = (ushort)instr_cnt[ CATEGORY_MIGRATING(0) ];
649 : /* The instruction index doesn't matter */
650 0 : #define CBP_TO_TUPLE_OPTION( out, flag, val0, val1 ) \
651 0 : do { \
652 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.out.discr = !!(cbp_state->flags & FD_COMPUTE_BUDGET_PROGRAM_FLAG_ ## flag); \
653 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.out._0 = (val0); \
654 0 : out_txn->versioned_transaction_config.compute_budget_instruction_details.out._1 = (val1); \
655 0 : } while( 0 )
656 :
657 0 : CBP_TO_TUPLE_OPTION( requested_compute_unit_price, SET_FEE, 0, cbp_state->micro_lamports_per_cu );
658 0 : CBP_TO_TUPLE_OPTION( requested_compute_unit_limit, SET_CU, 0, cbp_state->compute_units );
659 0 : CBP_TO_TUPLE_OPTION( requested_heap_size, SET_HEAP, 0, cbp_state->heap_size );
660 0 : CBP_TO_TUPLE_OPTION( requested_loaded_accounts_data_size_limit, SET_LOADED_DATA_SZ, 0, cbp_state->loaded_acct_data_sz );
661 0 : #undef CBP_TO_TUPLE_OPTION
662 0 : }
663 :
664 0 : if( FD_LIKELY( txn->transaction_version==FD_TXN_VLEGACY ) ) {
665 0 : sanitized_txn_abi_legacy_message1_t * legacy = &out_txn->message.legacy;
666 0 : sanitized_txn_abi_legacy_message0_t * message = &legacy->message.owned;
667 :
668 0 : out_txn->message.discr = ABI_HIGH_BIT;
669 :
670 0 : legacy->is_writable_account_cache_cnt = txn->acct_addr_cnt;
671 0 : legacy->is_writable_account_cache_cap = txn->acct_addr_cnt;
672 0 : legacy->is_writable_account_cache = out_sidecar;
673 0 : int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, NULL );
674 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
675 0 : int is_writable = fd_txn_is_writable( txn, i ) &&
676 : /* Agave does this check, but we don't need to here because pack
677 : rejects these transactions before they make it to the bank.
678 :
679 : !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
680 0 : (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
681 0 : legacy->is_writable_account_cache[ i ] = !!is_writable;
682 0 : }
683 0 : out_sidecar += txn->acct_addr_cnt;
684 0 : out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
685 :
686 0 : message->account_keys_cnt = txn->acct_addr_cnt;
687 0 : message->account_keys_cap = txn->acct_addr_cnt;
688 0 : message->account_keys = (void*)(payload + txn->acct_addr_off);
689 :
690 0 : message->instructions_cnt = txn->instr_cnt;
691 0 : message->instructions_cap = txn->instr_cnt;
692 0 : message->instructions = (void*)out_sidecar;
693 0 : for( ulong i=0; i<txn->instr_cnt; i++ ) {
694 0 : fd_txn_instr_t * instr = &txn->instr[ i ];
695 0 : sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
696 :
697 0 : out_instr->accounts_cnt = instr->acct_cnt;
698 0 : out_instr->accounts_cap = instr->acct_cnt;
699 0 : out_instr->accounts = payload + instr->acct_off;
700 :
701 0 : out_instr->data_cnt = instr->data_sz;
702 0 : out_instr->data_cap = instr->data_sz;
703 0 : out_instr->data = payload + instr->data_off;
704 :
705 0 : out_instr->program_id_index = instr->program_id;
706 0 : }
707 0 : out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
708 :
709 0 : fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
710 0 : message->header.num_required_signatures = txn->signature_cnt;
711 0 : message->header.num_readonly_signed_accounts = txn->readonly_signed_cnt;
712 0 : message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
713 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
714 0 : } else if( FD_LIKELY( txn->transaction_version==FD_TXN_V0 ) ){
715 0 : sanitized_txn_abi_v0_loaded_msg_t * v0 = &out_txn->message.v0;
716 0 : sanitized_txn_abi_v0_loaded_addresses_t * loaded_addresses = &v0->loaded_addresses.owned;
717 0 : sanitized_txn_abi_v0_message_t * message = &v0->message.owned;
718 :
719 0 : int result = fd_bank_abi_resolve_address_lookup_tables( bank, 1, slot, txn, payload, (fd_acct_addr_t*)out_sidecar );
720 0 : if( FD_UNLIKELY( result!=FD_BANK_ABI_TXN_INIT_SUCCESS ) ) return result;
721 :
722 0 : ulong lut_writable_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_WRITABLE_ALT );
723 0 : loaded_addresses->writable_cnt = lut_writable_acct_cnt;
724 0 : loaded_addresses->writable_cap = lut_writable_acct_cnt;
725 0 : loaded_addresses->writable = (sanitized_txn_abi_pubkey_t*)out_sidecar;
726 0 : out_sidecar += 32UL*lut_writable_acct_cnt;
727 :
728 0 : ulong lut_readonly_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_READONLY_ALT );
729 0 : loaded_addresses->readable_cnt = lut_readonly_acct_cnt;
730 0 : loaded_addresses->readable_cap = lut_readonly_acct_cnt;
731 0 : loaded_addresses->readable = (sanitized_txn_abi_pubkey_t*)out_sidecar;
732 0 : out_sidecar += 32UL*lut_readonly_acct_cnt;
733 :
734 0 : ulong total_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALL );
735 0 : v0->is_writable_account_cache_cnt = total_acct_cnt;
736 0 : v0->is_writable_account_cache_cap = total_acct_cnt;
737 0 : v0->is_writable_account_cache = out_sidecar;
738 :
739 : /* This looks like it will be an OOB read because we are passing
740 : just the writable account hashes, but the readable ones are
741 : immediately after them in memory, so it's ok. */
742 0 : int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, loaded_addresses->writable );
743 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
744 0 : int is_writable = fd_txn_is_writable( txn, i ) &&
745 : /* Agave does this check, but we don't need to here because pack
746 : rejects these transactions before they make it to the bank.
747 :
748 : !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
749 0 : (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
750 0 : v0->is_writable_account_cache[ i ] = !!is_writable;
751 0 : }
752 0 : for( ushort i=0; i<txn->addr_table_adtl_writable_cnt; i++ ) {
753 : /* We do need to check is_builtin_key_or_sysvar here, because pack
754 : has not yet loaded the address LUT accounts, so it doesn't
755 : reject these yet. */
756 0 : int is_writable = !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(loaded_addresses->writable + i) ) &&
757 0 : (!is_key_called_as_program( txn, (ushort)(txn->acct_addr_cnt+i) ) || _is_upgradeable_loader_present);
758 0 : v0->is_writable_account_cache[ txn->acct_addr_cnt+i ] = !!is_writable;
759 0 : }
760 0 : for( ushort i=0; i<txn->addr_table_adtl_cnt-txn->addr_table_adtl_writable_cnt; i++ ) {
761 0 : v0->is_writable_account_cache[ txn->acct_addr_cnt+txn->addr_table_adtl_writable_cnt+i ] = 0;
762 0 : }
763 :
764 0 : out_sidecar += txn->acct_addr_cnt + txn->addr_table_adtl_cnt;
765 0 : out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
766 :
767 0 : message->account_keys_cnt = txn->acct_addr_cnt;
768 0 : message->account_keys_cap = txn->acct_addr_cnt;
769 0 : message->account_keys = (void*)(payload + txn->acct_addr_off);
770 :
771 0 : message->instructions_cnt = txn->instr_cnt;
772 0 : message->instructions_cap = txn->instr_cnt;
773 0 : message->instructions = (void*)out_sidecar;
774 0 : for( ulong i=0; i<txn->instr_cnt; i++ ) {
775 0 : fd_txn_instr_t * instr = &txn->instr[ i ];
776 0 : sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
777 :
778 0 : out_instr->accounts_cnt = instr->acct_cnt;
779 0 : out_instr->accounts_cap = instr->acct_cnt;
780 0 : out_instr->accounts = payload + instr->acct_off;
781 :
782 0 : out_instr->data_cnt = instr->data_sz;
783 0 : out_instr->data_cap = instr->data_sz;
784 0 : out_instr->data = payload + instr->data_off;
785 :
786 0 : out_instr->program_id_index = instr->program_id;
787 0 : }
788 0 : out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
789 :
790 0 : fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
791 0 : message->header.num_required_signatures = txn->signature_cnt;
792 0 : message->header.num_readonly_signed_accounts = txn->readonly_signed_cnt;
793 0 : message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
794 :
795 0 : message->address_table_lookups_cnt = txn->addr_table_lookup_cnt;
796 0 : message->address_table_lookups_cap = txn->addr_table_lookup_cnt;
797 0 : message->address_table_lookups = (void*)out_sidecar;
798 0 : for( ulong i=0; i<txn->addr_table_lookup_cnt; i++ ) {
799 0 : fd_txn_acct_addr_lut_t const * lookup = fd_txn_get_address_tables_const( txn ) + i;
800 0 : sanitized_txn_abi_v0_message_address_table_lookup_t * out_lookup = &message->address_table_lookups[ i ];
801 :
802 0 : out_lookup->writable_indexes_cnt = lookup->writable_cnt;
803 0 : out_lookup->writable_indexes_cap = lookup->writable_cnt;
804 0 : out_lookup->writable_indexes = payload + lookup->writable_off;
805 :
806 0 : out_lookup->readonly_indexes_cnt = lookup->readonly_cnt;
807 0 : out_lookup->readonly_indexes_cap = lookup->readonly_cnt;
808 0 : out_lookup->readonly_indexes = payload + lookup->readonly_off;
809 :
810 0 : fd_memcpy( out_lookup->account_key, payload + lookup->addr_off, 32UL );
811 0 : }
812 0 : out_sidecar += txn->addr_table_lookup_cnt*sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t);
813 :
814 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
815 0 : } else if( FD_LIKELY( txn->transaction_version==FD_TXN_V1 ) ) {
816 : /* VersionedTransactionConfiguration::V1
817 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/runtime-transaction/src/transaction_meta.rs#L122-L129 */
818 0 : uint v1_config_mask = fd_uint_load_4( payload+4UL );
819 0 : ulong v1_priority_fee, v1_cu_limit, v1_loaded_sz, v1_heap_sz;
820 0 : fd_txn_parse_v1_config( v1_config_mask,
821 0 : payload + txn->v1_txn_config_values_off,
822 0 : &v1_priority_fee,
823 0 : &v1_cu_limit,
824 0 : &v1_loaded_sz,
825 0 : &v1_heap_sz );
826 :
827 0 : out_txn->versioned_transaction_config.discr = ABI_V1_CONFIG_DISCR;
828 0 : out_txn->versioned_transaction_config.v1_transaction_config.priority_fee_lamports = v1_priority_fee;
829 0 : out_txn->versioned_transaction_config.v1_transaction_config.updated_heap_bytes = (uint)v1_heap_sz;
830 0 : out_txn->versioned_transaction_config.v1_transaction_config.compute_unit_limit = (uint)v1_cu_limit;
831 0 : out_txn->versioned_transaction_config.v1_transaction_config.loaded_accounts_data_size_limit = (uint)v1_loaded_sz;
832 :
833 0 : sanitized_txn_abi_v1_cached_msg_t * v1 = &out_txn->message.v1;
834 0 : sanitized_txn_abi_v1_message_t * message = &v1->message.owned;
835 :
836 0 : out_txn->message.discr = ABI_V1_MSG_DISCR;
837 :
838 0 : v1->is_writable_account_cache_cnt = txn->acct_addr_cnt;
839 0 : v1->is_writable_account_cache_cap = txn->acct_addr_cnt;
840 0 : v1->is_writable_account_cache = out_sidecar;
841 :
842 : /* V1 transactions have no ALTs so passing NULL is safe here. */
843 0 : int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, NULL );
844 0 : for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
845 0 : int is_writable = fd_txn_is_writable( txn, i ) &&
846 : /* Agave does this check, but we don't need to here because pack
847 : rejects these transactions before they make it to the bank.
848 :
849 : !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
850 0 : (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
851 0 : v1->is_writable_account_cache[ i ] = !!is_writable;
852 0 : }
853 0 : out_sidecar += txn->acct_addr_cnt;
854 0 : out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
855 :
856 : /* The compute budget information is stored twice in the struct,
857 : once in
858 : RuntimeTransaction::meta::versioned_transaction_config::V1::*
859 : which has the default values applied, and once in
860 : RuntimeTransaction::transaction::message::V1::message::config::*
861 : that stores options (None if the option is not specified in the
862 : transaction).
863 : To simplify the code, even when the option is not specified, we
864 : set the default value, and then use the tag field to note that
865 : it is a None value. */
866 :
867 : /* This sets priority_fee.discr to 0 or 1. That means
868 : `v1->message.discr != ABI_V1_COW_BORROWED_DISCR`, so we know it
869 : is owned. */
870 0 : message->priority_fee.discr = (ulong)( v1_config_mask &1U);
871 0 : message->compute_unit_limit.discr = ((v1_config_mask>>2)&1U);
872 0 : message->loaded_accounts_data_size_limit.discr = ((v1_config_mask>>3)&1U);
873 0 : message->heap_size.discr = ((v1_config_mask>>4)&1U);
874 :
875 0 : message->priority_fee._0 = v1_priority_fee;
876 0 : message->compute_unit_limit._0 = (uint)v1_cu_limit;
877 0 : message->loaded_accounts_data_size_limit._0 = (uint)v1_loaded_sz;
878 0 : message->heap_size._0 = (uint)v1_heap_sz;
879 :
880 0 : message->account_keys_cnt = txn->acct_addr_cnt;
881 0 : message->account_keys_cap = txn->acct_addr_cnt;
882 0 : message->account_keys = (void*)(payload + txn->acct_addr_off);
883 :
884 0 : message->instructions_cnt = txn->instr_cnt;
885 0 : message->instructions_cap = txn->instr_cnt;
886 0 : message->instructions = (void*)out_sidecar;
887 0 : for( ulong i=0; i<txn->instr_cnt; i++ ) {
888 0 : fd_txn_instr_t * instr = &txn->instr[ i ];
889 0 : sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
890 :
891 0 : out_instr->accounts_cnt = instr->acct_cnt;
892 0 : out_instr->accounts_cap = instr->acct_cnt;
893 0 : out_instr->accounts = payload + instr->acct_off;
894 :
895 0 : out_instr->data_cnt = instr->data_sz;
896 0 : out_instr->data_cap = instr->data_sz;
897 0 : out_instr->data = payload + instr->data_off;
898 :
899 0 : out_instr->program_id_index = instr->program_id;
900 0 : }
901 0 : out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
902 :
903 0 : fd_memcpy( message->lifetime_specifier, payload + txn->recent_blockhash_off, 32UL );
904 0 : message->header.num_required_signatures = txn->signature_cnt;
905 0 : message->header.num_readonly_signed_accounts = txn->readonly_signed_cnt;
906 0 : message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
907 :
908 0 : return FD_BANK_ABI_TXN_INIT_SUCCESS;
909 0 : } else {
910 : /* A program abort case, unknown transaction version should never make it here. */
911 0 : FD_LOG_ERR(( "unknown transaction version %u", txn->transaction_version ));
912 0 : }
913 0 : }
|