Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h 2 : #define HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h 3 : 4 : #include "../../fd_flamenco_base.h" 5 : #include "../../types/fd_types.h" 6 : #include "../fd_txn_account.h" 7 : // TODO: rename to _MASK 8 0 : #define FD_INSTR_ACCT_FLAGS_IS_SIGNER (0x01U) 9 0 : #define FD_INSTR_ACCT_FLAGS_IS_WRITABLE (0x02U) 10 : 11 : /* While the maximum number of instruction accounts allowed for instruction 12 : execution is 256, it is entirely possible to have a transaction with more 13 : than 256 instruction accounts that passes transaction loading checks and enters 14 : `fd_execute_instr` (See mainnet transaction 15 : 3eDdfZE6HswPxFKrtnQPsEmTkyL1iP57gRPEXwaqNGAqF1paGXCYYMwh7z4uQDUMgFor742sikVSQZW1gFRDhPNh 16 : for an example). An instruction that goes into the VM with more than 256 instruction accounts 17 : will fail, but you could also theoretically invoke a native program with over 256 random 18 : unreferenced instruction accounts that will execute successfully. The true bound for the 19 : maximum number of instruction accounts you can pass in is slighly lower than the maximum 20 : possible size for a serialized transaction (1232). 21 : 22 : HOWEVER... to keep our memory footprint low, we cap the `acct_cnt` at 256 during setup since 23 : any extra accounts should (ideally) have literally 0 impact on program execution, whether 24 : or not they are present in the instr info. This keeps the transaction context size from 25 : blowing up to around 3MB in size. */ 26 0 : #define FD_INSTR_ACCT_MAX (256) 27 : 28 : struct fd_instr_info { 29 : uchar program_id; 30 : ushort data_sz; 31 : ushort acct_cnt; 32 : 33 : uchar * data; 34 : fd_pubkey_t program_id_pubkey; 35 : 36 : uchar acct_txn_idxs[FD_INSTR_ACCT_MAX]; 37 : uchar acct_flags[FD_INSTR_ACCT_MAX]; 38 : fd_pubkey_t acct_pubkeys[FD_INSTR_ACCT_MAX]; 39 : uchar is_duplicate[FD_INSTR_ACCT_MAX]; 40 : 41 : /* Indexed by index in instruction, not by index in transaction. */ 42 : fd_txn_account_t * accounts[FD_INSTR_ACCT_MAX]; 43 : 44 : /* fd_uwide representation of uint_128 */ 45 : ulong starting_lamports_h; 46 : ulong starting_lamports_l; 47 : }; 48 : 49 : typedef struct fd_instr_info fd_instr_info_t; 50 : 51 : FD_PROTOTYPES_BEGIN 52 : 53 : void 54 : fd_convert_txn_instr_to_instr( fd_exec_txn_ctx_t * txn_ctx, 55 : fd_txn_instr_t const * txn_instr, 56 : fd_txn_account_t * accts, 57 : fd_instr_info_t * instr ); 58 : 59 : FD_FN_PURE static inline int 60 : fd_instr_acc_is_writable_idx( fd_instr_info_t const * instr, 61 0 : ulong idx ) { 62 0 : return !!(instr->acct_flags[idx] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE); 63 0 : } 64 : 65 : static inline int 66 0 : fd_instr_acc_is_writable(fd_instr_info_t const * instr, fd_pubkey_t const * acc) { 67 0 : for( uchar i = 0; i < instr->acct_cnt; i++ ) { 68 0 : if( memcmp( &instr->acct_pubkeys[i], acc, sizeof( fd_pubkey_t ) )==0 ) { 69 0 : return fd_instr_acc_is_writable_idx( instr, i ); 70 0 : } 71 0 : } 72 : 73 0 : return 0; 74 0 : } 75 : 76 : FD_FN_PURE static inline int 77 : fd_instr_acc_is_signer_idx( fd_instr_info_t const * instr, 78 0 : ulong idx ) { 79 0 : return !!(instr->acct_flags[idx] & FD_INSTR_ACCT_FLAGS_IS_SIGNER); 80 0 : } 81 : 82 : static inline int 83 0 : fd_instr_acc_is_signer(fd_instr_info_t const * instr, fd_pubkey_t const * acc) { 84 0 : for( uchar i = 0; i < instr->acct_cnt; i++ ) { 85 0 : if( memcmp( &instr->acct_pubkeys[i], acc, sizeof( fd_pubkey_t ) )==0 ) { 86 0 : return fd_instr_acc_is_signer_idx( instr, i ); 87 0 : } 88 0 : } 89 : 90 0 : return 0; 91 0 : } 92 : 93 : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L35-L41 94 : 95 : fd_instr_any_signed matches 96 : solana_system_program::system_processor::Address::is_signer 97 : Scans instruction accounts for matching signer. 98 : 99 : Returns 1 if *any* instruction account with the given pubkey is a 100 : signer and 0 otherwise. Note that the same account/pubkey can be 101 : specified as multiple different instruction accounts that might not 102 : all have the signer bit. */ 103 : 104 : FD_FN_PURE int 105 : fd_instr_any_signed( fd_instr_info_t const * info, 106 : fd_pubkey_t const * pubkey ); 107 : 108 : /* fd_instr_info_sum_account_lamports returns the sum of lamport account 109 : balances of all instruction accounts in the context. 110 : 111 : Aborts on integer overflow. */ 112 : 113 : int 114 : fd_instr_info_sum_account_lamports( fd_instr_info_t const * instr, 115 : ulong * total_lamports_h, 116 : ulong * total_lamports_l ); 117 : 118 : static inline void 119 : fd_instr_get_signers( fd_instr_info_t const * self, 120 0 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) { 121 0 : ulong j = 0UL; 122 0 : for( uchar i = 0; i < self->acct_cnt && j < FD_TXN_SIG_MAX; i++ ) 123 0 : if( fd_instr_acc_is_signer_idx( self, i ) ) 124 0 : signers[j++] = &self->acct_pubkeys[i]; 125 0 : } 126 : 127 : /* Loop conditions could be optimized to allow for unroll/vectorize */ 128 : 129 : static inline int 130 : fd_instr_signers_contains( fd_pubkey_t const * signers[FD_TXN_SIG_MAX], 131 0 : fd_pubkey_t const * pubkey ) { 132 0 : for( ulong i = 0; i < FD_TXN_SIG_MAX && signers[i]; i++ ) 133 0 : if( 0==memcmp( signers[i], pubkey, sizeof( fd_pubkey_t ) ) ) return 1; 134 0 : return 0; 135 0 : } 136 : 137 : FD_PROTOTYPES_END 138 : 139 : #endif /* HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h */