LCOV - code coverage report
Current view: top level - discoh/bank - fd_bank_abi.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 212 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 5 0.0 %

          Line data    Source code
       1             : 
       2             : #include "fd_bank_abi.h"
       3             : #include "../../flamenco/runtime/fd_system_ids_pp.h"
       4             : #include "../../flamenco/runtime/fd_system_ids.h"
       5             : #include "../../flamenco/types/fd_types.h"
       6             : #include "../../disco/pack/fd_pack_unwritable.h"
       7             : 
       8             : #define ABI_ALIGN( x ) __attribute__((packed)) __attribute__((aligned(x)))
       9             : 
      10             : /* Lots of these types contain Rust structs with vectors in them.  The
      11             :    capacity field of Rust Vec<> objects is declared with
      12             :       type Cap = core::num::niche_types::UsizeNoHighBit;
      13             :    The compiler takes advantage of this to use that high bit in
      14             :    discriminating between members of Rust structs. */
      15           0 : #define ABI_HIGH_BIT 9223372036854775808UL
      16             : FD_STATIC_ASSERT( ABI_HIGH_BIT==0x8000000000000000UL, bank_abi_tag );
      17             : 
      18             : typedef struct ABI_ALIGN(1UL) {
      19             :   uchar key[ 32UL ];
      20             : } sanitized_txn_abi_pubkey_t;
      21             : 
      22             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_pubkey_t) == 32UL, "messed up size" );
      23             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_pubkey_t) == 1UL, "messed up size" );
      24             : 
      25             : typedef struct ABI_ALIGN(1UL) {
      26             :   uchar signature[ 64UL ];
      27             : } sanitized_txn_abi_signature_t;
      28             : 
      29             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_signature_t) == 64UL, "messed up size" );
      30             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_signature_t) == 1UL, "messed up size" );
      31             : 
      32             : typedef struct ABI_ALIGN(8UL) {
      33             :   ulong   accounts_cap;
      34             :   uchar * accounts;
      35             :   ulong   accounts_cnt;
      36             : 
      37             :   ulong   data_cap;
      38             :   uchar * data;
      39             :   ulong   data_cnt;
      40             : 
      41             :   uchar program_id_index;
      42             : } sanitized_txn_abi_compiled_instruction_t;
      43             : 
      44             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_compiled_instruction_t) == 56UL, bank_abi );
      45             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_compiled_instruction_t) == 8UL, bank_abi );
      46             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, accounts_cap)==0, bank_abi );
      47             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, data_cap)==24, bank_abi );
      48             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_compiled_instruction_t, program_id_index)==48, bank_abi );
      49             : 
      50             : typedef struct ABI_ALIGN(1UL) {
      51             :   uchar num_required_signatures;
      52             :   uchar num_readonly_signed_accounts;
      53             :   uchar num_readonly_unsigned_accounts;
      54             : } sanitized_txn_abi_message_header_t;
      55             : 
      56             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_message_header_t) == 3UL, "messed up size" );
      57             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_header_t) == 1UL, "messed up size" );
      58             : 
      59             : typedef struct ABI_ALIGN(8UL) {
      60             :   ulong account_keys_cap;
      61             :   sanitized_txn_abi_pubkey_t * account_keys;
      62             :   ulong account_keys_cnt;
      63             : 
      64             :   ulong instructions_cap;
      65             :   sanitized_txn_abi_compiled_instruction_t * instructions;
      66             :   ulong instructions_cnt;
      67             : 
      68             :   uchar recent_blockhash[ 32 ];
      69             : 
      70             :   sanitized_txn_abi_message_header_t header;
      71             : } sanitized_txn_abi_legacy_message0_t;
      72             : 
      73             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, account_keys_cap)==0, bank_abi );
      74             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, instructions_cap)==24, bank_abi );
      75             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, recent_blockhash)==48, bank_abi );
      76             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message0_t, header)==80, bank_abi );
      77             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message0_t) == 88UL, bank_abi );
      78             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message0_t) == 8UL, bank_abi );
      79             : 
      80             : typedef struct ABI_ALIGN(8UL) {
      81             :   ulong   is_writable_account_cache_cap;
      82             :   uchar * is_writable_account_cache;
      83             :   ulong   is_writable_account_cache_cnt;
      84             : 
      85             :   union ABI_ALIGN(8UL) {
      86             :     ulong discr;
      87             : 
      88             :     /* when discr==ABI_HIGH_BIT */
      89             :     struct ABI_ALIGN(8UL) {
      90             :       uchar _padding[8];
      91             :       sanitized_txn_abi_legacy_message0_t * borrowed;
      92             :     };
      93             : 
      94             :     /* else */
      95             :     sanitized_txn_abi_legacy_message0_t owned;
      96             :   } message;
      97             : } sanitized_txn_abi_legacy_message1_t;
      98             : 
      99             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_legacy_message1_t, message)==24UL, bank_abi );
     100             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_legacy_message1_t) == 112UL, bank_abi );
     101             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_legacy_message1_t) == 8UL, bank_abi );
     102             : 
     103             : typedef struct ABI_ALIGN(8UL) {
     104             :   ulong   writable_indexes_cap;
     105             :   uchar * writable_indexes;
     106             :   ulong   writable_indexes_cnt;
     107             : 
     108             :   ulong   readonly_indexes_cap;
     109             :   uchar * readonly_indexes;
     110             :   ulong   readonly_indexes_cnt;
     111             : 
     112             :   uchar account_key[ 32 ];
     113             : } sanitized_txn_abi_v0_message_address_table_lookup_t;
     114             : 
     115             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 80UL, "messed up size" );
     116             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_address_table_lookup_t) == 8UL, "messed up size" );
     117             : 
     118             : typedef struct ABI_ALIGN(8UL) {
     119             :   ulong                        account_keys_cap;
     120             :   sanitized_txn_abi_pubkey_t * account_keys;
     121             :   ulong                        account_keys_cnt;
     122             : 
     123             :   ulong                                      instructions_cap;
     124             :   sanitized_txn_abi_compiled_instruction_t * instructions;
     125             :   ulong                                      instructions_cnt;
     126             : 
     127             :   ulong                                                 address_table_lookups_cap;
     128             :   sanitized_txn_abi_v0_message_address_table_lookup_t * address_table_lookups;
     129             :   ulong                                                 address_table_lookups_cnt;
     130             : 
     131             :   uchar recent_blockhash[ 32 ];
     132             : 
     133             :   sanitized_txn_abi_message_header_t header;
     134             : } sanitized_txn_abi_v0_message_t;
     135             : 
     136             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_message_t) == 112UL, "messed up size" );
     137             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_message_t) == 8UL, "messed up size" );
     138             : 
     139             : typedef struct ABI_ALIGN(8UL) {
     140             :   ulong                        writable_cap;
     141             :   sanitized_txn_abi_pubkey_t * writable;
     142             :   ulong                        writable_cnt;
     143             : 
     144             :   ulong                        readable_cap;
     145             :   sanitized_txn_abi_pubkey_t * readable;
     146             :   ulong                        readable_cnt;
     147             : } sanitized_txn_abi_v0_loaded_addresses_t;
     148             : 
     149             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_addresses_t) == 48UL, "messed up size" );
     150             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_addresses_t) == 8UL, "messed up size" );
     151             : 
     152             : typedef struct ABI_ALIGN(8UL) {
     153             :   ulong   is_writable_account_cache_cap;
     154             :   uchar * is_writable_account_cache;
     155             :   ulong   is_writable_account_cache_cnt;
     156             : 
     157             :   union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     158             :     ulong discr;
     159             : 
     160             :     /* when discr==ABI_HIGH_BIT */
     161             :     struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     162             :       uchar _padding[8];
     163             :       sanitized_txn_abi_v0_message_t * borrowed;
     164             :     };
     165             : 
     166             :     /* else */
     167             :     struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     168             :       sanitized_txn_abi_v0_message_t owned;
     169             :     };
     170             :   } message;
     171             : 
     172             :   union __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     173             :     ulong discr;
     174             : 
     175             :     /* when discr==ABI_HIGH_BIT */
     176             :     struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     177             :       uchar _padding[8];
     178             :       sanitized_txn_abi_v0_loaded_addresses_t * borrowed;
     179             :     };
     180             : 
     181             :     /* else */
     182             :     struct __attribute__((__packed__)) __attribute__((aligned(8UL))) {
     183             :       sanitized_txn_abi_v0_loaded_addresses_t owned;
     184             :     };
     185             :   } loaded_addresses;
     186             : } sanitized_txn_abi_v0_loaded_msg_t;
     187             : 
     188             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, is_writable_account_cache_cap)==0, bank_abi );
     189             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, message)==24, bank_abi );
     190             : FD_STATIC_ASSERT( offsetof(sanitized_txn_abi_v0_loaded_msg_t, loaded_addresses)==136, bank_abi );
     191             : FD_STATIC_ASSERT( sizeof(sanitized_txn_abi_v0_loaded_msg_t)==184UL, bank_abi );
     192             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_v0_loaded_msg_t)==8UL, bank_abi );
     193             : 
     194             : typedef union ABI_ALIGN(8UL) {
     195             :   ulong discr;
     196             : 
     197             :   /* when discr==ABI_HIGH_BIT */
     198             :   struct ABI_ALIGN(8UL) {
     199             :     uchar _padding[8];
     200             :     sanitized_txn_abi_legacy_message1_t legacy;
     201             :   };
     202             : 
     203             :   /* else */
     204             :   /* No tag. Rust Vec's cap field (the first field in v0) is
     205             :      core::num::niche_types::UsizeNoHighBit, so this is never ambiguous. */
     206             :   sanitized_txn_abi_v0_loaded_msg_t v0;
     207             : } sanitized_txn_abi_message_t;
     208             : 
     209             : FD_STATIC_ASSERT( sizeof (sanitized_txn_abi_message_t) == 184UL, bank_abi );
     210             : FD_STATIC_ASSERT( alignof(sanitized_txn_abi_message_t) == 8UL,   bank_abi );
     211             : 
     212             : 
     213             : typedef union {
     214             :   ulong discr;
     215             :   /* When discr==1 */
     216             :   struct {
     217             :     uchar _padding[8];
     218             :     uchar _0;
     219             :     ulong _1;
     220             :   };
     221             :   /* when discr==0 */
     222             :   /* None */
     223             : } option_u8_u64_t;
     224             : FD_STATIC_ASSERT( sizeof (option_u8_u64_t)==24UL, bank_abi );
     225             : FD_STATIC_ASSERT( alignof(option_u8_u64_t)==8UL,  bank_abi );
     226             : 
     227             : 
     228             : typedef union {
     229             :   uint discr;
     230             :   /* When discr==1 */
     231             :   struct {
     232             :     uchar _padding[4];
     233             :     uchar _0;
     234             :     uint  _1;
     235             :   };
     236             :   /* when discr==0 */
     237             :   /* None */
     238             : } option_u8_u32_t;
     239             : FD_STATIC_ASSERT( sizeof (option_u8_u32_t)==12UL, bank_abi );
     240             : FD_STATIC_ASSERT( alignof(option_u8_u32_t)==4UL, bank_abi );
     241             : 
     242             : 
     243             : 
     244             : struct ABI_ALIGN(8UL) fd_bank_abi_txn_private {
     245             :   struct ABI_ALIGN(8UL) {
     246             :     struct ABI_ALIGN(8UL) {
     247             :       option_u8_u64_t requested_compute_unit_price;
     248             :       option_u8_u32_t requested_compute_unit_limit;
     249             :       option_u8_u32_t requested_heap_size;
     250             :       option_u8_u32_t requested_loaded_accounts_data_size_limit;
     251             : 
     252             :       ushort num_non_compute_budget_instructions;
     253             :       ushort num_non_migratable_builtin_instructions;
     254             :       ushort num_non_builtin_instructions;
     255             :       ushort migrating_builtin[3];
     256             :     } compute_budget_instruction_details;
     257             : 
     258             :     uchar _message_hash[ 32 ]; /* with the same value as message_hash */
     259             : 
     260             :     struct ABI_ALIGN(8UL) {
     261             :       ulong num_transaction_signatures;
     262             :       ulong num_secp256k1_instruction_signatures;
     263             :       ulong num_ed25519_instruction_signatures;
     264             :       ulong num_secp256r1_instruction_signatures;
     265             :     }; /* TransactionSignatureDetails */
     266             : 
     267             :     uchar is_simple_vote_transaction; /* same as is_simple_vote_tx */
     268             :   }; /* parts of the TransactionMeta */
     269             : 
     270             :   struct ABI_ALIGN(8UL) {
     271             :     ulong                           signatures_cap;
     272             :     sanitized_txn_abi_signature_t * signatures;
     273             :     ulong                           signatures_cnt;
     274             : 
     275             :     sanitized_txn_abi_message_t message;
     276             : 
     277             :     uchar message_hash[ 32 ];
     278             :     uchar is_simple_vote_tx;
     279             :   }; /* parts of the SanitizedTransaction */
     280             : };
     281             : 
     282             : FD_STATIC_ASSERT( sizeof (struct fd_bank_abi_txn_private)==FD_BANK_ABI_TXN_FOOTPRINT, bank_abi );
     283             : FD_STATIC_ASSERT( sizeof (struct fd_bank_abi_txn_private)==392UL, bank_abi );
     284             : FD_STATIC_ASSERT( alignof(struct fd_bank_abi_txn_private)==8UL,   bank_abi );
     285             : 
     286             : FD_STATIC_ASSERT( offsetof(struct fd_bank_abi_txn_private, signatures_cap )==144UL, bank_abi );
     287             : 
     288             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.requested_compute_unit_price)==0, bank_abi );
     289             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.requested_compute_unit_limit)==24, bank_abi );
     290             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.requested_heap_size)==36, bank_abi );
     291             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.requested_loaded_accounts_data_size_limit)==48, bank_abi );
     292             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.num_non_compute_budget_instructions)==60, bank_abi );
     293             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.num_non_migratable_builtin_instructions)==62, bank_abi );
     294             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.num_non_builtin_instructions)==64, bank_abi );
     295             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, compute_budget_instruction_details.migrating_builtin)==66, bank_abi );
     296             : 
     297             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, message)          -offsetof(struct fd_bank_abi_txn_private, signatures_cap)==24, bank_abi );
     298             : FD_STATIC_ASSERT( offsetof( struct fd_bank_abi_txn_private, message_hash)     -offsetof(struct fd_bank_abi_txn_private, signatures_cap)==208, bank_abi );
     299             : 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 );
     300             : 
     301             : static int
     302             : is_key_called_as_program( fd_txn_t const * txn,
     303           0 :                           ushort           key_index ) {
     304           0 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     305           0 :     fd_txn_instr_t const * instr = &txn->instr[ i ];
     306           0 :     if( FD_UNLIKELY( instr->program_id==key_index ) ) return 1;
     307           0 :   }
     308           0 :   return 0;
     309           0 : }
     310             : 
     311             : static const uchar BPF_UPGRADEABLE_PROG_ID1[32] = { BPF_UPGRADEABLE_PROG_ID };
     312             : 
     313             : static int
     314             : is_upgradeable_loader_present( fd_txn_t const *                   txn,
     315             :                                uchar const *                      payload,
     316           0 :                                sanitized_txn_abi_pubkey_t const * loaded_addresses ) {
     317           0 :   for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
     318           0 :     if( FD_UNLIKELY( !memcmp( payload + txn->acct_addr_off + i*32UL, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
     319           0 :   }
     320           0 :   for( ushort i=0; i<txn->addr_table_adtl_cnt; i++ ) {
     321           0 :     if( FD_UNLIKELY( !memcmp( loaded_addresses + i, BPF_UPGRADEABLE_PROG_ID1, 32UL ) ) ) return 1;
     322           0 :   }
     323           0 :   return 0;
     324           0 : }
     325             : 
     326             : extern int
     327             : fd_ext_bank_load_account( void const *  bank,
     328             :                           int           fixed_root,
     329             :                           uchar const * addr,
     330             :                           uchar *       owner,
     331             :                           uchar *       data,
     332             :                           ulong *       data_sz );
     333             : 
     334             : int
     335             : fd_bank_abi_resolve_address_lookup_tables( void const *     bank,
     336             :                                            int              fixed_root,
     337             :                                            ulong            slot,
     338             :                                            fd_txn_t const * txn,
     339             :                                            uchar const *    payload,
     340           0 :                                            fd_acct_addr_t * out_lut_accts ) {
     341           0 :   ulong writable_idx = 0UL;
     342           0 :   ulong readable_idx = 0UL;
     343           0 :   for( ulong i=0UL; i<txn->addr_table_lookup_cnt; i++ ) {
     344           0 :     fd_txn_acct_addr_lut_t const * lut = &fd_txn_get_address_tables_const( txn )[ i ];
     345           0 :     uchar const * addr = payload + lut->addr_off;
     346             : 
     347           0 :     uchar owner[ 32UL ];
     348           0 :     uchar data[ 1UL+56UL+256UL*32UL ];
     349           0 :     ulong data_sz = sizeof(data);
     350           0 :     int result = fd_ext_bank_load_account( bank, fixed_root, addr, owner, data, &data_sz );
     351           0 :     if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
     352             : 
     353           0 :     result = memcmp( owner, fd_solana_address_lookup_table_program_id.key, 32UL );
     354           0 :     if( FD_UNLIKELY( result ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_OWNER;
     355             : 
     356           0 :     if( FD_UNLIKELY( (data_sz<56UL) | (data_sz>(56UL+256UL*32UL)) ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
     357             : 
     358           0 :     fd_bincode_decode_ctx_t bincode = {
     359           0 :       .data    = data,
     360           0 :       .dataend = data+data_sz,
     361           0 :     };
     362             : 
     363           0 :     ulong total_sz = 0UL;
     364           0 :     result = fd_address_lookup_table_state_decode_footprint( &bincode, &total_sz );
     365           0 :     if( FD_UNLIKELY( result!=FD_BINCODE_SUCCESS ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
     366             : 
     367           0 :     fd_address_lookup_table_state_t table[1];
     368           0 :     fd_address_lookup_table_state_decode( table, &bincode );
     369             : 
     370           0 :     result = fd_address_lookup_table_state_is_lookup_table( table );
     371           0 :     if( FD_UNLIKELY( !result ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_UNINITIALIZED;
     372             : 
     373           0 :     if( FD_UNLIKELY( (data_sz-56UL)%32UL ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA;
     374             : 
     375           0 :     ulong addresses_len = (data_sz-56UL)/32UL;
     376           0 :     fd_acct_addr_t const * addresses = fd_type_pun_const( data+56UL );
     377             : 
     378             :     /* This logic is not currently very precise... an ALUT is allowed if
     379             :        the deactivation slot is no longer present in the slot hashes
     380             :        sysvar, which means that the slot was more than 512 *unskipped*
     381             :        slots prior.  In the current case, we are just throwing out a
     382             :        fraction of transactions that could actually still be valid
     383             :        (those deactivated between 512 and 512*(1+skip_rate) slots ago. */
     384             : 
     385           0 :     ulong deactivation_slot = table->inner.lookup_table.meta.deactivation_slot;
     386           0 :     if( FD_UNLIKELY( deactivation_slot!=ULONG_MAX && (deactivation_slot+512UL)<slot ) ) return FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND;
     387             : 
     388           0 :     ulong active_addresses_len = fd_ulong_if( slot>table->inner.lookup_table.meta.last_extended_slot,
     389           0 :                                               addresses_len,
     390           0 :                                               table->inner.lookup_table.meta.last_extended_slot_start_index );
     391           0 :     for( ulong j=0UL; j<lut->writable_cnt; j++ ) {
     392           0 :       uchar idx = payload[ lut->writable_off+j ];
     393           0 :       if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
     394           0 :       out_lut_accts[ writable_idx++ ] = addresses[ idx ];
     395           0 :     }
     396           0 :     for( ulong j=0UL; j<lut->readonly_cnt; j++ ) {
     397           0 :       uchar idx = payload[ lut->readonly_off+j ];
     398           0 :       if( FD_UNLIKELY( idx>=active_addresses_len ) ) return FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX;
     399           0 :       out_lut_accts[ txn->addr_table_adtl_writable_cnt+readable_idx++ ] = addresses[ idx ];
     400           0 :     }
     401           0 :   }
     402             : 
     403           0 :   return FD_BANK_ABI_TXN_INIT_SUCCESS;
     404           0 : }
     405             : 
     406             : #define MAP_PERFECT_NAME      precompile_table
     407             : #define MAP_PERFECT_LG_TBL_SZ 2
     408             : #define MAP_PERFECT_T         fd_acct_addr_t
     409             : #define MAP_PERFECT_KEY       b
     410             : #define MAP_PERFECT_KEY_T     fd_acct_addr_t const *
     411             : #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)
     412             : #define MAP_PERFECT_COMPLEX_KEY 1
     413           0 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
     414             : 
     415           0 : #define PERFECT_HASH( u ) (((2U*(u))>>30)&0x3U)
     416             : 
     417             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
     418             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
     419             :                                           PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
     420           0 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
     421             : 
     422             : #define MAP_PERFECT_0  ( KECCAK_SECP_PROG_ID ),
     423             : #define MAP_PERFECT_1  ( ED25519_SV_PROG_ID  ),
     424             : #define MAP_PERFECT_2  ( SECP256R1_PROG_ID   ),
     425             : 
     426             : #include "../../util/tmpl/fd_map_perfect.c"
     427             : 
     428             : /* Redefine it so we can use it below */
     429             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
     430             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
     431           0 :                                           PERFECT_HASH( ((uint)a08 | ((uint)a09<<8) | ((uint)a10<<16) | ((uint)a11<<24)) )
     432           0 : #define HASH( x ) MAP_PERFECT_HASH_PP( x )
     433             : 
     434             : FD_STATIC_ASSERT( HASH( KECCAK_SECP_PROG_ID )<3, precompile_table );
     435             : FD_STATIC_ASSERT( HASH( ED25519_SV_PROG_ID  )<3, precompile_table );
     436             : FD_STATIC_ASSERT( HASH( SECP256R1_PROG_ID   )<3, precompile_table );
     437             : 
     438             : int
     439             : fd_bank_abi_txn_init( fd_bank_abi_txn_t * out_txn,
     440             :                       uchar *             out_sidecar,
     441             :                       void const *        bank,
     442             :                       ulong               slot,
     443             :                       fd_blake3_t *       blake3,
     444             :                       uchar *             payload,
     445             :                       ulong               payload_sz,
     446             :                       fd_txn_t *          txn,
     447           0 :                       int                 is_simple_vote ) {
     448           0 :   out_txn->signatures_cnt = txn->signature_cnt;
     449           0 :   out_txn->signatures_cap = txn->signature_cnt;
     450           0 :   out_txn->signatures     = (void*)(payload + txn->signature_off);
     451             : 
     452           0 :   fd_blake3_init( blake3 );
     453           0 :   fd_blake3_append( blake3, "solana-tx-message-v1", 20UL );
     454           0 :   fd_blake3_append( blake3, payload + txn->message_off, payload_sz - txn->message_off );
     455           0 :   fd_blake3_fini( blake3, out_txn->message_hash );
     456           0 :   memcpy( out_txn->_message_hash, out_txn->message_hash, 32UL );
     457             : 
     458           0 :   out_txn->is_simple_vote_tx          = !!is_simple_vote;
     459           0 :   out_txn->is_simple_vote_transaction = !!is_simple_vote;
     460             : 
     461             :   /* ComputeBudgetInstructionDetails is only used in the method
     462             :      sanitize_and_convert_to_compute_budget_limits which never gets
     463             :      called from the code paths we invoke. */
     464           0 :   memset( &out_txn->compute_budget_instruction_details, '\0', sizeof(out_txn->compute_budget_instruction_details) );
     465             : 
     466             : 
     467           0 :   ulong sig_counters[4] = { 0UL };
     468           0 :   fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
     469           0 :   for( ulong i=0UL; i<txn->instr_cnt; i++ ) {
     470           0 :     ulong prog_id_idx = (ulong)txn->instr[i].program_id;
     471           0 :     fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
     472             : 
     473             :     /* Lookup prog_id in hash table.  If it's a miss, it'll return
     474             :        UINT_MAX which gets clamped to 3.  Otherwise, it'll be 0, 1, or
     475             :        2. */
     476           0 :     sig_counters[ fd_uint_min( 3UL, precompile_table_hash_or_default( prog_id ) ) ] +=
     477           0 :       (txn->instr[i].data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
     478           0 :   }
     479           0 :   out_txn->num_transaction_signatures = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_SIGNER );
     480           0 :   out_txn->num_secp256k1_instruction_signatures = sig_counters[ HASH( KECCAK_SECP_PROG_ID ) ];
     481           0 :   out_txn->num_ed25519_instruction_signatures = sig_counters  [ HASH( ED25519_SV_PROG_ID  ) ];
     482           0 :   out_txn->num_secp256r1_instruction_signatures = sig_counters[ HASH( SECP256R1_PROG_ID   ) ];
     483             : 
     484             : 
     485           0 :   if( FD_LIKELY( txn->transaction_version==FD_TXN_VLEGACY ) ) {
     486           0 :     sanitized_txn_abi_legacy_message1_t * legacy = &out_txn->message.legacy;
     487           0 :     sanitized_txn_abi_legacy_message0_t * message = &legacy->message.owned;
     488             : 
     489           0 :     out_txn->message.discr = ABI_HIGH_BIT;
     490             : 
     491           0 :     legacy->is_writable_account_cache_cnt = txn->acct_addr_cnt;
     492           0 :     legacy->is_writable_account_cache_cap = txn->acct_addr_cnt;
     493           0 :     legacy->is_writable_account_cache     = out_sidecar;
     494           0 :     int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, NULL );
     495           0 :     for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
     496           0 :       int is_writable = fd_txn_is_writable( txn, i ) &&
     497             :                         /* Agave does this check, but we don't need to here because pack
     498             :                            rejects these transactions before they make it to the bank.
     499             : 
     500             :                            !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
     501           0 :                         (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
     502           0 :       legacy->is_writable_account_cache[ i ] = !!is_writable;
     503           0 :     }
     504           0 :     out_sidecar += txn->acct_addr_cnt;
     505           0 :     out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
     506             : 
     507           0 :     message->account_keys_cnt = txn->acct_addr_cnt;
     508           0 :     message->account_keys_cap = txn->acct_addr_cnt;
     509           0 :     message->account_keys     = (void*)(payload + txn->acct_addr_off);
     510             : 
     511           0 :     message->instructions_cnt = txn->instr_cnt;
     512           0 :     message->instructions_cap = txn->instr_cnt;
     513           0 :     message->instructions     = (void*)out_sidecar;
     514           0 :     for( ulong i=0; i<txn->instr_cnt; i++ ) {
     515           0 :       fd_txn_instr_t * instr = &txn->instr[ i ];
     516           0 :       sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
     517             : 
     518           0 :       out_instr->accounts_cnt = instr->acct_cnt;
     519           0 :       out_instr->accounts_cap = instr->acct_cnt;
     520           0 :       out_instr->accounts     = payload + instr->acct_off;
     521             : 
     522           0 :       out_instr->data_cnt = instr->data_sz;
     523           0 :       out_instr->data_cap = instr->data_sz;
     524           0 :       out_instr->data     = payload + instr->data_off;
     525             : 
     526           0 :       out_instr->program_id_index = instr->program_id;
     527           0 :     }
     528           0 :     out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
     529             : 
     530           0 :     fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
     531           0 :     message->header.num_required_signatures        = txn->signature_cnt;
     532           0 :     message->header.num_readonly_signed_accounts   = txn->readonly_signed_cnt;
     533           0 :     message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
     534           0 :     return FD_BANK_ABI_TXN_INIT_SUCCESS;
     535           0 :   } else if( FD_LIKELY( txn->transaction_version==FD_TXN_V0 ) ){
     536           0 :     sanitized_txn_abi_v0_loaded_msg_t * v0 = &out_txn->message.v0;
     537           0 :     sanitized_txn_abi_v0_loaded_addresses_t * loaded_addresses = &v0->loaded_addresses.owned;
     538           0 :     sanitized_txn_abi_v0_message_t * message = &v0->message.owned;
     539             : 
     540           0 :     int result = fd_bank_abi_resolve_address_lookup_tables( bank, 1, slot, txn, payload, (fd_acct_addr_t*)out_sidecar );
     541           0 :     if( FD_UNLIKELY( result!=FD_BANK_ABI_TXN_INIT_SUCCESS ) ) return result;
     542             : 
     543           0 :     ulong lut_writable_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_WRITABLE_ALT );
     544           0 :     loaded_addresses->writable_cnt = lut_writable_acct_cnt;
     545           0 :     loaded_addresses->writable_cap = lut_writable_acct_cnt;
     546           0 :     loaded_addresses->writable     = (sanitized_txn_abi_pubkey_t*)out_sidecar;
     547           0 :     out_sidecar += 32UL*lut_writable_acct_cnt;
     548             : 
     549           0 :     ulong lut_readonly_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_READONLY_ALT );
     550           0 :     loaded_addresses->readable_cnt = lut_readonly_acct_cnt;
     551           0 :     loaded_addresses->readable_cap = lut_readonly_acct_cnt;
     552           0 :     loaded_addresses->readable     = (sanitized_txn_abi_pubkey_t*)out_sidecar;
     553           0 :     out_sidecar += 32UL*lut_readonly_acct_cnt;
     554             : 
     555           0 :     ulong total_acct_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALL );
     556           0 :     v0->is_writable_account_cache_cnt = total_acct_cnt;
     557           0 :     v0->is_writable_account_cache_cap = total_acct_cnt;
     558           0 :     v0->is_writable_account_cache     = out_sidecar;
     559             : 
     560             :     /* This looks like it will be an OOB read because we are passing
     561             :        just the writable account hashes, but the readable ones are
     562             :        immediately after them in memory, so it's ok. */
     563           0 :     int _is_upgradeable_loader_present = is_upgradeable_loader_present( txn, payload, loaded_addresses->writable );
     564           0 :     for( ushort i=0; i<txn->acct_addr_cnt; i++ ) {
     565           0 :       int is_writable = fd_txn_is_writable( txn, i ) &&
     566             :                         /* Agave does this check, but we don't need to here because pack
     567             :                            rejects these transactions before they make it to the bank.
     568             : 
     569             :                            !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(payload + txn->acct_addr_off + i*32UL) ) */
     570           0 :                         (!is_key_called_as_program( txn, i ) || _is_upgradeable_loader_present);
     571           0 :       v0->is_writable_account_cache[ i ] = !!is_writable;
     572           0 :     }
     573           0 :     for( ushort i=0; i<txn->addr_table_adtl_writable_cnt; i++ ) {
     574             :       /* We do need to check is_builtin_key_or_sysvar here, because pack
     575             :          has not yet loaded the address LUT accounts, so it doesn't
     576             :          reject these yet. */
     577           0 :       int is_writable = !fd_pack_unwritable_contains( (const fd_acct_addr_t*)(loaded_addresses->writable + i) ) &&
     578           0 :                         (!is_key_called_as_program( txn, (ushort)(txn->acct_addr_cnt+i) ) || _is_upgradeable_loader_present);
     579           0 :       v0->is_writable_account_cache[ txn->acct_addr_cnt+i ] = !!is_writable;
     580           0 :     }
     581           0 :     for( ushort i=0; i<txn->addr_table_adtl_cnt-txn->addr_table_adtl_writable_cnt; i++ ) {
     582           0 :       v0->is_writable_account_cache[ txn->acct_addr_cnt+txn->addr_table_adtl_writable_cnt+i ] = 0;
     583           0 :     }
     584             : 
     585           0 :     out_sidecar += txn->acct_addr_cnt + txn->addr_table_adtl_cnt;
     586           0 :     out_sidecar = (void*)fd_ulong_align_up( (ulong)out_sidecar, 8UL );
     587             : 
     588           0 :     message->account_keys_cnt = txn->acct_addr_cnt;
     589           0 :     message->account_keys_cap = txn->acct_addr_cnt;
     590           0 :     message->account_keys     = (void*)(payload + txn->acct_addr_off);
     591             : 
     592           0 :     message->instructions_cnt = txn->instr_cnt;
     593           0 :     message->instructions_cap = txn->instr_cnt;
     594           0 :     message->instructions     = (void*)out_sidecar;
     595           0 :     for( ulong i=0; i<txn->instr_cnt; i++ ) {
     596           0 :       fd_txn_instr_t * instr = &txn->instr[ i ];
     597           0 :       sanitized_txn_abi_compiled_instruction_t * out_instr = &message->instructions[ i ];
     598             : 
     599           0 :       out_instr->accounts_cnt = instr->acct_cnt;
     600           0 :       out_instr->accounts_cap = instr->acct_cnt;
     601           0 :       out_instr->accounts     = payload + instr->acct_off;
     602             : 
     603           0 :       out_instr->data_cnt = instr->data_sz;
     604           0 :       out_instr->data_cap = instr->data_sz;
     605           0 :       out_instr->data     = payload + instr->data_off;
     606             : 
     607           0 :       out_instr->program_id_index = instr->program_id;
     608           0 :     }
     609           0 :     out_sidecar += txn->instr_cnt*sizeof(sanitized_txn_abi_compiled_instruction_t);
     610             : 
     611           0 :     fd_memcpy( message->recent_blockhash, payload + txn->recent_blockhash_off, 32UL );
     612           0 :     message->header.num_required_signatures        = txn->signature_cnt;
     613           0 :     message->header.num_readonly_signed_accounts   = txn->readonly_signed_cnt;
     614           0 :     message->header.num_readonly_unsigned_accounts = txn->readonly_unsigned_cnt;
     615             : 
     616           0 :     message->address_table_lookups_cnt = txn->addr_table_lookup_cnt;
     617           0 :     message->address_table_lookups_cap = txn->addr_table_lookup_cnt;
     618           0 :     message->address_table_lookups     = (void*)out_sidecar;
     619           0 :     for( ulong i=0; i<txn->addr_table_lookup_cnt; i++ ) {
     620           0 :       fd_txn_acct_addr_lut_t const * lookup = fd_txn_get_address_tables_const( txn ) + i;
     621           0 :       sanitized_txn_abi_v0_message_address_table_lookup_t * out_lookup = &message->address_table_lookups[ i ];
     622             : 
     623           0 :       out_lookup->writable_indexes_cnt = lookup->writable_cnt;
     624           0 :       out_lookup->writable_indexes_cap = lookup->writable_cnt;
     625           0 :       out_lookup->writable_indexes     = payload + lookup->writable_off;
     626             : 
     627           0 :       out_lookup->readonly_indexes_cnt = lookup->readonly_cnt;
     628           0 :       out_lookup->readonly_indexes_cap = lookup->readonly_cnt;
     629           0 :       out_lookup->readonly_indexes     = payload + lookup->readonly_off;
     630             : 
     631           0 :       fd_memcpy( out_lookup->account_key, payload + lookup->addr_off, 32UL );
     632           0 :     }
     633           0 :     out_sidecar += txn->addr_table_lookup_cnt*sizeof(sanitized_txn_abi_v0_message_address_table_lookup_t);
     634             : 
     635           0 :     return FD_BANK_ABI_TXN_INIT_SUCCESS;
     636           0 :   } else {
     637             :     /* A program abort case, unknown transaction version should never make it here. */
     638           0 :     FD_LOG_ERR(( "unknown transaction version %u", txn->transaction_version ));
     639           0 :   }
     640           0 : }
     641             : 
     642             : fd_acct_addr_t const *
     643           0 : fd_bank_abi_get_lookup_addresses( fd_bank_abi_txn_t const * txn ) {
     644           0 :   return txn->message.discr==ABI_HIGH_BIT ? NULL :
     645           0 :     (fd_acct_addr_t const *) txn->message.v0.loaded_addresses.owned.writable;
     646           0 : }

Generated by: LCOV version 1.14