diff --git a/contrib/test/test-vectors-commit-sha.txt b/contrib/test/test-vectors-commit-sha.txt index 125748085a..e7696069f7 100644 --- a/contrib/test/test-vectors-commit-sha.txt +++ b/contrib/test/test-vectors-commit-sha.txt @@ -1 +1 @@ -3040262e57e97af58ade353ac3f32c9f7f181d8b +155ea679befde81a71977eaf8ebf20a23d6d1fc3 diff --git a/src/discof/exec/fd_exec_tile.c b/src/discof/exec/fd_exec_tile.c index 384c3bccd7..42c2dc17ab 100644 --- a/src/discof/exec/fd_exec_tile.c +++ b/src/discof/exec/fd_exec_tile.c @@ -128,8 +128,9 @@ returnable_frag( fd_exec_tile_ctx_t * ctx, fd_exec_txn_exec_msg_t * msg = fd_chunk_to_laddr( ctx->replay_in->mem, chunk ); ctx->bank = fd_banks_bank_query( ctx->banks, msg->bank_idx ); FD_TEST( ctx->bank ); - ctx->txn_in.txn = &msg->txn; - ctx->txn_in.exec_accounts = &ctx->exec_accounts; + ctx->txn_in.txn = &msg->txn; + ctx->txn_in.exec_accounts = &ctx->exec_accounts; + ctx->runtime->log.capture_ctx = ctx->capture_ctx; fd_runtime_prepare_and_execute_txn( ctx->runtime, ctx->bank, &ctx->txn_in, &ctx->txn_out ); diff --git a/src/flamenco/runtime/fd_executor.c b/src/flamenco/runtime/fd_executor.c index 2f824d1e68..e08f1402b2 100644 --- a/src/flamenco/runtime/fd_executor.c +++ b/src/flamenco/runtime/fd_executor.c @@ -405,22 +405,6 @@ fd_executor_verify_transaction( fd_bank_t * bank, return FD_RUNTIME_EXECUTE_SUCCESS; } -static void -fd_executor_setup_instr_infos_from_txn_instrs( fd_runtime_t * runtime, - fd_bank_t * bank, - fd_txn_in_t const * txn_in, - fd_txn_out_t * txn_out ) { - ushort instr_cnt = TXN( txn_in->txn )->instr_cnt; - - /* Set up the instr infos for the transaction */ - for( ushort i=0; itxn )->instr[i]; - fd_instr_info_init_from_txn_instr( &runtime->instr.infos[i], bank, txn_in, txn_out, instr ); - } - - runtime->instr.info_cnt = instr_cnt; -} - /* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/account_loader.rs#L410-427 */ static int accumulate_and_check_loaded_account_data_size( ulong acc_size, @@ -456,8 +440,7 @@ accumulate_and_check_loaded_account_data_size( ulong acc_size, https://github.com/anza-xyz/agave/blob/v2.3.1/svm/src/account_loader.rs#L199-L228 */ static ulong -load_transaction_account( fd_runtime_t * runtime, - fd_bank_t * bank, +load_transaction_account( fd_bank_t * bank, fd_txn_in_t const * txn_in, fd_txn_out_t * txn_out, fd_txn_account_t * acct, @@ -472,7 +455,7 @@ load_transaction_account( fd_runtime_t * runtime, constructed by the SVM and modified within each transaction's instruction execution only, so it incurs a loaded size cost of 0. */ - fd_sysvar_instructions_serialize_account( txn_in, txn_out, (fd_instr_info_t const *)runtime->instr.infos, TXN( txn_in->txn )->instr_cnt, txn_idx ); + fd_sysvar_instructions_serialize_account( bank, txn_in, txn_out, txn_idx ); return 0UL; } @@ -549,7 +532,7 @@ fd_executor_load_transaction_accounts_old( fd_runtime_t * runtime, } /* https://github.com/anza-xyz/agave/blob/v2.3.1/svm/src/account_loader.rs#L733-L740 */ - ulong loaded_acc_size = load_transaction_account( runtime, bank, txn_in, txn_out, acct, is_writable, unknown_acc, i ); + ulong loaded_acc_size = load_transaction_account( bank, txn_in, txn_out, acct, is_writable, unknown_acc, i ); int err = accumulate_and_check_loaded_account_data_size( loaded_acc_size, requested_loaded_accounts_data_size, &txn_out->details.loaded_accounts_data_size ); @@ -816,7 +799,7 @@ fd_executor_load_transaction_accounts_simd_186( fd_runtime_t * runtime, /* Load and collect any remaining accounts https://github.com/anza-xyz/agave/blob/v2.3.1/svm/src/account_loader.rs#L652-L659 */ - ulong loaded_acc_size = load_transaction_account( runtime, bank, txn_in, txn_out, acct, is_writable, unknown_acc, i ); + ulong loaded_acc_size = load_transaction_account( bank, txn_in, txn_out, acct, is_writable, unknown_acc, i ); int err = fd_collect_loaded_account( runtime, txn_out, @@ -1160,11 +1143,13 @@ fd_txn_ctx_push( fd_runtime_t * runtime, } } - /* https://github.com/anza-xyz/agave/blob/c4b42ab045860d7b13b3912eafb30e6d2f4e593f/sdk/src/transaction_context.rs#L347-L351 */ - if( FD_UNLIKELY( runtime->instr.trace_length>=FD_MAX_INSTRUCTION_TRACE_LENGTH ) ) { + /* Note that we don't update the trace length here - since the caller + allocates out of the trace array, they are also responsible for + incrementing the trace length variable. + https://github.com/anza-xyz/agave/blob/c4b42ab045860d7b13b3912eafb30e6d2f4e593f/sdk/src/transaction_context.rs#L347-L351 */ + if( FD_UNLIKELY( runtime->instr.trace_length>FD_MAX_INSTRUCTION_TRACE_LENGTH ) ) { return FD_EXECUTOR_INSTR_ERR_MAX_INSN_TRACE_LENS_EXCEEDED; } - runtime->instr.trace_length++; /* https://github.com/anza-xyz/agave/blob/c4b42ab045860d7b13b3912eafb30e6d2f4e593f/sdk/src/transaction_context.rs#L352-L356 */ if( FD_UNLIKELY( runtime->instr.stack_sz>=FD_MAX_INSTRUCTION_STACK_DEPTH ) ) { @@ -1342,11 +1327,6 @@ fd_execute_instr( fd_runtime_t * runtime, }; fd_base58_encode_32( txn_out->accounts.accounts[ instr->program_id ].pubkey->uc, NULL, ctx->program_id_base58 ); - runtime->instr.trace[ runtime->instr.trace_length - 1 ] = (fd_exec_instr_trace_entry_t) { - .instr_info = instr, - .stack_height = runtime->instr.stack_sz, - }; - /* Look up the native program. We check for precompiles within the lookup function as well. https://github.com/anza-xyz/agave/blob/v2.1.6/svm/src/message_processor.rs#L88 */ fd_exec_instr_fn_t native_prog_fn; @@ -1588,9 +1568,6 @@ fd_executor_setup_accounts_for_txn( fd_runtime_t * runtime, txn_out->accounts.nonce_idx_in_txn = ULONG_MAX; runtime->executable.cnt = executable_idx; - - /* Set up instr infos from the txn descriptor. No Agave equivalent to this function. */ - fd_executor_setup_instr_infos_from_txn_instrs( runtime, bank, txn_in, txn_out ); } int @@ -1620,19 +1597,34 @@ fd_execute_txn( fd_runtime_t * runtime, bool dump_insn = runtime->log.capture_ctx && fd_bank_slot_get( bank ) >= runtime->log.capture_ctx->dump_proto_start_slot && runtime->log.capture_ctx->dump_instr_to_pb; (void)dump_insn; + fd_txn_t const * txn = TXN( txn_in->txn ); + /* Initialize log collection. */ fd_log_collector_init( runtime->log.log_collector, runtime->log.enable_log_collector ); for( ushort i=0; itxn )->instr_cnt; i++ ) { - runtime->instr.current_idx = i; + /* Set up the instr info for the current instruction */ + fd_instr_info_t * instr_info = &runtime->instr.trace[runtime->instr.trace_length++]; + fd_instr_info_init_from_txn_instr( + instr_info, + bank, + txn_in, + txn_out, + &txn->instr[i] + ); + # if FD_HAS_FLATCC if( FD_UNLIKELY( dump_insn ) ) { // Capture the input and convert it into a Protobuf message - fd_dump_instr_to_protobuf( runtime, bank, txn_in, txn_out, &runtime->instr.infos[i], i ); + fd_dump_instr_to_protobuf( runtime, bank, txn_in, txn_out, instr_info, i ); } # endif - int instr_exec_result = fd_execute_instr( runtime, bank, txn_in, txn_out, &runtime->instr.infos[i] ); + /* Update the current executing instruction index */ + runtime->instr.current_idx = i; + + /* Execute the current instruction */ + int instr_exec_result = fd_execute_instr( runtime, bank, txn_in, txn_out, instr_info ); if( FD_UNLIKELY( instr_exec_result!=FD_EXECUTOR_INSTR_SUCCESS ) ) { if( txn_out->err.exec_err_idx==INT_MAX ) { txn_out->err.exec_err_idx = i; diff --git a/src/flamenco/runtime/fd_runtime.c b/src/flamenco/runtime/fd_runtime.c index 4854c58ec4..651724f124 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -1341,7 +1341,6 @@ fd_runtime_prepare_and_execute_txn( fd_runtime_t * runtime, runtime->executable.cnt = 0UL; runtime->log.enable_log_collector = 0; - runtime->instr.info_cnt = 0UL; runtime->instr.trace_length = 0UL; runtime->instr.current_idx = 0; runtime->instr.stack_sz = 0; diff --git a/src/flamenco/runtime/fd_runtime.h b/src/flamenco/runtime/fd_runtime.h index 0d89225d70..0ef64179ce 100644 --- a/src/flamenco/runtime/fd_runtime.h +++ b/src/flamenco/runtime/fd_runtime.h @@ -13,22 +13,19 @@ struct fd_runtime { uchar stack_sz; /* Current depth of the instruction execution stack. */ fd_exec_instr_ctx_t stack[ FD_MAX_INSTRUCTION_STACK_DEPTH ]; /* Instruction execution stack. */ /* The memory for all of the instructions in the transaction - (including CPI instructions) are preallocated. However, the order - in which the instructions are executed does not match the order in - which they are allocated. The instr_trace will instead be used to - track the order in which the instructions are executed. We leave - space for an extra instruction to account for the case where the - transaction has too many instructions leading to - FD_EXECUTOR_INSTR_ERR_MAX_INSN_TRACE_LENS_EXCEEDED. - TODO: In reality, we should just be allocating instr_infos per - instruction and not up front. The dependency on using instr_info - for the sysvar instruction setup is not needed and should be - removed. At this point, instr_info and instr_trace should be - combined. */ - fd_instr_info_t infos[ FD_MAX_INSTRUCTION_TRACE_LENGTH * 2UL ]; - ulong info_cnt; - fd_exec_instr_trace_entry_t trace[ FD_MAX_INSTRUCTION_TRACE_LENGTH ]; /* Instruction trace */ - ulong trace_length; /* Number of instructions in the trace */ + (including CPI instructions) are preallocated. However, the + order in which the instructions are executed does not match the + order in which they are allocated. The instr_trace will instead + be used to track the order in which the instructions are + executed. We add a +1 to allow any instructions past the max + instr trace limit to be safely allocated, so that we can fail + out like Agave does later at the stack push step within + fd_execute_instr. + + The caller is responsible for updating the trace_length for the + callee. */ + fd_instr_info_t trace[ FD_MAX_INSTRUCTION_TRACE_LENGTH+1UL ]; + ulong trace_length; /* The current instruction index being executed */ int current_idx; } instr; diff --git a/src/flamenco/runtime/fd_runtime_helpers.h b/src/flamenco/runtime/fd_runtime_helpers.h index 7e7a9d4971..4e94e4d817 100644 --- a/src/flamenco/runtime/fd_runtime_helpers.h +++ b/src/flamenco/runtime/fd_runtime_helpers.h @@ -32,16 +32,6 @@ typedef struct fd_txn_return_data fd_txn_return_data_t; /* fd_exec_txn_ctx_t is the context needed to execute a transaction. */ -/* An entry in the instruction trace */ -struct fd_exec_instr_trace_entry { - /* Metadata about the instruction */ - fd_instr_info_t * instr_info; - /* Stack height when this instruction was pushed onto the stack (including itself) - https://github.com/anza-xyz/agave/blob/d87e23d8d91c32d5f2be2bb3557c730bee1e9434/sdk/src/transaction_context.rs#L475-L480 */ - ulong stack_height; -}; -typedef struct fd_exec_instr_trace_entry fd_exec_instr_trace_entry_t; - FD_PROTOTYPES_BEGIN /* Returns 0 on success, and non zero otherwise. On failure, the out diff --git a/src/flamenco/runtime/info/fd_instr_info.c b/src/flamenco/runtime/info/fd_instr_info.c index 61fe017017..15cacdb458 100644 --- a/src/flamenco/runtime/info/fd_instr_info.c +++ b/src/flamenco/runtime/info/fd_instr_info.c @@ -28,6 +28,10 @@ fd_instr_info_init_from_txn_instr( fd_instr_info_t * instr, fd_txn_t const * txn_descriptor = TXN( txn_in->txn ); uchar * instr_acc_idxs = (uchar *)txn_in->txn->payload + txn_instr->acct_off; + /* Set the stack height to 1 (since this is a top-level instruction) */ + instr->stack_height = 1; + + /* Set the program id */ instr->program_id = txn_instr->program_id; /* See note in fd_instr_info.h. TLDR: capping this value at 256 @@ -38,7 +42,7 @@ fd_instr_info_init_from_txn_instr( fd_instr_info_t * instr, the instr info. */ instr->acct_cnt = fd_ushort_min( txn_instr->acct_cnt, FD_INSTR_ACCT_MAX ); instr->data_sz = txn_instr->data_sz; - instr->data = (uchar *)txn_in->txn->payload + txn_instr->data_off; + memcpy( instr->data, txn_in->txn->payload+txn_instr->data_off, instr->data_sz ); uchar acc_idx_seen[ FD_INSTR_ACCT_MAX ] = {0}; diff --git a/src/flamenco/runtime/info/fd_instr_info.h b/src/flamenco/runtime/info/fd_instr_info.h index 6c37110ff4..8a56c77cbc 100644 --- a/src/flamenco/runtime/info/fd_instr_info.h +++ b/src/flamenco/runtime/info/fd_instr_info.h @@ -36,14 +36,17 @@ typedef struct fd_instruction_account fd_instruction_account_t; struct fd_instr_info { uchar program_id; - ushort data_sz; ushort acct_cnt; - uchar * data; + uchar data[ 10<<10 ]; // 10KB + ushort data_sz; fd_instruction_account_t accounts[ FD_INSTR_ACCT_MAX ]; uchar is_duplicate[ FD_INSTR_ACCT_MAX ]; + /* Stack height when this instruction was pushed onto the stack (including itself) */ + uchar stack_height; + /* TODO: convert to fd_uwide_t representation of uint_128 */ ulong starting_lamports_h; ulong starting_lamports_l; @@ -157,20 +160,6 @@ fd_instr_info_sum_account_lamports( fd_instr_info_t const * instr, ulong * total_lamports_h, ulong * total_lamports_l ); -static inline uchar -fd_instr_get_acc_flags( fd_instr_info_t const * instr, - ushort idx ) { - if( FD_UNLIKELY( idx>=instr->acct_cnt ) ) { - return 0; - } - - uchar flags = 0; - if( instr->accounts[idx].is_signer ) flags |= FD_INSTR_ACCT_FLAGS_IS_SIGNER; - if( instr->accounts[idx].is_writable ) flags |= FD_INSTR_ACCT_FLAGS_IS_WRITABLE; - - return flags; -} - FD_PROTOTYPES_END #endif /* HEADER_fd_src_flamenco_runtime_info_fd_instr_info_h */ diff --git a/src/flamenco/runtime/program/fd_bpf_loader_program.c b/src/flamenco/runtime/program/fd_bpf_loader_program.c index 583df76be9..9e33b8ef33 100644 --- a/src/flamenco/runtime/program/fd_bpf_loader_program.c +++ b/src/flamenco/runtime/program/fd_bpf_loader_program.c @@ -909,13 +909,11 @@ common_extend_program( fd_exec_instr_ctx_t * instr_ctx, /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L566-L1444 */ static int process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { - uchar const * data = instr_ctx->instr->data; - uchar __attribute__((aligned(FD_BPF_UPGRADEABLE_LOADER_PROGRAM_INSTRUCTION_ALIGN))) instruction_mem[ FD_BPF_UPGRADEABLE_LOADER_PROGRAM_INSTRUCTION_FOOTPRINT ] = {0}; fd_bpf_upgradeable_loader_program_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize( bpf_upgradeable_loader_program_instruction, instruction_mem, - data, + instr_ctx->instr->data, instr_ctx->instr->data_sz, FD_TXN_MTU, NULL ); diff --git a/src/flamenco/runtime/program/fd_bpf_loader_serialization.c b/src/flamenco/runtime/program/fd_bpf_loader_serialization.c index 012173984c..00f31555f4 100644 --- a/src/flamenco/runtime/program/fd_bpf_loader_serialization.c +++ b/src/flamenco/runtime/program/fd_bpf_loader_serialization.c @@ -391,8 +391,7 @@ fd_bpf_loader_input_serialize_aligned( fd_exec_instr_ctx_t * ctx, *instr_data_offset = FD_VM_MEM_MAP_INPUT_REGION_START + region_vaddr_offset + (ulong)(serialized_params - curr_serialized_params_start); /* https://github.com/anza-xyz/agave/blob/v3.0.0/program-runtime/src/serialization.rs#L559 */ - uchar * instr_data = ctx->instr->data; - fd_memcpy( serialized_params, instr_data, instr_data_len ); + fd_memcpy( serialized_params, ctx->instr->data, instr_data_len ); serialized_params += instr_data_len; /* https://github.com/anza-xyz/agave/blob/v3.0.0/program-runtime/src/serialization.rs#L560 */ @@ -641,8 +640,7 @@ fd_bpf_loader_input_serialize_unaligned( fd_exec_instr_ctx_t * ctx, } *instr_data_offset = FD_VM_MEM_MAP_INPUT_REGION_START + region_vaddr_offset + (ulong)(serialized_params - curr_serialized_params_start); - uchar * instr_data = (uchar *)ctx->instr->data; - fd_memcpy( serialized_params, instr_data, instr_data_len ); + fd_memcpy( serialized_params, ctx->instr->data, instr_data_len ); serialized_params += instr_data_len; FD_STORE( fd_pubkey_t, serialized_params, txn_accs[ctx->instr->program_id] ); diff --git a/src/flamenco/runtime/program/fd_config_program.c b/src/flamenco/runtime/program/fd_config_program.c index 090527e1ed..bdb9249576 100644 --- a/src/flamenco/runtime/program/fd_config_program.c +++ b/src/flamenco/runtime/program/fd_config_program.c @@ -30,9 +30,6 @@ _process_config_instr( fd_exec_instr_ctx_t * ctx ) { /* Deserialize the Config Program instruction data, which consists only of the ConfigKeys https://github.com/solana-labs/solana/blob/v1.17.17/programs/config/src/config_processor.rs#L21 */ - if( FD_UNLIKELY( ctx->instr->data==NULL ) ) { - return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; - } if( FD_UNLIKELY( ctx->instr->data_sz>FD_TXN_MTU ) ) { return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; } diff --git a/src/flamenco/runtime/program/fd_native_cpi.c b/src/flamenco/runtime/program/fd_native_cpi.c index ce11106cd4..9bcbfab101 100644 --- a/src/flamenco/runtime/program/fd_native_cpi.c +++ b/src/flamenco/runtime/program/fd_native_cpi.c @@ -14,9 +14,12 @@ fd_native_cpi_native_invoke( fd_exec_instr_ctx_t * ctx, fd_pubkey_t const * signers, ulong signers_cnt ) { /* Set up the instr info */ - fd_instr_info_t instr_info[ 1 ]; + fd_instr_info_t * instr_info = &ctx->runtime->instr.trace[ ctx->runtime->instr.trace_length++ ]; fd_instruction_account_t instruction_accounts[ FD_INSTR_ACCT_MAX ]; - ulong instruction_accounts_cnt; + ulong instruction_accounts_cnt; + + /* Set the stack size */ + instr_info->stack_height = ctx->runtime->instr.stack_sz+1; /* fd_vm_prepare_instruction will handle missing/invalid account case */ instr_info->program_id = UCHAR_MAX; @@ -47,7 +50,7 @@ fd_native_cpi_native_invoke( fd_exec_instr_ctx_t * ctx, acct_meta->is_signer ); } - instr_info->data = instr_data; + fd_memcpy( instr_info->data, instr_data, instr_data_len ); instr_info->data_sz = (ushort)instr_data_len; /* https://github.com/anza-xyz/agave/blob/v2.2.6/program-runtime/src/invoke_context.rs#L312-L313 */ diff --git a/src/flamenco/runtime/program/fd_precompiles.c b/src/flamenco/runtime/program/fd_precompiles.c index 0d940a41df..1530391fda 100644 --- a/src/flamenco/runtime/program/fd_precompiles.c +++ b/src/flamenco/runtime/program/fd_precompiles.c @@ -100,8 +100,11 @@ fd_precompile_get_instr_data( fd_exec_instr_ctx_t * ctx, if( FD_UNLIKELY( index>=TXN( ctx->txn_in->txn )->instr_cnt ) ) return FD_EXECUTOR_PRECOMPILE_ERR_DATA_OFFSET; - fd_instr_info_t const * instr = &ctx->runtime->instr.infos[ index ]; - data = instr->data; + fd_txn_t const * txn = TXN( ctx->txn_in->txn ); + uchar const * payload = ctx->txn_in->txn->payload; + fd_txn_instr_t const * instr = &txn->instr[ index ]; + + data = fd_txn_get_instr_data( instr, payload ); data_sz = instr->data_sz; } diff --git a/src/flamenco/runtime/program/fd_stake_program.c b/src/flamenco/runtime/program/fd_stake_program.c index 5c9c9e7dc0..b9a3d52610 100644 --- a/src/flamenco/runtime/program/fd_stake_program.c +++ b/src/flamenco/runtime/program/fd_stake_program.c @@ -2557,9 +2557,6 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = {0}; fd_exec_instr_ctx_get_signers( ctx, signers ); - if( FD_UNLIKELY( ctx->instr->data==NULL ) ) { - return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; - } if( FD_UNLIKELY( ctx->instr->data_sz>FD_STAKE_INSTR_FOOTPRINT ) ) { return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; } diff --git a/src/flamenco/runtime/program/fd_system_program.c b/src/flamenco/runtime/program/fd_system_program.c index ea6b303c67..10017961a1 100644 --- a/src/flamenco/runtime/program/fd_system_program.c +++ b/src/flamenco/runtime/program/fd_system_program.c @@ -623,12 +623,6 @@ int fd_system_program_execute( fd_exec_instr_ctx_t * ctx ) { FD_EXEC_CU_UPDATE( ctx, 150UL ); - /* Deserialize the SystemInstruction enum */ - uchar * data = ctx->instr->data; - if( FD_UNLIKELY( data==NULL ) ) { - return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; - } - if( FD_UNLIKELY( ctx->instr->data_sz>FD_SYSTEM_PROGRAM_INSTR_FOOTPRINT ) ) { return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; } @@ -637,10 +631,13 @@ fd_system_program_execute( fd_exec_instr_ctx_t * ctx ) { int decode_err; fd_system_program_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize( - system_program_instruction, instr_mem, - data, ctx->instr->data_sz, + system_program_instruction, + instr_mem, + ctx->instr->data, + ctx->instr->data_sz, FD_TXN_MTU, - &decode_err ); + &decode_err + ); if( FD_UNLIKELY( decode_err ) ) { return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; } diff --git a/src/flamenco/runtime/program/fd_vote_program.c b/src/flamenco/runtime/program/fd_vote_program.c index 2ff36f0a80..b97cbaae5c 100644 --- a/src/flamenco/runtime/program/fd_vote_program.c +++ b/src/flamenco/runtime/program/fd_vote_program.c @@ -2211,11 +2211,6 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = { 0 }; fd_exec_instr_ctx_get_signers( ctx, signers ); - // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L70 - if( FD_UNLIKELY( ctx->instr->data==NULL ) ) { - return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; - } - uchar __attribute__((aligned(alignof(fd_vote_instruction_t)))) vote_instruction_mem[ FD_VOTE_INSTRUCTION_FOOTPRINT ]; fd_vote_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize( vote_instruction, diff --git a/src/flamenco/runtime/program/zksdk/fd_zksdk.c b/src/flamenco/runtime/program/zksdk/fd_zksdk.c index cb7bbfa62c..1f1bfe0b95 100644 --- a/src/flamenco/runtime/program/zksdk/fd_zksdk.c +++ b/src/flamenco/runtime/program/zksdk/fd_zksdk.c @@ -115,9 +115,9 @@ fd_zksdk_process_close_context_state( fd_exec_instr_ctx_t * ctx ) { int fd_zksdk_process_verify_proof( fd_exec_instr_ctx_t * ctx ) { int err; - uchar const * instr_data = ctx->instr->data; - ulong instr_acc_cnt = ctx->instr->acct_cnt; - uchar instr_id = instr_data[0]; /* instr_data_sz already checked by the caller */ + uchar const * instr_data = ctx->instr->data; + ulong instr_acc_cnt = ctx->instr->acct_cnt; + uchar instr_id = instr_data[0]; /* instr_data_sz already checked by the caller */ /* ProofContextState "header" size, ie. 1 authority pubkey + 1 proof_type byte */ #define CTX_HEAD_SZ 33UL diff --git a/src/flamenco/runtime/program/zksdk/test_zksdk.c b/src/flamenco/runtime/program/zksdk/test_zksdk.c index f5c85788ec..15a0b4473b 100644 --- a/src/flamenco/runtime/program/zksdk/test_zksdk.c +++ b/src/flamenco/runtime/program/zksdk/test_zksdk.c @@ -47,9 +47,9 @@ create_test_ctx( fd_exec_instr_ctx_t * ctx, ctx->txn_out->details.compute_budget.compute_meter = compute_meter; ctx->instr = instr; ctx->runtime = runtime; - instr->data = &tx[instr_off]; instr->data_sz = (ushort)(tx_len - instr_off); //TODO: this only works if the instruction is the last one instr->acct_cnt = 0; // TODO: hack to avoid filling proof context account (it requires to create the account first) + memcpy( instr->data, &tx[instr_off], instr->data_sz ); fd_log_collector_init( ctx->runtime->log.log_collector, 1 ); } @@ -76,7 +76,6 @@ test_pubkey_validity( FD_FN_UNUSED fd_rng_t * rng, fd_runtime_t * runtime ) { fd_log_collector_t log_collector[1]; fd_bank_t bank[1]; ulong tx_len = 0; - ulong proof_offset = offset + 1 + context_sz; ctx.bank = bank; runtime->log.log_collector = log_collector; @@ -88,8 +87,8 @@ test_pubkey_validity( FD_FN_UNUSED fd_rng_t * rng, fd_runtime_t * runtime ) { uchar * tx = load_test_tx( hex, hex_sz, &tx_len ); create_test_ctx( &ctx, runtime, txn_out, instr, tx, tx_len, offset, cu ); - void const * context = tx + offset + 1; - void const * proof = tx + proof_offset; + void const * context = instr->data+1; + void const * proof = instr->data+1+context_sz; // valid FD_TEST( fd_zksdk_instr_verify_proof_pubkey_validity( context, proof )==FD_EXECUTOR_INSTR_SUCCESS ); @@ -97,10 +96,10 @@ test_pubkey_validity( FD_FN_UNUSED fd_rng_t * rng, fd_runtime_t * runtime ) { FD_TEST( fd_executor_zk_elgamal_proof_program_execute( &ctx )==FD_EXECUTOR_INSTR_SUCCESS ); // invalid proof - tx[1 + proof_offset] ^= 0xff; + instr->data[1 + context_sz] ^= 0xff; FD_TEST( fd_zksdk_instr_verify_proof_pubkey_validity( context, proof )==FD_ZKSDK_VERIFY_PROOF_ERROR ); FD_TEST( fd_zksdk_process_verify_proof( &ctx )==FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA ); - tx[1 + proof_offset] ^= 0xff; + instr->data[1 + context_sz] ^= 0xff; // invalid data instr->data_sz = (ushort)(instr->data_sz - 10); diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.c b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.c index 1fa56730bc..729e0f7e3d 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.c @@ -3,26 +3,25 @@ #include "../fd_system_ids.h" static ulong -instructions_serialized_size( fd_instr_info_t const * instrs, - ushort instrs_cnt ) { - ulong serialized_size = 0; +instructions_serialized_size( fd_txn_t const * txn ) { + ushort instr_cnt = txn->instr_cnt; + ulong serialized_size = sizeof(ushort) // num_instructions + + (sizeof(ushort)*instr_cnt); // instruction offsets - serialized_size += sizeof(ushort) // num_instructions - + (sizeof(ushort) * instrs_cnt); // instruction offsets - - for ( ushort i = 0; i < instrs_cnt; ++i ) { - fd_instr_info_t const * instr = &instrs[i]; + for( ushort i=0; iinstr[i].data_sz; + ushort acct_cnt = txn->instr[i].acct_cnt; serialized_size += sizeof(ushort); // num_accounts; - serialized_size += instr->acct_cnt * ( + serialized_size += acct_cnt * ( sizeof(uchar) // flags (is_signer, is_writeable) - + sizeof(fd_pubkey_t) // pubkey + + sizeof(fd_pubkey_t) // pubkey ); serialized_size += sizeof(fd_pubkey_t) // program_id pubkey + sizeof(ushort) // instr_data_len; - + instr->data_sz; // instr_data; + + data_sz; // instr_data; } @@ -33,12 +32,12 @@ instructions_serialized_size( fd_instr_info_t const * instrs, /* https://github.com/anza-xyz/agave/blob/v2.1.1/svm/src/account_loader.rs#L547-L576 */ void -fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, - fd_txn_out_t * txn_out, - fd_instr_info_t const * instrs, - ushort instrs_cnt, - ulong txn_idx ) { - ulong serialized_sz = instructions_serialized_size( instrs, instrs_cnt ); +fd_sysvar_instructions_serialize_account( fd_bank_t * bank, + fd_txn_in_t const * txn_in, + fd_txn_out_t * txn_out, + ulong txn_idx ) { + fd_txn_t const * txn = TXN( txn_in->txn ); + ulong serialized_sz = instructions_serialized_size( txn ); fd_txn_account_t * rec = NULL; int err = fd_runtime_get_account_with_key( txn_in, @@ -83,34 +82,39 @@ fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, uchar * serialized_instructions = fd_txn_account_get_data_mut( rec ); ulong offset = 0; - // TODO: do we needs bounds checking? // num_instructions - FD_STORE( ushort, serialized_instructions + offset, instrs_cnt); + ushort instr_cnt = txn->instr_cnt; + FD_STORE( ushort, serialized_instructions + offset, instr_cnt); offset += sizeof(ushort); // instruction offsets uchar * serialized_instruction_offsets = serialized_instructions + offset; - offset += (ushort)(sizeof(ushort) * instrs_cnt); + offset += (ushort)(sizeof(ushort) * instr_cnt); // serialize instructions - for( ushort i = 0; i < instrs_cnt; ++i ) { + for( ushort i=0; iinstr[i]; // num_accounts FD_STORE( ushort, serialized_instructions + offset, instr->acct_cnt ); offset += sizeof(ushort); - for ( ushort j = 0; j < instr->acct_cnt; j++ ) { + uchar const * instr_accts = fd_txn_get_instr_accts( instr, txn_in->txn->payload ); + for( ushort j=0; jacct_cnt; j++ ) { + uchar idx_in_txn = instr_accts[j]; + uchar is_writable = (uchar)fd_runtime_account_is_writable_idx( txn_in, txn_out, bank, idx_in_txn ); + uchar is_signer = (uchar)fd_txn_is_signer( txn, idx_in_txn ); + uchar flags = ((!!is_signer)*FD_INSTR_ACCT_FLAGS_IS_SIGNER) | ((!!is_writable)*FD_INSTR_ACCT_FLAGS_IS_WRITABLE); + // flags - FD_STORE( uchar, serialized_instructions + offset, fd_instr_get_acc_flags( instr, j ) ); + FD_STORE( uchar, serialized_instructions + offset, flags ); offset += sizeof(uchar); // pubkey - ushort idx_in_txn = instr->accounts[j].index_in_transaction; FD_STORE( fd_pubkey_t, serialized_instructions + offset, txn_out->accounts.account_keys[ idx_in_txn ] ); offset += sizeof(fd_pubkey_t); } @@ -124,11 +128,11 @@ fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, offset += sizeof(ushort); // instr_data - fd_memcpy( serialized_instructions + offset, instr->data, instr->data_sz ); + uchar const * instr_data = fd_txn_get_instr_data( instr, txn_in->txn->payload ); + fd_memcpy( serialized_instructions + offset, instr_data, instr->data_sz ); offset += instr->data_sz; } - // FD_STORE( ushort, serialized_instructions + offset, 0 ); offset += sizeof(ushort); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h index 60428b3d26..ee47828d40 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h @@ -8,11 +8,10 @@ FD_PROTOTYPES_BEGIN void -fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, - fd_txn_out_t * txn_out, - fd_instr_info_t const * instrs, - ushort instrs_cnt, - ulong txn_idx ); +fd_sysvar_instructions_serialize_account( fd_bank_t * bank, + fd_txn_in_t const * txn_in, + fd_txn_out_t * txn_out, + ulong txn_idx ); void fd_sysvar_instructions_update_current_instr_idx( fd_txn_account_t * rec, diff --git a/src/flamenco/runtime/tests/fd_instr_harness.c b/src/flamenco/runtime/tests/fd_instr_harness.c index 99c7fa9658..37fdfd201d 100644 --- a/src/flamenco/runtime/tests/fd_instr_harness.c +++ b/src/flamenco/runtime/tests/fd_instr_harness.c @@ -104,8 +104,7 @@ fd_solfuzz_pb_instr_ctx_create( fd_solfuzz_runner_t * runner, runtime->log.capture_ctx = NULL; - runtime->instr.info_cnt = 0UL; - runtime->instr.trace_length = 0UL; + runtime->instr.trace_length = 1UL; txn_out->err.exec_err = 0; txn_out->err.exec_err_kind = FD_EXECUTOR_ERR_KIND_NONE; @@ -114,25 +113,24 @@ fd_solfuzz_pb_instr_ctx_create( fd_solfuzz_runner_t * runner, txn_in->txn = txn; txn_out->details.compute_budget.compute_unit_limit = test_ctx->cu_avail; txn_out->details.compute_budget.compute_meter = test_ctx->cu_avail; - runtime->instr.info_cnt = 1UL; runtime->log.enable_vm_tracing = runner->enable_vm_tracing; runtime->log.tracing_mem = runner->enable_vm_tracing ? fd_spad_alloc_check( runner->spad, FD_RUNTIME_VM_TRACE_STATIC_ALIGN, FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT * FD_MAX_INSTRUCTION_STACK_DEPTH ) : NULL; /* Set up instruction context */ - - fd_instr_info_t * info = fd_spad_alloc( runner->spad, 8UL, sizeof(fd_instr_info_t) ); - assert( info ); + fd_instr_info_t * info = &runtime->instr.trace[ 0UL ]; memset( info, 0, sizeof(fd_instr_info_t) ); + info->stack_height = 1; if( test_ctx->data ) { + if( FD_UNLIKELY( test_ctx->data->size>FD_TXN_MTU ) ) { + FD_LOG_ERR(( "invariant violation: instr data sz is too large %u > %lu", test_ctx->data->size, FD_TXN_MTU )); + } info->data_sz = (ushort)test_ctx->data->size; - info->data = test_ctx->data->bytes; + memcpy( info->data, test_ctx->data->bytes, info->data_sz ); } - runtime->instr.infos[ 0UL ] = *info; - /* Prepare borrowed account table (correctly handles aliasing) */ if( FD_UNLIKELY( test_ctx->accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) { @@ -333,7 +331,7 @@ fd_solfuzz_pb_instr_ctx_create( fd_solfuzz_runner_t * runner, return 0; } - ctx->instr = info; + ctx->instr = info; ctx->runtime->progcache = runner->progcache; ctx->runtime->accdb = runner->accdb; diff --git a/src/flamenco/runtime/tests/fd_txn_harness.c b/src/flamenco/runtime/tests/fd_txn_harness.c index 940a4fb7c9..1df4356f75 100644 --- a/src/flamenco/runtime/tests/fd_txn_harness.c +++ b/src/flamenco/runtime/tests/fd_txn_harness.c @@ -450,8 +450,9 @@ fd_solfuzz_pb_txn_run( fd_solfuzz_runner_t * runner, } else { /* Capture the instruction error code */ if( exec_res==FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ) { - int instr_err_idx = txn_out->err.exec_err_idx; - int program_id_idx = runtime->instr.infos[instr_err_idx].program_id; + fd_txn_t const * txn = TXN( txn_in->txn ); + int instr_err_idx = txn_out->err.exec_err_idx; + int program_id_idx = txn->instr[instr_err_idx].program_id; txn_result->instruction_error = (uint32_t) -txn_out->err.exec_err; txn_result->instruction_error_index = (uint32_t) instr_err_idx; diff --git a/src/flamenco/runtime/tests/fd_vm_harness.c b/src/flamenco/runtime/tests/fd_vm_harness.c index 1b7f31227f..114c001738 100644 --- a/src/flamenco/runtime/tests/fd_vm_harness.c +++ b/src/flamenco/runtime/tests/fd_vm_harness.c @@ -406,8 +406,6 @@ fd_solfuzz_pb_syscall_run( fd_solfuzz_runner_t * runner, if( !fd_solfuzz_pb_instr_ctx_create( runner, ctx, input_instr_ctx, skip_extra_checks ) ) goto error; - ctx->runtime->instr.trace[0].instr_info = (fd_instr_info_t *)ctx->instr; - ctx->runtime->instr.trace[0].stack_height = 1; ctx->txn_out->err.exec_err = 0; ctx->txn_out->err.exec_err_kind = FD_EXECUTOR_ERR_KIND_NONE; ctx->bank = runner->bank; diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c index 0d07044206..58dd73d7c9 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c @@ -61,10 +61,11 @@ VM_SYSCALL_CPI_INSTRUCTION_TO_INSTR_FUNC( fd_vm_t * vm, fd_instr_info_t * out_instr, fd_pubkey_t out_instr_acct_keys[ FD_INSTR_ACCT_MAX ] ) { - out_instr->program_id = UCHAR_MAX; - out_instr->data_sz = (ushort)VM_SYSCALL_CPI_INSTR_DATA_LEN( cpi_instr ); - out_instr->data = (uchar *)cpi_instr_data; - out_instr->acct_cnt = (ushort)VM_SYSCALL_CPI_INSTR_ACCS_LEN( cpi_instr ); + out_instr->program_id = UCHAR_MAX; + out_instr->stack_height = vm->instr_ctx->runtime->instr.stack_sz+1; + out_instr->data_sz = (ushort)VM_SYSCALL_CPI_INSTR_DATA_LEN( cpi_instr ); + out_instr->acct_cnt = (ushort)VM_SYSCALL_CPI_INSTR_ACCS_LEN( cpi_instr ); + memcpy( out_instr->data, cpi_instr_data, out_instr->data_sz ); /* Find the index of the CPI instruction's program account in the transaction */ int program_id_idx = fd_runtime_find_index_of_account( vm->instr_ctx->txn_out, program_id ); @@ -782,7 +783,7 @@ VM_SYSCALL_CPI_ENTRYPOINT( void * _vm, /* Create the instruction to execute (in the input format the FD runtime expects) from the translated CPI ABI inputs. */ fd_pubkey_t cpi_instr_acct_keys[ FD_INSTR_ACCT_MAX ]; - fd_instr_info_t * instruction_to_execute = &vm->instr_ctx->runtime->instr.infos[ vm->instr_ctx->runtime->instr.info_cnt++ ]; + fd_instr_info_t * instruction_to_execute = &vm->instr_ctx->runtime->instr.trace[ vm->instr_ctx->runtime->instr.trace_length++ ]; err = VM_SYSCALL_CPI_INSTRUCTION_TO_INSTR_FUNC( vm, cpi_instruction, cpi_account_metas, program_id, data, instruction_to_execute, cpi_instr_acct_keys ); if( FD_UNLIKELY( err ) ) { diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c b/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c index 7d4fc35572..f6cb1bfd3d 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c @@ -460,14 +460,14 @@ fd_vm_syscall_sol_get_processed_sibling_instruction( https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1518-L1522 */ ulong instruction_trace_length = vm->instr_ctx->runtime->instr.trace_length; ulong reverse_index_at_stack_height = 0UL; - fd_exec_instr_trace_entry_t * found_instruction_context = NULL; + fd_instr_info_t * found_instruction_context = NULL; for( ulong index_in_trace=instruction_trace_length; index_in_trace>0UL; index_in_trace-- ) { /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1524-L1526 This error can never happen */ /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1527-L1529 */ - fd_exec_instr_trace_entry_t * instruction_context = &vm->instr_ctx->runtime->instr.trace[ index_in_trace-1UL ]; + fd_instr_info_t * instruction_context = &vm->instr_ctx->runtime->instr.trace[ index_in_trace-1UL ]; if( FD_LIKELY( instruction_context->stack_heightinstr_info; - fd_vm_haddr_query_t result_header_query = { .vaddr = result_meta_vaddr, .align = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN, @@ -502,7 +500,7 @@ fd_vm_syscall_sol_get_processed_sibling_instruction( fd_vm_syscall_processed_sibling_instruction_t * result_header = result_header_query.haddr; /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1546-L1583 */ - if( result_header->data_len==instr_info->data_sz && result_header->accounts_len==instr_info->acct_cnt ) { + if( result_header->data_len==found_instruction_context->data_sz && result_header->accounts_len==found_instruction_context->acct_cnt ) { fd_vm_haddr_query_t program_id_query = { .vaddr = result_program_id_vaddr, .align = FD_VM_ALIGN_RUST_PUBKEY, @@ -533,9 +531,11 @@ fd_vm_syscall_sol_get_processed_sibling_instruction( /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1561-L1562 */ fd_pubkey_t const * instr_ctx_program_id = NULL; - int err = fd_runtime_get_key_of_account_at_index( vm->instr_ctx->txn_out, - instr_info->program_id, - &instr_ctx_program_id ); + int err = fd_runtime_get_key_of_account_at_index( + vm->instr_ctx->txn_out, + found_instruction_context->program_id, + &instr_ctx_program_id + ); if( FD_UNLIKELY( err ) ) { FD_VM_ERR_FOR_LOG_INSTR( vm, err ); return err; @@ -543,12 +543,12 @@ fd_vm_syscall_sol_get_processed_sibling_instruction( fd_memcpy( program_id, instr_ctx_program_id, sizeof(fd_pubkey_t) ); /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1563 */ - fd_memcpy( data, instr_info->data, instr_info->data_sz ); + fd_memcpy( data, found_instruction_context->data, found_instruction_context->data_sz ); /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1564-L1581 */ - for( ushort i=0; iacct_cnt; i++ ) { + for( ushort i=0; iacct_cnt; i++ ) { fd_pubkey_t const * account_key; - ushort txn_idx = instr_info->accounts[ i ].index_in_transaction; + ushort txn_idx = found_instruction_context->accounts[ i ].index_in_transaction; err = fd_runtime_get_key_of_account_at_index( vm->instr_ctx->txn_out, txn_idx, &account_key ); if( FD_UNLIKELY( err ) ) { FD_VM_ERR_FOR_LOG_INSTR( vm, err ); @@ -556,14 +556,14 @@ fd_vm_syscall_sol_get_processed_sibling_instruction( } fd_memcpy( accounts[ i ].pubkey, account_key, sizeof(fd_pubkey_t) ); - accounts[ i ].is_signer = !!(instr_info->accounts[ i ].is_signer ); - accounts[ i ].is_writable = !!(instr_info->accounts[ i ].is_writable ); + accounts[ i ].is_signer = !!(found_instruction_context->accounts[ i ].is_signer ); + accounts[ i ].is_writable = !!(found_instruction_context->accounts[ i ].is_writable ); } } else { /* Copy the actual metadata into the result meta struct https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1584-L1586 */ - result_header->data_len = instr_info->data_sz; - result_header->accounts_len = instr_info->acct_cnt; + result_header->data_len = found_instruction_context->data_sz; + result_header->accounts_len = found_instruction_context->acct_cnt; } /* Return true as we found a sibling instruction