Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_context_fd_exec_instr_ctx_h 2 : #define HEADER_fd_src_flamenco_runtime_context_fd_exec_instr_ctx_h 3 : 4 : #include "../info/fd_instr_info.h" 5 : #include "../fd_executor_err.h" 6 : #include "../sysvar/fd_sysvar_cache.h" 7 : #include "../../fd_flamenco_base.h" 8 : #include "../../../ballet/txn/fd_txn.h" 9 : 10 : /* Avoid circular include dependency with forward declaration */ 11 : struct fd_borrowed_account; 12 : typedef struct fd_borrowed_account fd_borrowed_account_t; 13 : 14 : /* fd_exec_instr_ctx_t is the context needed to execute a single 15 : instruction (program invocation). */ 16 : 17 : struct fd_exec_instr_ctx { 18 : fd_instr_info_t const * instr; /* The instruction info for this instruction */ 19 : fd_runtime_t * runtime; /* The runtime for this instruction */ 20 : fd_txn_in_t const * txn_in; /* The input for this instruction */ 21 : fd_txn_out_t * txn_out; /* The output for this instruction */ 22 : fd_sysvar_cache_t const * sysvar_cache; 23 : fd_bank_t * bank; 24 : 25 : /* Most instructions log the base58 program id multiple times, so it's 26 : convenient to compute it once and reuse it. */ 27 : char program_id_base58[ FD_BASE58_ENCODED_32_SZ ]; 28 : }; 29 : 30 : #define FD_EXEC_INSTR_CTX_ALIGN (alignof(fd_exec_instr_ctx_t)) 31 : #define FD_EXEC_INSTR_CTX_FOOTPRINT (sizeof (fd_exec_instr_ctx_t)) 32 : 33 : /* Be careful when using this macro. There may be places where the error 34 : will need to be handled differently. */ 35 73110 : #define FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, idx, acc ) do { \ 36 73110 : int err = fd_exec_instr_ctx_try_borrow_instr_account( ctx, idx, acc ); \ 37 73110 : if( FD_UNLIKELY( err ) ) return err; \ 38 73110 : } while (0) 39 : 40 : FD_PROTOTYPES_BEGIN 41 : 42 : /* Operators */ 43 : 44 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::check_number_of_instruction_accounts 45 : 46 : Assert that enough accounts were supplied to this instruction. Returns 47 : FD_EXECUTOR_INSTR_SUCCESS if the number of accounts is as expected and 48 : FD_EXECUTOR_INSTR_ERR_MISSING_ACC otherwise. 49 : 50 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L490 */ 51 : 52 : static inline int 53 : fd_exec_instr_ctx_check_num_insn_accounts( fd_exec_instr_ctx_t const * ctx, 54 4567 : uint expected_accounts ) { 55 : 56 4567 : if( FD_UNLIKELY( ctx->instr->acct_cnt<expected_accounts ) ) { 57 7 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC; 58 7 : } 59 4560 : return FD_EXECUTOR_INSTR_SUCCESS; 60 4567 : } 61 : 62 : /* fd_exec_instr_ctx_instr_account_map fills map with, for each 63 : transaction account index, the first index of that account in the 64 : instruction, or USHORT_MAX. Transaction keys are unique, so 65 : map[ fd_runtime_find_index_of_account( pubkey ) ] is the index of 66 : pubkey in the instruction. */ 67 : 68 : void 69 : fd_exec_instr_ctx_instr_account_map( fd_exec_instr_ctx_t const * ctx, 70 : ushort map[ MAX_TX_ACCOUNT_LOCKS ] ); 71 : 72 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::get_index_of_instruction_account_in_transaction 73 : 74 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L552 */ 75 : 76 : static inline int 77 : fd_exec_instr_ctx_get_index_of_instr_account_in_transaction( fd_exec_instr_ctx_t const * ctx, 78 : ushort idx_in_instr, 79 251644 : ushort * idx_in_txn ) { 80 251644 : if( FD_UNLIKELY( idx_in_instr==USHORT_MAX ) ) { 81 1 : *idx_in_txn = USHORT_MAX; 82 1 : return FD_EXECUTOR_INSTR_SUCCESS; 83 1 : } 84 : 85 : /* Return a NotEnoughAccountKeys error if the idx is out of bounds. 86 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L559 */ 87 251643 : if( FD_UNLIKELY( idx_in_instr>=ctx->instr->acct_cnt ) ) { 88 173 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC; 89 173 : } 90 : 91 251470 : *idx_in_txn = ctx->instr->accounts[ idx_in_instr ].index_in_transaction; 92 251470 : return FD_EXECUTOR_INSTR_SUCCESS; 93 251643 : } 94 : 95 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::get_number_of_program_accounts. 96 : 97 : Strictly returns 1, as we only support one program account per instruction. 98 : 99 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L480-L482 */ 100 : 101 : static inline ushort 102 0 : fd_exec_instr_ctx_get_number_of_program_accounts( fd_exec_instr_ctx_t const * ctx ) { 103 0 : (void) ctx; 104 0 : return 1U; 105 0 : } 106 : 107 : /* A helper function to get the pubkey of an account using its instruction context index */ 108 : int 109 : fd_exec_instr_ctx_get_key_of_account_at_index( fd_exec_instr_ctx_t const * ctx, 110 : ushort idx_in_instr, 111 : fd_pubkey_t const * * key ); 112 : 113 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::get_last_program_key. 114 : 115 : There can only be one program per instruction, so this function simply retrieves 116 : that program's pubkey, despite the name implying multiple programs per instruction. 117 : The function exists to match semantics with Agave. 118 : 119 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L582 */ 120 : 121 : int 122 : fd_exec_instr_ctx_get_last_program_key( fd_exec_instr_ctx_t const * ctx, 123 : fd_pubkey_t const * * key ); 124 : 125 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::try_borrow_account. 126 : 127 : Borrows an account from the instruction context with a given account index. 128 : 129 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L594 */ 130 : 131 : int 132 : fd_exec_instr_ctx_try_borrow_instr_account( fd_exec_instr_ctx_t const * ctx, 133 : ushort idx, 134 : fd_borrowed_account_t * account ); 135 : 136 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::try_borrow_last_program_account 137 : 138 : Borrows the instruction's program account. Since there is only one program account per 139 : instruction, this function simply borrows the instruction's only program account, despite the name. 140 : 141 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L616 */ 142 : 143 : int 144 : fd_exec_instr_ctx_try_borrow_last_program_account( fd_exec_instr_ctx_t const * ctx, 145 : fd_borrowed_account_t * account ); 146 : 147 : /* Mirrors Agave function solana_sdk::transaction_context::InstructionContext::get_signers 148 : 149 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L684 */ 150 : 151 : int 152 : fd_exec_instr_ctx_get_signers( fd_exec_instr_ctx_t const * ctx, 153 : fd_pubkey_t const * signers[ static FD_INSTR_SIGNERS_MAX ], 154 : ulong * signers_cnt ); 155 : 156 : /* fd_exec_instr_ctx_any_signed matches 157 : solana_system_program::system_processor::Address::is_signer 158 : 159 : Scans instruction accounts for matching signer. 160 : 161 : Returns 1 if *any* instruction account with the given pubkey is a 162 : signer and 0 otherwise. Note that the same account/pubkey can be 163 : specified as multiple different instruction accounts that might not 164 : all have the signer bit. 165 : 166 : https://github.com/anza-xyz/agave/blob/v2.1.14/programs/system/src/system_processor.rs#L35-L41 */ 167 : 168 : FD_FN_PURE int 169 : fd_exec_instr_ctx_any_signed( fd_exec_instr_ctx_t const * ctx, 170 : fd_pubkey_t const * pubkey ); 171 : 172 : /* Although fd_signers_contains does not take an instruction context, 173 : it is included here for relevance to signer helper functions 174 : 175 : Loop conditions could be optimized to allow for unroll/vectorize */ 176 : 177 : static inline int 178 : fd_signers_contains( fd_pubkey_t const * signers[ static FD_INSTR_SIGNERS_MAX ], 179 : ulong signers_cnt, 180 13801 : fd_pubkey_t const * pubkey ) { 181 26125 : for( ulong i=0; i<signers_cnt; i++ ) 182 15742 : if( 0==memcmp( signers[i], pubkey, sizeof( fd_pubkey_t ) ) ) return 1; 183 10383 : return 0; 184 13801 : } 185 : 186 : FD_PROTOTYPES_END 187 : 188 : #endif /* HEADER_fd_src_flamenco_runtime_context_fd_exec_instr_ctx_h */