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_txn_account.h" 5 : #include "../fd_executor_err.h" 6 : #include "../fd_runtime_const.h" 7 : #include "../../../ballet/txn/fd_txn.h" 8 : 9 : /* While the maximum number of instruction accounts allowed for instruction 10 : execution is 256, it is entirely possible to have a transaction with more 11 : than 256 instruction accounts that passes transaction loading checks and enters 12 : `fd_execute_instr` (See mainnet transaction 13 : 3eDdfZE6HswPxFKrtnQPsEmTkyL1iP57gRPEXwaqNGAqF1paGXCYYMwh7z4uQDUMgFor742sikVSQZW1gFRDhPNh 14 : for an example). An instruction that goes into the VM with more than 256 instruction accounts 15 : will fail, but you could also theoretically invoke a native program with over 256 random 16 : unreferenced instruction accounts that will execute successfully. The true bound for the 17 : maximum number of instruction accounts you can pass in is slighly lower than the maximum 18 : possible size for a serialized transaction (1232). 19 : 20 : HOWEVER... to keep our memory footprint low, we cap the `acct_cnt` at 256 during setup since 21 : any extra accounts should (ideally) have literally 0 impact on program execution, whether 22 : or not they are present in the instr info. This keeps the transaction context size from 23 : blowing up to around 3MB in size. */ 24 0 : #define FD_INSTR_ACCT_FLAGS_IS_SIGNER (0x01U) 25 0 : #define FD_INSTR_ACCT_FLAGS_IS_WRITABLE (0x02U) 26 : 27 : /* The maximum possible size for the instruction data for any 28 : instruction, which is bounded by FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN 29 : (which is 10KB). */ 30 : #define FD_INSTR_DATA_MAX FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN 31 : 32 : struct fd_instruction_account { 33 : ushort index_in_transaction; 34 : ushort index_in_caller; 35 : ushort index_in_callee; 36 : uchar is_writable; 37 : uchar is_signer; 38 : }; 39 : 40 : typedef struct fd_instruction_account fd_instruction_account_t; 41 : 42 : struct fd_instr_info { 43 : uchar program_id; 44 : ushort acct_cnt; 45 : 46 : uchar data[ FD_INSTR_DATA_MAX ]; 47 : ushort data_sz; 48 : 49 : fd_instruction_account_t accounts[ FD_INSTR_ACCT_MAX ]; 50 : uchar is_duplicate[ FD_INSTR_ACCT_MAX ]; 51 : 52 : /* Stack height when this instruction was pushed onto the stack (including itself) */ 53 : uchar stack_height; 54 : 55 : /* TODO: convert to fd_uwide_t representation of uint_128 */ 56 : ulong starting_lamports_h; 57 : ulong starting_lamports_l; 58 : }; 59 : 60 : typedef struct fd_instr_info fd_instr_info_t; 61 : 62 : FD_PROTOTYPES_BEGIN 63 : 64 : static inline fd_instruction_account_t 65 : fd_instruction_account_init( ushort idx_in_txn, 66 : ushort idx_in_caller, 67 : ushort idx_in_callee, 68 : uchar is_writable, 69 0 : uchar is_signer ) { 70 0 : fd_instruction_account_t acc = { 71 0 : .index_in_transaction = idx_in_txn, 72 0 : .index_in_caller = idx_in_caller, 73 0 : .index_in_callee = idx_in_callee, 74 0 : .is_writable = is_writable, 75 0 : .is_signer = is_signer, 76 0 : }; 77 0 : return acc; 78 0 : } 79 : 80 : static inline void 81 : fd_instr_info_setup_instr_account( fd_instr_info_t * instr, 82 : uchar acc_idx_seen[ FD_INSTR_ACCT_MAX ], 83 : ushort idx_in_txn, 84 : ushort idx_in_caller, 85 : ushort idx_in_callee, 86 : uchar is_writable, 87 0 : uchar is_signer ) { 88 0 : if( FD_LIKELY( idx_in_txn!=USHORT_MAX ) ) { 89 0 : instr->is_duplicate[ idx_in_callee ] = acc_idx_seen[ idx_in_txn ]; 90 : 91 0 : if( FD_LIKELY( !acc_idx_seen[ idx_in_txn ] ) ) { 92 : /* This is the first time seeing this account */ 93 0 : acc_idx_seen[ idx_in_txn ] = 1; 94 0 : } 95 0 : } 96 : 97 0 : instr->accounts[ idx_in_callee ] = fd_instruction_account_init( idx_in_txn, 98 0 : idx_in_caller, 99 0 : idx_in_callee, 100 0 : is_writable, 101 0 : is_signer ); 102 0 : } 103 : 104 : /* fd_instr_info_accumulate_starting_lamports accumulates the starting lamports fields 105 : when setting up an fd_instr_info_t object. 106 : Note that the caller must zero out the starting lamports fields in fd_instr_info_t 107 : beforehand. */ 108 : 109 : void 110 : fd_instr_info_accumulate_starting_lamports( fd_instr_info_t * instr, 111 : fd_txn_out_t * txn_out, 112 : ushort idx_in_callee, 113 : ushort idx_in_txn ); 114 : 115 : void 116 : fd_instr_info_init_from_txn_instr( fd_instr_info_t * instr, 117 : fd_bank_t * bank, 118 : fd_txn_in_t const * txn_in, 119 : fd_txn_out_t * txn_out, 120 : fd_txn_instr_t const * txn_instr ); 121 : 122 : /* https://github.com/anza-xyz/solana-sdk/blob/589e6237f203c2719c300dc044f4e00f48e66a8f/message/src/versions/v0/loaded.rs#L152-L157 */ 123 : FD_FN_PURE static inline int 124 : fd_instr_acc_is_writable_idx( fd_instr_info_t const * instr, 125 0 : ushort idx ) { 126 0 : if( FD_UNLIKELY( idx>=instr->acct_cnt ) ) { 127 0 : return 0; 128 0 : } 129 : 130 0 : return !!(instr->accounts[idx].is_writable); 131 0 : } 132 : 133 : /* fd_instr_acc_is_signer_idx returns: 134 : - 1 if account is signer 135 : - 0 (with *out_opt_err==0) if account is not signer 136 : If an error occurs during query, returns 0 and writes the 137 : error code to *out_opt_err. Possible values for out_opt_err: 138 : - FD_EXECUTOR_INSTR_ERR_MISSING_ACC occurs when the instr account 139 : index provided is invalid (out of bounds). 140 : - 0 if the query was successful. Check the return value to see 141 : if the account is a signer. 142 : 143 : https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L782-L791 */ 144 : FD_FN_PURE static inline int 145 : fd_instr_acc_is_signer_idx( fd_instr_info_t const * instr, 146 : ushort idx, 147 0 : int * out_opt_err ) { 148 0 : if( FD_UNLIKELY( idx>=instr->acct_cnt ) ) { 149 0 : if( out_opt_err ) *out_opt_err = FD_EXECUTOR_INSTR_ERR_MISSING_ACC; 150 0 : return 0; 151 0 : } 152 : 153 0 : if( out_opt_err ) *out_opt_err = 0; 154 0 : return !!(instr->accounts[idx].is_signer); 155 0 : } 156 : 157 : /* fd_instr_info_sum_account_lamports returns the sum of lamport account 158 : balances of all instruction accounts in the context. 159 : 160 : Aborts on integer overflow. */ 161 : 162 : int 163 : fd_instr_info_sum_account_lamports( fd_instr_info_t const * instr, 164 : fd_txn_out_t * txn_out, 165 : ulong * total_lamports_h, 166 : ulong * total_lamports_l ); 167 : 168 : FD_PROTOTYPES_END 169 : 170 : #endif /* HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h */