LCOV - code coverage report
Current view: top level - discoh/bank - fd_bank_abi.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 294 0.0 %
Date: 2026-09-17 04:28:31 Functions: 0 4 0.0 %

          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 : }

Generated by: LCOV version 1.14