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