From 34b76ac58032b47504d411763d3ae05e7308220a Mon Sep 17 00:00:00 2001 From: Joe C Date: Wed, 1 May 2024 15:22:43 -0500 Subject: [PATCH] Program-Runtime: Add `EnvironmentConfig` to `InvokeContext` (#1059) * program-runtime: add `EnvironmentConfig` to `InvokeContext` * move `blockhash` to `EnvironmentConfig` * move `lamports_per_signature` to `EnvironmentConfig` * move `feature_set` to `EnvironmentConfig` * move `sysvar_cache` to `EnvironmentConfig` * add `get_feature_set` getter --- ledger-tool/src/program.rs | 2 +- program-runtime/src/invoke_context.rs | 73 +++++++++++----- .../address-lookup-table/src/processor.rs | 6 +- programs/bpf_loader/src/lib.rs | 6 +- programs/bpf_loader/src/syscalls/cpi.rs | 25 +++--- programs/bpf_loader/src/syscalls/mem_ops.rs | 6 +- programs/bpf_loader/src/syscalls/mod.rs | 18 ++-- programs/sbf/benches/bpf_loader.rs | 10 +-- programs/stake/src/stake_instruction.rs | 12 +-- programs/stake/src/stake_state.rs | 11 +-- programs/system/src/system_instruction.rs | 57 +++++++------ programs/system/src/system_processor.rs | 4 +- programs/vote/src/vote_processor.rs | 26 +++--- programs/zk-token-proof/src/lib.rs | 4 +- .../bank/builtins/core_bpf_migration/mod.rs | 8 +- svm/src/message_processor.rs | 83 ++++++++++++------- svm/src/transaction_processor.rs | 12 +-- 17 files changed, 214 insertions(+), 149 deletions(-) diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index 7010f51f39..4613d3a4cf 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -325,7 +325,7 @@ fn load_program<'a>( }; let account_size = contents.len(); let program_runtime_environment = create_program_runtime_environment_v1( - &invoke_context.feature_set, + invoke_context.get_feature_set(), invoke_context.get_compute_budget(), false, /* deployment */ true, /* debugging_features */ diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index af5e0c6884..9e020d962c 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -144,6 +144,28 @@ impl BpfAllocator { } } +pub struct EnvironmentConfig<'a> { + pub blockhash: Hash, + pub feature_set: Arc, + pub lamports_per_signature: u64, + sysvar_cache: &'a SysvarCache, +} +impl<'a> EnvironmentConfig<'a> { + pub fn new( + blockhash: Hash, + feature_set: Arc, + lamports_per_signature: u64, + sysvar_cache: &'a SysvarCache, + ) -> Self { + Self { + blockhash, + feature_set, + lamports_per_signature, + sysvar_cache, + } + } +} + pub struct SyscallContext { pub allocator: BpfAllocator, pub accounts_metadata: Vec, @@ -159,19 +181,19 @@ pub struct SerializedAccountMetadata { pub vm_owner_addr: u64, } +/// Main pipeline from runtime to program execution. pub struct InvokeContext<'a> { + /// Information about the currently executing transaction. pub transaction_context: &'a mut TransactionContext, - sysvar_cache: &'a SysvarCache, + /// Runtime configurations used to provision the invocation environment. + pub environment_config: EnvironmentConfig<'a>, log_collector: Option>>, compute_budget: ComputeBudget, current_compute_budget: ComputeBudget, compute_meter: RefCell, pub programs_loaded_for_tx_batch: &'a ProgramCacheForTxBatch, pub programs_modified_by_tx: &'a mut ProgramCacheForTxBatch, - pub feature_set: Arc, pub timings: ExecuteDetailsTimings, - pub blockhash: Hash, - pub lamports_per_signature: u64, pub syscall_context: Vec>, traces: Vec>, } @@ -180,28 +202,22 @@ impl<'a> InvokeContext<'a> { #[allow(clippy::too_many_arguments)] pub fn new( transaction_context: &'a mut TransactionContext, - sysvar_cache: &'a SysvarCache, + environment_config: EnvironmentConfig<'a>, log_collector: Option>>, compute_budget: ComputeBudget, programs_loaded_for_tx_batch: &'a ProgramCacheForTxBatch, programs_modified_by_tx: &'a mut ProgramCacheForTxBatch, - feature_set: Arc, - blockhash: Hash, - lamports_per_signature: u64, ) -> Self { Self { transaction_context, - sysvar_cache, + environment_config, log_collector, current_compute_budget: compute_budget, compute_budget, compute_meter: RefCell::new(compute_budget.compute_unit_limit), programs_loaded_for_tx_batch, programs_modified_by_tx, - feature_set, timings: ExecuteDetailsTimings::default(), - blockhash, - lamports_per_signature, syscall_context: Vec::new(), traces: Vec::new(), } @@ -219,7 +235,7 @@ impl<'a> InvokeContext<'a> { &self, effective_slot: Slot, ) -> Result<&ProgramRuntimeEnvironments, InstructionError> { - let epoch_schedule = self.sysvar_cache.get_epoch_schedule()?; + let epoch_schedule = self.environment_config.sysvar_cache.get_epoch_schedule()?; let epoch = epoch_schedule.get_epoch(effective_slot); Ok(self .programs_loaded_for_tx_batch @@ -578,9 +594,21 @@ impl<'a> InvokeContext<'a> { &self.current_compute_budget } + /// Get the current feature set. + pub fn get_feature_set(&self) -> &FeatureSet { + &self.environment_config.feature_set + } + + /// Set feature set. + /// + /// Only use for tests and benchmarks. + pub fn mock_set_feature_set(&mut self, feature_set: Arc) { + self.environment_config.feature_set = feature_set; + } + /// Get cached sysvars pub fn get_sysvar_cache(&self) -> &SysvarCache { - self.sysvar_cache + self.environment_config.sysvar_cache } // Should alignment be enforced during user pointer translation @@ -645,8 +673,10 @@ macro_rules! with_mock_invoke_context { }, std::sync::Arc, $crate::{ - compute_budget::ComputeBudget, invoke_context::InvokeContext, - loaded_programs::ProgramCacheForTxBatch, log_collector::LogCollector, + compute_budget::ComputeBudget, + invoke_context::{EnvironmentConfig, InvokeContext}, + loaded_programs::ProgramCacheForTxBatch, + log_collector::LogCollector, sysvar_cache::SysvarCache, }, }; @@ -675,18 +705,21 @@ macro_rules! with_mock_invoke_context { } } }); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let programs_loaded_for_tx_batch = ProgramCacheForTxBatch::default(); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); let mut $invoke_context = InvokeContext::new( &mut $transaction_context, - &sysvar_cache, + environment_config, Some(LogCollector::new_ref()), compute_budget, &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); }; } diff --git a/programs/address-lookup-table/src/processor.rs b/programs/address-lookup-table/src/processor.rs index 4db568c71a..7becdbd047 100644 --- a/programs/address-lookup-table/src/processor.rs +++ b/programs/address-lookup-table/src/processor.rs @@ -61,7 +61,7 @@ impl Processor { let table_key = *lookup_table_account.get_key(); let lookup_table_owner = *lookup_table_account.get_owner(); if !invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id()) && !lookup_table_account.get_data().is_empty() { @@ -74,7 +74,7 @@ impl Processor { instruction_context.try_borrow_instruction_account(transaction_context, 1)?; let authority_key = *authority_account.get_key(); if !invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id()) && !authority_account.is_signer() { @@ -127,7 +127,7 @@ impl Processor { } if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id()) && check_id(&lookup_table_owner) { diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index f7eb72c7b3..ce8ec698ab 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -957,7 +957,7 @@ fn process_loader_upgradeable_instruction( } UpgradeableLoaderInstruction::SetAuthorityChecked => { if !invoke_context - .feature_set + .get_feature_set() .is_active(&enable_bpf_loader_set_authority_checked_ix::id()) { return Err(InstructionError::InvalidInstructionData); @@ -1352,7 +1352,7 @@ fn execute<'a, 'b: 'a>( #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))] let use_jit = executable.get_compiled_program().is_some(); let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&bpf_account_data_direct_mapping::id()); let mut serialize_time = Measure::start("serialize"); @@ -1505,7 +1505,7 @@ pub mod test_utils { pub fn load_all_invoked_programs(invoke_context: &mut InvokeContext) { let mut load_program_metrics = LoadProgramMetrics::default(); let program_runtime_environment = create_program_runtime_environment_v1( - &invoke_context.feature_set, + invoke_context.get_feature_set(), invoke_context.get_compute_budget(), false, /* deployment */ false, /* debugging_features */ diff --git a/programs/bpf_loader/src/syscalls/cpi.rs b/programs/bpf_loader/src/syscalls/cpi.rs index 13f9cbaf90..4c8a0e45e4 100644 --- a/programs/bpf_loader/src/syscalls/cpi.rs +++ b/programs/bpf_loader/src/syscalls/cpi.rs @@ -107,7 +107,7 @@ impl<'a, 'b> CallerAccount<'a, 'b> { account_metadata: &SerializedAccountMetadata, ) -> Result, Error> { let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()); if direct_mapping { @@ -244,7 +244,7 @@ impl<'a, 'b> CallerAccount<'a, 'b> { account_metadata: &SerializedAccountMetadata, ) -> Result, Error> { let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()); if direct_mapping { @@ -452,7 +452,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust { let ix_data_len = ix.data.len() as u64; if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::loosen_cpi_size_restriction::id()) { consume_compute_meter( @@ -666,7 +666,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC { let ix_data_len = ix_c.data_len; if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::loosen_cpi_size_restriction::id()) { consume_compute_meter( @@ -866,7 +866,7 @@ where .accounts_metadata; let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()); for (instruction_account_index, instruction_account) in instruction_accounts.iter().enumerate() @@ -961,7 +961,7 @@ fn check_instruction_size( invoke_context: &mut InvokeContext, ) -> Result<(), Error> { if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::loosen_cpi_size_restriction::id()) { let data_len = data_len as u64; @@ -998,11 +998,11 @@ fn check_account_infos( invoke_context: &mut InvokeContext, ) -> Result<(), Error> { if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::loosen_cpi_size_restriction::id()) { let max_cpi_account_infos = if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::increase_tx_account_lock_limit::id()) { MAX_CPI_ACCOUNT_INFOS @@ -1041,14 +1041,14 @@ fn check_authorized_program( && !(bpf_loader_upgradeable::is_upgrade_instruction(instruction_data) || bpf_loader_upgradeable::is_set_authority_instruction(instruction_data) || (invoke_context - .feature_set + .get_feature_set() .is_active(&enable_bpf_loader_set_authority_checked_ix::id()) && bpf_loader_upgradeable::is_set_authority_checked_instruction( instruction_data, )) || bpf_loader_upgradeable::is_close_instruction(instruction_data))) || is_precompile(program_id, |feature_id: &Pubkey| { - invoke_context.feature_set.is_active(feature_id) + invoke_context.get_feature_set().is_active(feature_id) }) { return Err(Box::new(SyscallError::ProgramNotSupported(*program_id))); @@ -1122,7 +1122,7 @@ fn cpi_common( // // Synchronize the callee's account changes so the caller can see them. let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()); if direct_mapping { @@ -1629,8 +1629,9 @@ mod tests { .map(|a| (a.0, a.1)) .collect::>(); with_mock_invoke_context!($invoke_context, $transaction_context, transaction_accounts); - let feature_set = Arc::make_mut(&mut $invoke_context.feature_set); + let mut feature_set = $invoke_context.get_feature_set().clone(); feature_set.deactivate(&bpf_account_data_direct_mapping::id()); + $invoke_context.mock_set_feature_set(Arc::new(feature_set)); $invoke_context .transaction_context .get_next_instruction_context() diff --git a/programs/bpf_loader/src/syscalls/mem_ops.rs b/programs/bpf_loader/src/syscalls/mem_ops.rs index f02f1935d9..bbdf0ccc4c 100644 --- a/programs/bpf_loader/src/syscalls/mem_ops.rs +++ b/programs/bpf_loader/src/syscalls/mem_ops.rs @@ -69,7 +69,7 @@ declare_builtin_function!( mem_op_consume(invoke_context, n)?; if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()) { let cmp_result = translate_type_mut::( @@ -125,7 +125,7 @@ declare_builtin_function!( mem_op_consume(invoke_context, n)?; if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()) { memset_non_contiguous(dst_addr, c as u8, n, memory_mapping) @@ -150,7 +150,7 @@ fn memmove( memory_mapping: &MemoryMapping, ) -> Result { if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::bpf_account_data_direct_mapping::id()) { memmove_non_contiguous(dst_addr, src_addr, n, memory_mapping) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index ab2e85e349..b71e60ca7d 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -918,7 +918,7 @@ declare_builtin_function!( } _ => { if invoke_context - .feature_set + .get_feature_set() .is_active(&abort_on_invalid_curve::id()) { Err(SyscallError::InvalidAttribute.into()) @@ -1035,7 +1035,7 @@ declare_builtin_function!( } _ => { if invoke_context - .feature_set + .get_feature_set() .is_active(&abort_on_invalid_curve::id()) { Err(SyscallError::InvalidAttribute.into()) @@ -1134,7 +1134,7 @@ declare_builtin_function!( } _ => { if invoke_context - .feature_set + .get_feature_set() .is_active(&abort_on_invalid_curve::id()) { Err(SyscallError::InvalidAttribute.into()) @@ -1146,7 +1146,7 @@ declare_builtin_function!( _ => { if invoke_context - .feature_set + .get_feature_set() .is_active(&abort_on_invalid_curve::id()) { Err(SyscallError::InvalidAttribute.into()) @@ -1261,7 +1261,7 @@ declare_builtin_function!( _ => { if invoke_context - .feature_set + .get_feature_set() .is_active(&abort_on_invalid_curve::id()) { Err(SyscallError::InvalidAttribute.into()) @@ -1613,7 +1613,7 @@ declare_builtin_function!( }; let simplify_alt_bn128_syscall_error_codes = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id()); let result_point = match calculation(input) { @@ -1771,7 +1771,7 @@ declare_builtin_function!( .collect::, Error>>()?; let simplify_alt_bn128_syscall_error_codes = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id()); let hash = match poseidon::hashv(parameters, endianness, inputs.as_slice()) { @@ -1866,7 +1866,7 @@ declare_builtin_function!( )?; let simplify_alt_bn128_syscall_error_codes = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id()); match op { @@ -2484,7 +2484,7 @@ mod tests { // many small unaligned allocs { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); - invoke_context.feature_set = Arc::new(FeatureSet::default()); + invoke_context.mock_set_feature_set(Arc::new(FeatureSet::default())); mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context); let mut vm = vm.unwrap(); let invoke_context = &mut vm.context_object_pointer; diff --git a/programs/sbf/benches/bpf_loader.rs b/programs/sbf/benches/bpf_loader.rs index cf8670cc86..8f4257e87c 100644 --- a/programs/sbf/benches/bpf_loader.rs +++ b/programs/sbf/benches/bpf_loader.rs @@ -119,7 +119,7 @@ fn bench_program_alu(bencher: &mut Bencher) { with_mock_invoke_context!(invoke_context, bpf_loader::id(), 10000001); let program_runtime_environment = create_program_runtime_environment_v1( - &invoke_context.feature_set, + invoke_context.get_feature_set(), &ComputeBudget::default(), true, false, @@ -235,10 +235,10 @@ fn bench_create_vm(bencher: &mut Bencher) { invoke_context.mock_set_remaining(BUDGET); let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&bpf_account_data_direct_mapping::id()); let program_runtime_environment = create_program_runtime_environment_v1( - &invoke_context.feature_set, + invoke_context.get_feature_set(), &ComputeBudget::default(), true, false, @@ -280,7 +280,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { invoke_context.mock_set_remaining(BUDGET); let direct_mapping = invoke_context - .feature_set + .get_feature_set() .is_active(&bpf_account_data_direct_mapping::id()); // Serialize account data @@ -295,7 +295,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { .unwrap(); let program_runtime_environment = create_program_runtime_environment_v1( - &invoke_context.feature_set, + invoke_context.get_feature_set(), &ComputeBudget::default(), true, false, diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 9b4f60b877..b0c8eadc45 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -145,7 +145,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &clock, &stake_history, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } StakeInstruction::Split(lamports) => { @@ -310,7 +310,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| set_lockup(&mut me, &lockup, &signers, &clock) } StakeInstruction::GetMinimumDelegation => { - let feature_set = invoke_context.feature_set.as_ref(); + let feature_set = invoke_context.get_feature_set(); let minimum_delegation = crate::get_minimum_delegation(feature_set); let minimum_delegation = Vec::from(minimum_delegation.to_le_bytes()); invoke_context @@ -335,7 +335,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| StakeInstruction::Redelegate => { let mut me = get_stake_account()?; if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::stake_redelegate_instruction::id()) { instruction_context.check_number_of_instruction_accounts(3)?; @@ -460,7 +460,7 @@ mod tests { expected_result, Entrypoint::vm, |invoke_context| { - invoke_context.feature_set = Arc::clone(&feature_set); + invoke_context.mock_set_feature_set(Arc::clone(&feature_set)); }, |_invoke_context| {}, ) @@ -6889,11 +6889,11 @@ mod tests { Ok(()), Entrypoint::vm, |invoke_context| { - invoke_context.feature_set = Arc::clone(&feature_set); + invoke_context.mock_set_feature_set(Arc::clone(&feature_set)); }, |invoke_context| { let expected_minimum_delegation = - crate::get_minimum_delegation(&invoke_context.feature_set).to_le_bytes(); + crate::get_minimum_delegation(invoke_context.get_feature_set()).to_le_bytes(); let actual_minimum_delegation = invoke_context.transaction_context.get_return_data().1; assert_eq!(expected_minimum_delegation, actual_minimum_delegation); diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index f20283cfbd..3e49f0f872 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -64,7 +64,7 @@ pub(crate) fn new_warmup_cooldown_rate_epoch(invoke_context: &InvokeContext) -> .get_epoch_schedule() .unwrap(); invoke_context - .feature_set + .get_feature_set() .new_warmup_cooldown_rate_epoch(epoch_schedule.as_ref()) } @@ -94,7 +94,7 @@ fn redelegate_stake( // If stake is currently active: if stake.stake(clock.epoch, stake_history, new_rate_activation_epoch) != 0 { let stake_lamports_ok = if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::stake_redelegate_instruction::id()) { // When a stake account is redelegated, the delegated lamports from the source stake @@ -301,7 +301,7 @@ fn deactivate_stake( epoch: Epoch, ) -> Result<(), InstructionError> { if invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::stake_redelegate_instruction::id()) { if stake_flags.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED) { @@ -402,7 +402,8 @@ pub fn split( match stake_state { StakeStateV2::Stake(meta, mut stake, stake_flags) => { meta.authorized.check(signers, StakeAuthorize::Staker)?; - let minimum_delegation = crate::get_minimum_delegation(&invoke_context.feature_set); + let minimum_delegation = + crate::get_minimum_delegation(invoke_context.get_feature_set()); let is_active = { let clock = invoke_context.get_sysvar_cache().get_clock()?; let status = get_stake_status(invoke_context, &stake, &clock)?; @@ -688,7 +689,7 @@ pub fn redelegate( let ValidatedDelegatedInfo { stake_amount } = validate_delegated_amount( &uninitialized_stake_account, &uninitialized_stake_meta, - &invoke_context.feature_set, + invoke_context.get_feature_set(), )?; uninitialized_stake_account.set_state(&StakeStateV2::Stake( uninitialized_stake_meta, diff --git a/programs/system/src/system_instruction.rs b/programs/system/src/system_instruction.rs index 95860379fb..57353e73d7 100644 --- a/programs/system/src/system_instruction.rs +++ b/programs/system/src/system_instruction.rs @@ -42,7 +42,8 @@ pub fn advance_nonce_account( ); return Err(InstructionError::MissingRequiredSignature); } - let next_durable_nonce = DurableNonce::from_blockhash(&invoke_context.blockhash); + let next_durable_nonce = + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash); if data.durable_nonce == next_durable_nonce { ic_msg!( invoke_context, @@ -54,7 +55,7 @@ pub fn advance_nonce_account( let new_data = nonce::state::Data::new( data.authority, next_durable_nonce, - invoke_context.lamports_per_signature, + invoke_context.environment_config.lamports_per_signature, ); account.set_state(&Versions::new(State::Initialized(new_data))) } @@ -106,7 +107,8 @@ pub fn withdraw_nonce_account( } State::Initialized(ref data) => { if lamports == from.get_lamports() { - let durable_nonce = DurableNonce::from_blockhash(&invoke_context.blockhash); + let durable_nonce = + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash); if data.durable_nonce == durable_nonce { ic_msg!( invoke_context, @@ -177,11 +179,12 @@ pub fn initialize_nonce_account( ); return Err(InstructionError::InsufficientFunds); } - let durable_nonce = DurableNonce::from_blockhash(&invoke_context.blockhash); + let durable_nonce = + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash); let data = nonce::state::Data::new( *nonce_authority, durable_nonce, - invoke_context.lamports_per_signature, + invoke_context.environment_config.lamports_per_signature, ); let state = State::Initialized(data); account.set_state(&Versions::new(state)) @@ -306,8 +309,10 @@ mod test { macro_rules! set_invoke_context_blockhash { ($invoke_context:expr, $seed:expr) => { - $invoke_context.blockhash = hash(&bincode::serialize(&$seed).unwrap()); - $invoke_context.lamports_per_signature = ($seed as u64).saturating_mul(100); + $invoke_context.environment_config.blockhash = + hash(&bincode::serialize(&$seed).unwrap()); + $invoke_context.environment_config.lamports_per_signature = + ($seed as u64).saturating_mul(100); }; } @@ -343,8 +348,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( data.authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); // First nonce instruction drives state from Uninitialized to Initialized assert_eq!(versions.state(), &State::Initialized(data.clone())); @@ -353,8 +358,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( data.authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); // Second nonce instruction consumes and replaces stored nonce assert_eq!(versions.state(), &State::Initialized(data.clone())); @@ -363,8 +368,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( data.authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); // Third nonce instruction for fun and profit assert_eq!(versions.state(), &State::Initialized(data)); @@ -422,8 +427,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); assert_eq!(versions.state(), &State::Initialized(data)); // Nonce account did not sign @@ -734,8 +739,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); assert_eq!(versions.state(), &State::Initialized(data.clone())); let withdraw_lamports = 42; @@ -763,8 +768,8 @@ mod test { let versions = nonce_account.get_state::().unwrap(); let data = nonce::state::Data::new( data.authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); assert_eq!(versions.state(), &State::Initialized(data)); assert_eq!(nonce_account.get_lamports(), from_expect_lamports); @@ -955,8 +960,8 @@ mod test { initialize_nonce_account(&mut nonce_account, &authorized, &rent, &invoke_context); let data = nonce::state::Data::new( authorized, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); assert_eq!(result, Ok(())); let versions = nonce_account.get_state::().unwrap(); @@ -1024,8 +1029,8 @@ mod test { let authority = Pubkey::default(); let data = nonce::state::Data::new( authority, - DurableNonce::from_blockhash(&invoke_context.blockhash), - invoke_context.lamports_per_signature, + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash), + invoke_context.environment_config.lamports_per_signature, ); authorize_nonce_account(&mut nonce_account, &authority, &signers, &invoke_context).unwrap(); let versions = nonce_account.get_state::().unwrap(); @@ -1104,7 +1109,8 @@ mod test { .get_account_at_index(NONCE_ACCOUNT_INDEX) .unwrap() .borrow(), - DurableNonce::from_blockhash(&invoke_context.blockhash).as_hash(), + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash) + .as_hash(), ), Some(_) ); @@ -1165,7 +1171,8 @@ mod test { .get_account_at_index(NONCE_ACCOUNT_INDEX) .unwrap() .borrow(), - DurableNonce::from_blockhash(&invoke_context.blockhash).as_hash(), + DurableNonce::from_blockhash(&invoke_context.environment_config.blockhash) + .as_hash(), ), None ); diff --git a/programs/system/src/system_processor.rs b/programs/system/src/system_processor.rs index 57cd8e546f..d455fb84ba 100644 --- a/programs/system/src/system_processor.rs +++ b/programs/system/src/system_processor.rs @@ -1578,7 +1578,7 @@ mod tests { Ok(()), Entrypoint::vm, |invoke_context: &mut InvokeContext| { - invoke_context.blockhash = hash(&serialize(&0).unwrap()); + invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap()); }, |_invoke_context| {}, ); @@ -1925,7 +1925,7 @@ mod tests { Err(SystemError::NonceNoRecentBlockhashes.into()), Entrypoint::vm, |invoke_context: &mut InvokeContext| { - invoke_context.blockhash = hash(&serialize(&0).unwrap()); + invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap()); }, |_invoke_context| {}, ); diff --git a/programs/vote/src/vote_processor.rs b/programs/vote/src/vote_processor.rs index 02225ceb1d..b43b874de6 100644 --- a/programs/vote/src/vote_processor.rs +++ b/programs/vote/src/vote_processor.rs @@ -46,7 +46,7 @@ fn process_authorize_with_seed_instruction( authorization_type, &expected_authority_keys, &clock, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } @@ -80,7 +80,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &vote_init, &signers, &clock, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::Authorize(voter_pubkey, vote_authorize) => { @@ -92,7 +92,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| vote_authorize, &signers, &clock, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::AuthorizeWithSeed(args) => { @@ -136,7 +136,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &mut me, node_pubkey, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::UpdateCommission(commission) => { @@ -148,7 +148,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &signers, sysvar_cache.get_epoch_schedule()?.as_ref(), sysvar_cache.get_clock()?.as_ref(), - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { @@ -162,7 +162,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &clock, &vote, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::UpdateVoteState(vote_state_update) @@ -176,7 +176,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &clock, vote_state_update, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::CompactUpdateVoteState(vote_state_update) @@ -190,13 +190,13 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &clock, vote_state_update, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::TowerSync(tower_sync) | VoteInstruction::TowerSyncSwitch(tower_sync, _) => { if !invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::enable_tower_sync_ix::id()) { return Err(InstructionError::InvalidInstructionData); @@ -210,7 +210,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &clock, tower_sync, &signers, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::Withdraw(lamports) => { @@ -228,7 +228,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| &signers, &rent_sysvar, &clock_sysvar, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } VoteInstruction::AuthorizeChecked(vote_authorize) => { @@ -247,7 +247,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| vote_authorize, &signers, &clock, - &invoke_context.feature_set, + invoke_context.get_feature_set(), ) } } @@ -337,7 +337,7 @@ mod tests { expected_result, Entrypoint::vm, |invoke_context| { - invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default()); + invoke_context.mock_set_feature_set(std::sync::Arc::new(FeatureSet::default())); }, |_invoke_context| {}, ) diff --git a/programs/zk-token-proof/src/lib.rs b/programs/zk-token-proof/src/lib.rs index a90d321212..32b7b69ed0 100644 --- a/programs/zk-token-proof/src/lib.rs +++ b/programs/zk-token-proof/src/lib.rs @@ -51,7 +51,7 @@ where // if instruction data is exactly 5 bytes, then read proof from an account let context_data = if instruction_data.len() == INSTRUCTION_DATA_LENGTH_WITH_PROOF_ACCOUNT { if !invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::enable_zk_proof_from_account::id()) { return Err(InstructionError::InvalidInstructionData); @@ -184,7 +184,7 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(), declare_process_instruction!(Entrypoint, 0, |invoke_context| { let enable_zk_transfer_with_fee = invoke_context - .feature_set + .get_feature_set() .is_active(&feature_set::enable_zk_transfer_with_fee::id()); let transaction_context = &invoke_context.transaction_context; diff --git a/runtime/src/bank/builtins/core_bpf_migration/mod.rs b/runtime/src/bank/builtins/core_bpf_migration/mod.rs index f1fc3a8598..2c71d91935 100644 --- a/runtime/src/bank/builtins/core_bpf_migration/mod.rs +++ b/runtime/src/bank/builtins/core_bpf_migration/mod.rs @@ -8,7 +8,8 @@ use { error::CoreBpfMigrationError, num_traits::{CheckedAdd, CheckedSub}, solana_program_runtime::{ - invoke_context::InvokeContext, loaded_programs::ProgramCacheForTxBatch, + invoke_context::{EnvironmentConfig, InvokeContext}, + loaded_programs::ProgramCacheForTxBatch, sysvar_cache::SysvarCache, }, solana_sdk::{ @@ -174,14 +175,11 @@ impl Bank { let mut dummy_invoke_context = InvokeContext::new( &mut dummy_transaction_context, - &sysvar_cache, + EnvironmentConfig::new(Hash::default(), self.feature_set.clone(), 0, &sysvar_cache), None, compute_budget, &programs_loaded, &mut programs_modified, - self.feature_set.clone(), - Hash::default(), - 0, ); solana_bpf_loader_program::direct_deploy_program( diff --git a/svm/src/message_processor.rs b/svm/src/message_processor.rs index 15de67d204..112d9c67e4 100644 --- a/svm/src/message_processor.rs +++ b/svm/src/message_processor.rs @@ -47,8 +47,9 @@ impl MessageProcessor { .zip(program_indices.iter()) .enumerate() { - let is_precompile = - is_precompile(program_id, |id| invoke_context.feature_set.is_active(id)); + let is_precompile = is_precompile(program_id, |id| { + invoke_context.get_feature_set().is_active(id) + }); // Fixup the special instructions key if present // before the account pre-values are taken care of @@ -148,6 +149,7 @@ mod tests { solana_program_runtime::{ compute_budget::ComputeBudget, declare_process_instruction, + invoke_context::EnvironmentConfig, loaded_programs::{ProgramCacheEntry, ProgramCacheForTxBatch}, sysvar_cache::SysvarCache, }, @@ -272,16 +274,19 @@ mod tests { )); let sysvar_cache = SysvarCache::default(); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -323,16 +328,19 @@ mod tests { ]), )); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -364,16 +372,19 @@ mod tests { ]), )); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -496,16 +507,19 @@ mod tests { )); let sysvar_cache = SysvarCache::default(); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -532,16 +546,19 @@ mod tests { Some(transaction_context.get_key_of_account_at_index(0).unwrap()), )); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -565,16 +582,19 @@ mod tests { Some(transaction_context.get_key_of_account_at_index(0).unwrap()), )); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, @@ -659,16 +679,19 @@ mod tests { Arc::new(ProgramCacheEntry::new_builtin(0, 0, MockBuiltin::vm)), ); let mut programs_modified_by_tx = ProgramCacheForTxBatch::default(); + let environment_config = EnvironmentConfig::new( + Hash::default(), + Arc::new(FeatureSet::all_enabled()), + 0, + &sysvar_cache, + ); let mut invoke_context = InvokeContext::new( &mut transaction_context, - &sysvar_cache, + environment_config, None, ComputeBudget::default(), &programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - Arc::new(FeatureSet::all_enabled()), - Hash::default(), - 0, ); let result = MessageProcessor::process_message( &message, diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index 4fb54e5a1f..2b75da5d97 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -19,7 +19,7 @@ use { solana_measure::measure::Measure, solana_program_runtime::{ compute_budget::ComputeBudget, - invoke_context::InvokeContext, + invoke_context::{EnvironmentConfig, InvokeContext}, loaded_programs::{ ForkGraph, ProgramCache, ProgramCacheEntry, ProgramCacheForTxBatch, ProgramCacheMatchCriteria, @@ -534,14 +534,16 @@ impl TransactionBatchProcessor { let mut invoke_context = InvokeContext::new( &mut transaction_context, - sysvar_cache, + EnvironmentConfig::new( + blockhash, + callback.get_feature_set(), + lamports_per_signature, + sysvar_cache, + ), log_collector.clone(), compute_budget, programs_loaded_for_tx_batch, &mut programs_modified_by_tx, - callback.get_feature_set(), - blockhash, - lamports_per_signature, ); let mut process_message_time = Measure::start("process_message_time");