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_executor_err.h" 5 : #include "../fd_runtime_const.h" 6 : #include "../../../ballet/txn/fd_txn.h" 7 : 8 0 : #define FD_INSTR_ACCT_FLAGS_IS_SIGNER (0x01U) 9 0 : #define FD_INSTR_ACCT_FLAGS_IS_WRITABLE (0x02U) 10 : 11 : /* The maximum possible size for the instruction data for any 12 : instruction, which is bounded by FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN 13 : (which is 10KB). */ 14 : #define FD_INSTR_DATA_MAX FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN 15 : 16 : struct fd_instruction_account { 17 : ushort index_in_transaction; 18 : ushort index_in_caller; 19 : ushort index_in_callee; 20 : uchar is_writable; 21 : uchar is_signer; 22 : }; 23 : 24 : typedef struct fd_instruction_account fd_instruction_account_t; 25 : 26 : struct fd_instr_info { 27 : uchar program_id; 28 : ushort acct_cnt; 29 : 30 : uchar data[ FD_INSTR_DATA_MAX ]; 31 : ushort data_sz; 32 : 33 : fd_instruction_account_t accounts[ FD_TXN_INSTR_ACCT_MAX ]; 34 : uchar is_duplicate[ FD_TXN_INSTR_ACCT_MAX ]; 35 : 36 : /* Stack height when this instruction was pushed onto the stack (including itself) */ 37 : uchar stack_height; 38 : 39 : /* TODO: convert to fd_uwide_t representation of uint_128 */ 40 : ulong starting_lamports_h; 41 : ulong starting_lamports_l; 42 : }; 43 : 44 : typedef struct fd_instr_info fd_instr_info_t; 45 : 46 : FD_PROTOTYPES_BEGIN 47 : 48 : static inline fd_instr_info_t * 49 0 : fd_instr_info_new( fd_instr_info_t * instr ) { 50 0 : if( FD_UNLIKELY( !instr ) ) return NULL; 51 : 52 0 : instr->program_id = UCHAR_MAX; 53 0 : instr->acct_cnt = 0U; 54 0 : instr->data_sz = 0U; 55 0 : instr->stack_height = 0U; 56 0 : instr->starting_lamports_h = 0UL; 57 0 : instr->starting_lamports_l = 0UL; 58 : 59 0 : return instr; 60 0 : } 61 : 62 : static inline fd_instruction_account_t 63 : fd_instruction_account_init( ushort idx_in_txn, 64 : ushort idx_in_caller, 65 : ushort idx_in_callee, 66 : uchar is_writable, 67 23955 : uchar is_signer ) { 68 23955 : fd_instruction_account_t acc = { 69 23955 : .index_in_transaction = idx_in_txn, 70 23955 : .index_in_caller = idx_in_caller, 71 23955 : .index_in_callee = idx_in_callee, 72 23955 : .is_writable = is_writable, 73 23955 : .is_signer = is_signer, 74 23955 : }; 75 23955 : return acc; 76 23955 : } 77 : 78 : static inline void 79 : fd_instr_info_setup_instr_account( fd_instr_info_t * instr, 80 : uchar acc_idx_seen[ FD_TXN_ACCT_ADDR_MAX ], 81 : ushort idx_in_txn, 82 : ushort idx_in_caller, 83 : ushort idx_in_callee, 84 : uchar is_writable, 85 15297 : uchar is_signer ) { 86 15297 : if( FD_LIKELY( idx_in_txn!=USHORT_MAX ) ) { 87 15297 : instr->is_duplicate[ idx_in_callee ] = acc_idx_seen[ idx_in_txn ]; 88 : 89 15297 : if( FD_LIKELY( !acc_idx_seen[ idx_in_txn ] ) ) { 90 : /* This is the first time seeing this account */ 91 13131 : acc_idx_seen[ idx_in_txn ] = 1; 92 13131 : } 93 15297 : } 94 : 95 15297 : instr->accounts[ idx_in_callee ] = fd_instruction_account_init( idx_in_txn, 96 15297 : idx_in_caller, 97 15297 : idx_in_callee, 98 15297 : is_writable, 99 15297 : is_signer ); 100 15297 : } 101 : 102 : void 103 : fd_instr_info_init_from_txn_instr( fd_instr_info_t * instr, 104 : fd_txn_in_t const * txn_in, 105 : fd_txn_out_t * txn_out, 106 : fd_txn_instr_t const * txn_instr ); 107 : 108 : /* https://github.com/anza-xyz/solana-sdk/blob/589e6237f203c2719c300dc044f4e00f48e66a8f/message/src/versions/v0/loaded.rs#L152-L157 */ 109 : FD_FN_PURE static inline int 110 : fd_instr_acc_is_writable_idx( fd_instr_info_t const * instr, 111 22383 : ushort idx ) { 112 22383 : if( FD_UNLIKELY( idx>=instr->acct_cnt ) ) { 113 0 : return 0; 114 0 : } 115 : 116 22383 : return !!(instr->accounts[idx].is_writable); 117 22383 : } 118 : 119 : /* fd_instr_acc_is_signer_idx returns: 120 : - 1 if account is signer 121 : - 0 (with *out_opt_err==0) if account is not signer 122 : If an error occurs during query, returns 0 and writes the 123 : error code to *out_opt_err. Possible values for out_opt_err: 124 : - FD_EXECUTOR_INSTR_ERR_MISSING_ACC occurs when the instr account 125 : index provided is invalid (out of bounds). 126 : - 0 if the query was successful. Check the return value to see 127 : if the account is a signer. 128 : 129 : https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L770-L779 */ 130 : static inline int 131 : fd_instr_acc_is_signer_idx( fd_instr_info_t const * instr, 132 : ushort idx, 133 5112 : int * out_opt_err ) { 134 5112 : if( FD_UNLIKELY( idx>=instr->acct_cnt ) ) { 135 0 : if( out_opt_err ) *out_opt_err = FD_EXECUTOR_INSTR_ERR_MISSING_ACC; 136 0 : return 0; 137 0 : } 138 : 139 5112 : if( out_opt_err ) *out_opt_err = 0; 140 5112 : return !!(instr->accounts[idx].is_signer); 141 5112 : } 142 : 143 : /* fd_instr_info_sum_account_lamports calculates the sum of lamports 144 : account balances of all instruction accounts in the context, 145 : outputting the result in total_lamports_h and total_lamports_l. 146 : 147 : Returns FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW on arithmetic 148 : overflow, otherwise FD_EXECUTOR_INSTR_SUCCESS */ 149 : 150 : int 151 : fd_instr_info_sum_account_lamports( fd_instr_info_t const * instr, 152 : fd_txn_out_t * txn_out, 153 : ulong * total_lamports_h, 154 : ulong * total_lamports_l ); 155 : 156 : FD_PROTOTYPES_END 157 : 158 : #endif /* HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h */