diff --git a/chain/chain/src/runtime/mod.rs b/chain/chain/src/runtime/mod.rs index a3999d87573..3468a69fd64 100644 --- a/chain/chain/src/runtime/mod.rs +++ b/chain/chain/src/runtime/mod.rs @@ -495,7 +495,12 @@ impl NightshadeRuntime { let contract_cache = compiled_contract_cache.as_deref(); let slot_sender = slot_sender.clone(); scope.spawn(move |_| { - precompile_contract(&code, &runtime_config.wasm_config, contract_cache).ok(); + precompile_contract( + &code, + Arc::clone(&runtime_config.wasm_config), + contract_cache, + ) + .ok(); // If this fails, it just means there won't be any more attempts to recv the // slots let _ = slot_sender.send(()); diff --git a/core/parameters/src/config.rs b/core/parameters/src/config.rs index ccec9d003c4..584b361d8ac 100644 --- a/core/parameters/src/config.rs +++ b/core/parameters/src/config.rs @@ -1,12 +1,12 @@ //! Settings of the parameters of the runtime. +use super::parameter_table::InvalidConfigError; use crate::config_store::INITIAL_TESTNET_CONFIG; use crate::cost::RuntimeFeesConfig; use crate::parameter_table::ParameterTable; use near_account_id::AccountId; use near_primitives_core::types::{Balance, Gas}; use near_primitives_core::version::PROTOCOL_VERSION; - -use super::parameter_table::InvalidConfigError; +use std::sync::Arc; // Lowered promise yield timeout length used in integration tests. // The resharding tests for yield timeouts take too long to run otherwise. @@ -19,12 +19,12 @@ pub struct RuntimeConfig { /// /// This contains parameters that are required by the WASM runtime and the /// transaction runtime. - pub fees: RuntimeFeesConfig, + pub fees: Arc, /// Config of wasm operations, also includes wasm gas costs. /// /// This contains all the configuration parameters that are only required by /// the WASM runtime. - pub wasm_config: crate::vm::Config, + pub wasm_config: Arc, /// Config that defines rules for account creation. pub account_creation_config: AccountCreationConfig, /// The configuration for congestion control. @@ -54,8 +54,8 @@ impl RuntimeConfig { wasm_config.limit_config.yield_timeout_length_in_blocks = TEST_CONFIG_YIELD_TIMEOUT_LENGTH; RuntimeConfig { - fees: RuntimeFeesConfig::test(), - wasm_config, + fees: Arc::new(RuntimeFeesConfig::test()), + wasm_config: Arc::new(wasm_config), account_creation_config: AccountCreationConfig::default(), congestion_control_config: runtime_config.congestion_control_config, witness_config: runtime_config.witness_config, @@ -70,8 +70,8 @@ impl RuntimeConfig { wasm_config.make_free(); Self { - fees: RuntimeFeesConfig::free(), - wasm_config, + fees: Arc::new(RuntimeFeesConfig::free()), + wasm_config: Arc::new(wasm_config), account_creation_config: AccountCreationConfig::default(), congestion_control_config: runtime_config.congestion_control_config, witness_config: runtime_config.witness_config, diff --git a/core/parameters/src/config_store.rs b/core/parameters/src/config_store.rs index 85a3b0fd8cc..a6eeb505414 100644 --- a/core/parameters/src/config_store.rs +++ b/core/parameters/src/config_store.rs @@ -85,7 +85,8 @@ impl RuntimeConfigStore { #[cfg(feature = "calimero_zero_storage")] { let mut initial_config = RuntimeConfig::new(¶ms).unwrap_or_else(|err| panic!("Failed generating `RuntimeConfig` from parameters for base parameter file. Error: {err}")); - initial_config.fees.storage_usage_config.storage_amount_per_byte = 0; + let fees = Arc::make_mut(&mut initial_config.fees); + fees.storage_usage_config.storage_amount_per_byte = 0; store.insert(0, Arc::new(initial_config)); } @@ -100,17 +101,26 @@ impl RuntimeConfigStore { #[cfg(feature = "calimero_zero_storage")] { let mut runtime_config = RuntimeConfig::new(¶ms).unwrap_or_else(|err| panic!("Failed generating `RuntimeConfig` from parameters for version {protocol_version}. Error: {err}")); - runtime_config.fees.storage_usage_config.storage_amount_per_byte = 0; + let fees = Arc::make_mut(&mut runtime_config.fees); + fees.storage_usage_config.storage_amount_per_byte = 0; store.insert(*protocol_version, Arc::new(runtime_config)); } } if let Some(runtime_config) = genesis_runtime_config { - let mut config = runtime_config.clone(); - store.insert(0, Arc::new(config.clone())); - - config.fees.storage_usage_config.storage_amount_per_byte = 10u128.pow(19); - store.insert(42, Arc::new(config)); + let mut fees = crate::RuntimeFeesConfig::clone(&runtime_config.fees); + fees.storage_usage_config.storage_amount_per_byte = 10u128.pow(19); + store.insert( + 42, + Arc::new(RuntimeConfig { + fees: Arc::new(fees), + wasm_config: Arc::clone(&runtime_config.wasm_config), + account_creation_config: runtime_config.account_creation_config.clone(), + congestion_control_config: runtime_config.congestion_control_config, + witness_config: runtime_config.witness_config, + }), + ); + store.insert(0, Arc::new(runtime_config.clone())); } Self { store } diff --git a/core/parameters/src/parameter_table.rs b/core/parameters/src/parameter_table.rs index 82558254c91..77d25e2251f 100644 --- a/core/parameters/src/parameter_table.rs +++ b/core/parameters/src/parameter_table.rs @@ -10,6 +10,7 @@ use near_primitives_core::account::id::ParseAccountError; use near_primitives_core::types::AccountId; use num_rational::Rational32; use std::collections::BTreeMap; +use std::sync::Arc; /// Represents values supported by parameter config. #[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq)] @@ -290,7 +291,7 @@ impl TryFrom<&ParameterTable> for RuntimeConfig { fn try_from(params: &ParameterTable) -> Result { Ok(RuntimeConfig { - fees: RuntimeFeesConfig { + fees: Arc::new(RuntimeFeesConfig { action_fees: enum_map::enum_map! { action_cost => params.get_fee(action_cost)? }, @@ -302,8 +303,8 @@ impl TryFrom<&ParameterTable> for RuntimeConfig { num_bytes_account: params.get(Parameter::StorageNumBytesAccount)?, num_extra_bytes_record: params.get(Parameter::StorageNumExtraBytesRecord)?, }, - }, - wasm_config: Config { + }), + wasm_config: Arc::new(Config { ext_costs: ExtCostsConfig { costs: enum_map::enum_map! { cost => params.get(cost.param())? @@ -327,7 +328,7 @@ impl TryFrom<&ParameterTable> for RuntimeConfig { function_call_weight: params.get(Parameter::FunctionCallWeight)?, eth_implicit_accounts: params.get(Parameter::EthImplicitAccounts)?, yield_resume_host_functions: params.get(Parameter::YieldResume)?, - }, + }), account_creation_config: AccountCreationConfig { min_allowed_top_level_account_length: params .get(Parameter::MinAllowedTopLevelAccountLength)?, diff --git a/core/parameters/src/view.rs b/core/parameters/src/view.rs index 99588594ebe..3839577a44f 100644 --- a/core/parameters/src/view.rs +++ b/core/parameters/src/view.rs @@ -185,7 +185,7 @@ impl From for RuntimeConfigView { .fees .pessimistic_gas_price_inflation_ratio, }, - wasm_config: VMConfigView::from(config.wasm_config), + wasm_config: VMConfigView::from(crate::vm::Config::clone(&config.wasm_config)), account_creation_config: AccountCreationConfigView { min_allowed_top_level_account_length: config .account_creation_config diff --git a/genesis-tools/genesis-populate/src/lib.rs b/genesis-tools/genesis-populate/src/lib.rs index c6189feec4b..7e7ba1fa496 100644 --- a/genesis-tools/genesis-populate/src/lib.rs +++ b/genesis-tools/genesis-populate/src/lib.rs @@ -184,7 +184,7 @@ impl GenesisBuilder { let mut state_update = self.state_updates.remove(&shard_idx).expect("State updates are always available"); let protocol_config = self.runtime.get_protocol_config(&EpochId::default())?; - let storage_usage_config = protocol_config.runtime_config.fees.storage_usage_config; + let storage_usage_config = protocol_config.runtime_config.fees.storage_usage_config.clone(); // Compute storage usage and update accounts. for (account_id, storage_usage) in compute_storage_usage(&records, &storage_usage_config) { diff --git a/integration-tests/src/tests/client/features/congestion_control.rs b/integration-tests/src/tests/client/features/congestion_control.rs index 11c4ff37ca0..c745fe4dd4c 100644 --- a/integration-tests/src/tests/client/features/congestion_control.rs +++ b/integration-tests/src/tests/client/features/congestion_control.rs @@ -34,7 +34,8 @@ fn setup_runtime(sender_id: AccountId, protocol_version: ProtocolVersion) -> Tes let mut config = RuntimeConfig::test(); // Make 1 wasm op cost ~4 GGas, to let "loop_forever" finish more quickly. - config.wasm_config.regular_op_cost = u32::MAX; + let wasm_config = Arc::make_mut(&mut config.wasm_config); + wasm_config.regular_op_cost = u32::MAX; let runtime_configs = vec![RuntimeConfigStore::with_one_config(config)]; TestEnv::builder(&genesis.config) diff --git a/integration-tests/src/tests/client/features/zero_balance_account.rs b/integration-tests/src/tests/client/features/zero_balance_account.rs index b5ea8458c8e..3d1854cb42e 100644 --- a/integration-tests/src/tests/client/features/zero_balance_account.rs +++ b/integration-tests/src/tests/client/features/zero_balance_account.rs @@ -1,5 +1,4 @@ use assert_matches::assert_matches; - use near_chain_configs::Genesis; use near_client::test_utils::TestEnv; use near_crypto::{InMemorySigner, KeyType, PublicKey, Signer}; @@ -15,6 +14,7 @@ use near_primitives::version::{ProtocolFeature, PROTOCOL_VERSION}; use near_primitives::views::{FinalExecutionStatus, QueryRequest, QueryResponseKind}; use nearcore::test_utils::TestEnvNightshadeSetupExt; use node_runtime::ZERO_BALANCE_ACCOUNT_STORAGE_LIMIT; +use std::sync::Arc; /// Assert that an account exists and has zero balance fn assert_zero_balance_account(env: &TestEnv, account_id: &AccountId) { @@ -123,12 +123,14 @@ fn test_zero_balance_account_add_key() { // create free runtime config for transaction costs to make it easier to assert // the exact amount of tokens on accounts let mut runtime_config = RuntimeConfig::free(); - runtime_config.fees.storage_usage_config = StorageUsageConfig { + let fees = Arc::make_mut(&mut runtime_config.fees); + fees.storage_usage_config = StorageUsageConfig { storage_amount_per_byte: 10u128.pow(19), num_bytes_account: 100, num_extra_bytes_record: 40, }; - runtime_config.wasm_config.ext_costs = ExtCostsConfig::test(); + let wasm_config = Arc::make_mut(&mut runtime_config.wasm_config); + wasm_config.ext_costs = ExtCostsConfig::test(); let runtime_config_store = RuntimeConfigStore::with_one_config(runtime_config); let mut env = TestEnv::builder(&genesis.config) .nightshade_runtimes_with_runtime_config_store(&genesis, vec![runtime_config_store]) diff --git a/integration-tests/src/tests/standard_cases/runtime.rs b/integration-tests/src/tests/standard_cases/runtime.rs index ac2cadf7e3e..79520ba543d 100644 --- a/integration-tests/src/tests/standard_cases/runtime.rs +++ b/integration-tests/src/tests/standard_cases/runtime.rs @@ -5,6 +5,7 @@ use near_crypto::SecretKey; use near_primitives::checked_feature; use near_primitives::state_record::StateRecord; use near_primitives::version::PROTOCOL_VERSION; +use std::sync::Arc; use testlib::runtime_utils::{add_test_contract, alice_account, bob_account}; fn create_runtime_node() -> RuntimeNode { @@ -21,7 +22,8 @@ fn create_runtime_with_expensive_storage() -> RuntimeNode { add_test_contract(&mut genesis, &bob_account()); // Set expensive state requirements and add alice more money. let mut runtime_config = RuntimeConfig::test(); - runtime_config.fees.storage_usage_config.storage_amount_per_byte = TESTING_INIT_BALANCE / 1000; + let fees = Arc::make_mut(&mut runtime_config.fees); + fees.storage_usage_config.storage_amount_per_byte = TESTING_INIT_BALANCE / 1000; let records = genesis.force_read_records().as_mut(); match &mut records[0] { StateRecord::Account { account, .. } => account.set_amount(TESTING_INIT_BALANCE * 10000), diff --git a/runtime/near-vm-runner/fuzz/fuzz_targets/diffrunner.rs b/runtime/near-vm-runner/fuzz/fuzz_targets/diffrunner.rs index 291dbc3f92d..36eacd8465a 100644 --- a/runtime/near-vm-runner/fuzz/fuzz_targets/diffrunner.rs +++ b/runtime/near-vm-runner/fuzz/fuzz_targets/diffrunner.rs @@ -9,6 +9,7 @@ use near_vm_runner::logic::mocks::mock_external::MockedExternal; use near_vm_runner::logic::VMOutcome; use near_vm_runner::ContractCode; use near_vm_runner_fuzz::{create_context, find_entry_point, ArbitraryModule}; +use std::sync::Arc; libfuzzer_sys::fuzz_target!(|module: ArbitraryModule| { let code = ContractCode::new(module.0.module.to_bytes(), None); @@ -23,20 +24,18 @@ fn run_fuzz(code: &ContractCode, vm_kind: VMKind) -> VMOutcome { context.prepaid_gas = 10u64.pow(14); let config_store = RuntimeConfigStore::new(None); let config = config_store.get_config(PROTOCOL_VERSION); - let fees = &config.fees; - let mut wasm_config = config.wasm_config.clone(); + let fees = Arc::clone(&config.fees); + let mut wasm_config = near_parameters::vm::Config::clone(&config.wasm_config); wasm_config.limit_config.contract_prepare_version = near_vm_runner::logic::ContractPrepareVersion::V2; - let promise_results = vec![]; - let method_name = find_entry_point(code).unwrap_or_else(|| "main".to_string()); - let res = vm_kind.runtime(wasm_config).unwrap().run( + let res = vm_kind.runtime(wasm_config.into()).unwrap().run( &method_name, &mut fake_external, &context, fees, - &promise_results, + [].into(), None, ); diff --git a/runtime/near-vm-runner/fuzz/fuzz_targets/runner.rs b/runtime/near-vm-runner/fuzz/fuzz_targets/runner.rs index 21377faeefc..5f58401cae6 100644 --- a/runtime/near-vm-runner/fuzz/fuzz_targets/runner.rs +++ b/runtime/near-vm-runner/fuzz/fuzz_targets/runner.rs @@ -20,16 +20,14 @@ fn run_fuzz(code: &ContractCode, config: Arc) -> VMOutcome { let mut fake_external = MockedExternal::with_code(code.clone_for_tests()); let mut context = create_context(vec![]); context.prepaid_gas = 10u64.pow(14); - let mut wasm_config = config.wasm_config.clone(); + let mut wasm_config = near_parameters::vm::Config::clone(&config.wasm_config); wasm_config.limit_config.wasmer2_stack_limit = i32::MAX; // If we can crash wasmer2 even without the secondary stack limit it's still good to know let vm_kind = config.wasm_config.vm_kind; - let fees = &config.fees; - let promise_results = vec![]; - + let fees = Arc::clone(&config.fees); let method_name = find_entry_point(code).unwrap_or_else(|| "main".to_string()); vm_kind - .runtime(wasm_config) + .runtime(wasm_config.into()) .unwrap() - .run(&method_name, &mut fake_external, &context, fees, &promise_results, None) + .run(&method_name, &mut fake_external, &context, fees, [].into(), None) .unwrap_or_else(|err| panic!("fatal error: {err:?}")) } diff --git a/runtime/near-vm-runner/src/cache.rs b/runtime/near-vm-runner/src/cache.rs index a5d87c2fd1b..13ebee29a94 100644 --- a/runtime/near-vm-runner/src/cache.rs +++ b/runtime/near-vm-runner/src/cache.rs @@ -475,19 +475,19 @@ impl AnyCache { /// is already in the cache, or if cache is `None`. pub fn precompile_contract( code: &ContractCode, - config: &Config, + config: Arc, cache: Option<&dyn ContractRuntimeCache>, ) -> Result, CacheError> { let _span = tracing::debug_span!(target: "vm", "precompile_contract").entered(); let vm_kind = config.vm_kind; let runtime = vm_kind - .runtime(config.clone()) + .runtime(Arc::clone(&config)) .unwrap_or_else(|| panic!("the {vm_kind:?} runtime has not been enabled at compile time")); let cache = match cache { Some(it) => it, None => return Ok(Ok(ContractPrecompilatonResult::CacheNotAvailable)), }; - let key = get_contract_cache_key(*code.hash(), config); + let key = get_contract_cache_key(*code.hash(), &config); // Check if we already cached with such a key. if cache.has(&key).map_err(CacheError::ReadError)? { return Ok(Ok(ContractPrecompilatonResult::ContractAlreadyInCache)); diff --git a/runtime/near-vm-runner/src/logic/logic.rs b/runtime/near-vm-runner/src/logic/logic.rs index 257fd3ded45..4294c63ae1b 100644 --- a/runtime/near-vm-runner/src/logic/logic.rs +++ b/runtime/near-vm-runner/src/logic/logic.rs @@ -19,6 +19,7 @@ use near_primitives_core::types::{ AccountId, Balance, Compute, EpochHeight, Gas, GasWeight, StorageUsage, }; use std::mem::size_of; +use std::sync::Arc; use ExtCosts::*; pub type Result = ::std::result::Result; @@ -36,12 +37,12 @@ pub struct VMLogic<'a> { /// Part of Context API and Economics API that was extracted from the receipt. context: &'a VMContext, /// All gas and economic parameters required during contract execution. - pub(crate) config: &'a Config, - /// Fees for creating (async) actions on runtime. - fees_config: &'a RuntimeFeesConfig, + pub(crate) config: Arc, + /// Fees charged for various operations that contract may execute. + fees_config: Arc, /// If this method execution is invoked directly as a callback by one or more contract calls the /// results of the methods that made the callback are stored in this collection. - promise_results: &'a [PromiseResult], + promise_results: Arc<[PromiseResult]>, /// Pointer to the guest memory. memory: super::vmstate::Memory, @@ -132,9 +133,9 @@ impl<'a> VMLogic<'a> { pub fn new( ext: &'a mut dyn External, context: &'a VMContext, - config: &'a Config, - fees_config: &'a RuntimeFeesConfig, - promise_results: &'a [PromiseResult], + config: Arc, + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, memory: impl MemoryLike + 'static, ) -> Self { // Overflow should be checked before calling VMLogic. @@ -157,6 +158,7 @@ impl<'a> VMLogic<'a> { ext.get_recorded_storage_size(), config.limit_config.per_receipt_storage_proof_size_limit, ); + let remaining_stack = u64::from(config.limit_config.max_stack_height); Self { ext, context, @@ -174,7 +176,7 @@ impl<'a> VMLogic<'a> { registers: Default::default(), promises: vec![], total_log_length: 0, - remaining_stack: u64::from(config.limit_config.max_stack_height), + remaining_stack, } } @@ -1798,14 +1800,14 @@ impl<'a> VMLogic<'a> { let (receipt_idx, sir) = self.promise_idx_to_receipt_idx_with_sir(promise_idx)?; let receiver_id = self.ext.get_receipt_receiver(receipt_idx); let send_fee = transfer_send_fee( - self.fees_config, + &self.fees_config, sir, self.config.implicit_account_creation, self.config.eth_implicit_accounts, receiver_id.get_account_type(), ); let exec_fee = transfer_exec_fee( - self.fees_config, + &self.fees_config, self.config.implicit_account_creation, self.config.eth_implicit_accounts, receiver_id.get_account_type(), diff --git a/runtime/near-vm-runner/src/logic/tests/promises.rs b/runtime/near-vm-runner/src/logic/tests/promises.rs index 1dc0d2540c0..4fd3cebf982 100644 --- a/runtime/near-vm-runner/src/logic/tests/promises.rs +++ b/runtime/near-vm-runner/src/logic/tests/promises.rs @@ -12,14 +12,14 @@ fn vm_receipts<'a>(ext: &'a MockedExternal) -> Vec { #[test] fn test_promise_results() { - let promise_results = vec![ + let promise_results = [ PromiseResult::Successful(b"test".to_vec()), PromiseResult::Failed, PromiseResult::NotReady, ]; let mut logic_builder = VMLogicBuilder::default(); - logic_builder.promise_results = promise_results; + logic_builder.promise_results = promise_results.into(); let mut logic = logic_builder.build(); assert_eq!(logic.promise_results_count(), Ok(3), "Total count of registers must be 3"); diff --git a/runtime/near-vm-runner/src/logic/tests/vm_logic_builder.rs b/runtime/near-vm-runner/src/logic/tests/vm_logic_builder.rs index 14864d2fe0c..ed432087d48 100644 --- a/runtime/near-vm-runner/src/logic/tests/vm_logic_builder.rs +++ b/runtime/near-vm-runner/src/logic/tests/vm_logic_builder.rs @@ -4,12 +4,13 @@ use crate::logic::types::PromiseResult; use crate::logic::{Config, MemSlice, VMContext, VMLogic}; use crate::tests::test_vm_config; use near_parameters::RuntimeFeesConfig; +use std::sync::Arc; pub(super) struct VMLogicBuilder { pub ext: MockedExternal, pub config: Config, pub fees_config: RuntimeFeesConfig, - pub promise_results: Vec, + pub promise_results: Arc<[PromiseResult]>, pub memory: MockedMemory, pub context: VMContext, } @@ -21,7 +22,7 @@ impl Default for VMLogicBuilder { fees_config: RuntimeFeesConfig::test(), ext: MockedExternal::default(), memory: MockedMemory::default(), - promise_results: vec![], + promise_results: [].into(), context: get_context(), } } @@ -40,9 +41,9 @@ impl VMLogicBuilder { TestVMLogic::from(VMLogic::new( &mut self.ext, &self.context, - &self.config, - &self.fees_config, - &self.promise_results, + Arc::new(self.config.clone()), + Arc::new(self.fees_config.clone()), + Arc::clone(&self.promise_results), self.memory.clone(), )) } @@ -57,7 +58,7 @@ impl VMLogicBuilder { fees_config: RuntimeFeesConfig::free(), ext: MockedExternal::default(), memory: MockedMemory::default(), - promise_results: vec![], + promise_results: [].into(), context: get_context(), } } diff --git a/runtime/near-vm-runner/src/near_vm_runner/runner.rs b/runtime/near-vm-runner/src/near_vm_runner/runner.rs index 050bba91ebd..ac4faefbfd6 100644 --- a/runtime/near-vm-runner/src/near_vm_runner/runner.rs +++ b/runtime/near-vm-runner/src/near_vm_runner/runner.rs @@ -93,12 +93,12 @@ fn translate_runtime_error( } pub(crate) struct NearVM { - pub(crate) config: Config, + pub(crate) config: Arc, pub(crate) engine: UniversalEngine, } impl NearVM { - pub(crate) fn new_for_target(config: Config, target: near_vm_compiler::Target) -> Self { + pub(crate) fn new_for_target(config: Arc, target: near_vm_compiler::Target) -> Self { // We only support singlepass compiler at the moment. assert_eq!(VM_CONFIG.compiler, NearVmCompiler::Singlepass); let mut compiler = Singlepass::new(); @@ -137,7 +137,7 @@ impl NearVM { } } - pub(crate) fn new(config: Config) -> Self { + pub(crate) fn new(config: Arc) -> Self { use near_vm_compiler::{CpuFeature, Target, Triple}; let target_features = if cfg!(feature = "no_cpu_compatibility_checks") { let mut fs = CpuFeature::set(); @@ -214,8 +214,8 @@ impl NearVM { cache: &dyn ContractRuntimeCache, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, method_name: &str, closure: impl FnOnce(VMMemory, VMLogic<'_>, &VMArtifact) -> Result, ) -> VMResult { @@ -312,8 +312,14 @@ impl NearVM { // FIXME: this mostly duplicates the `run_module` method. // Note that we don't clone the actual backing memory, just increase the RC. let vmmemory = memory.vm(); - let mut logic = - VMLogic::new(ext, context, &self.config, fees_config, promise_results, memory); + let mut logic = VMLogic::new( + ext, + context, + Arc::clone(&self.config), + fees_config, + promise_results, + memory, + ); let result = logic.before_loading_executable(method_name, wasm_bytes); if let Err(e) = result { @@ -588,8 +594,8 @@ impl crate::runner::VM for NearVM { method_name: &str, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> Result { let cache = cache.unwrap_or(&NoContractRuntimeCache); diff --git a/runtime/near-vm-runner/src/runner.rs b/runtime/near-vm-runner/src/runner.rs index a9d4c0ac1a9..6a4698af9e4 100644 --- a/runtime/near-vm-runner/src/runner.rs +++ b/runtime/near-vm-runner/src/runner.rs @@ -5,6 +5,7 @@ use crate::logic::{External, VMContext, VMOutcome}; use crate::{ContractCode, ContractRuntimeCache}; use near_parameters::vm::{Config, VMKind}; use near_parameters::RuntimeFeesConfig; +use std::sync::Arc; /// Returned by VM::run method. /// @@ -50,15 +51,15 @@ pub fn run( method_name: &str, ext: &mut dyn External, context: &VMContext, - wasm_config: &Config, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + wasm_config: Arc, + fees_config: Arc, + promise_results: std::sync::Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> VMResult { let span = tracing::Span::current(); let vm_kind = wasm_config.vm_kind; let runtime = vm_kind - .runtime(wasm_config.clone()) + .runtime(wasm_config) .unwrap_or_else(|| panic!("the {vm_kind:?} runtime has not been enabled at compile time")); let outcome = runtime.run(method_name, ext, context, fees_config, promise_results, cache); let outcome = match outcome { @@ -91,8 +92,8 @@ pub trait VM { method_name: &str, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: std::sync::Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> VMResult; @@ -115,7 +116,7 @@ pub trait VMKindExt { /// /// This is not intended to be used by code other than internal tools like /// the estimator. - fn runtime(&self, config: Config) -> Option>; + fn runtime(&self, config: std::sync::Arc) -> Option>; } impl VMKindExt for VMKind { @@ -127,7 +128,7 @@ impl VMKindExt for VMKind { Self::NearVm => cfg!(all(feature = "near_vm", target_arch = "x86_64")), } } - fn runtime(&self, config: Config) -> Option> { + fn runtime(&self, config: std::sync::Arc) -> Option> { match self { #[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))] Self::Wasmer0 => Some(Box::new(crate::wasmer_runner::Wasmer0VM::new(config))), diff --git a/runtime/near-vm-runner/src/tests.rs b/runtime/near-vm-runner/src/tests.rs index bacca8c2c10..8747da037d2 100644 --- a/runtime/near-vm-runner/src/tests.rs +++ b/runtime/near-vm-runner/src/tests.rs @@ -23,7 +23,7 @@ pub(crate) fn test_vm_config() -> near_parameters::vm::Config { let config = store.get_config(PROTOCOL_VERSION).wasm_config.clone(); near_parameters::vm::Config { vm_kind: config.vm_kind.replace_with_wasmtime_if_unsupported(), - ..config + ..near_parameters::vm::Config::clone(&config) } } diff --git a/runtime/near-vm-runner/src/tests/cache.rs b/runtime/near-vm-runner/src/tests/cache.rs index 4b3c425487a..071ab443f52 100644 --- a/runtime/near-vm-runner/src/tests/cache.rs +++ b/runtime/near-vm-runner/src/tests/cache.rs @@ -19,7 +19,7 @@ use std::sync::Arc; #[test] fn test_caches_compilation_error() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { // The cache is currently properly implemented only for NearVM match vm_kind { @@ -33,7 +33,7 @@ fn test_caches_compilation_error() { let terragas = 1000000000000u64; assert_eq!(cache.len(), 0); let outcome1 = make_cached_contract_call_vm( - &config, + Arc::clone(&config), &cache, code_hash, Some(&code), @@ -45,7 +45,7 @@ fn test_caches_compilation_error() { println!("{:?}", cache); assert_eq!(cache.len(), 1); let outcome2 = make_cached_contract_call_vm( - &config, + Arc::clone(&config), &cache, code_hash, None, @@ -60,7 +60,7 @@ fn test_caches_compilation_error() { #[test] fn test_does_not_cache_io_error() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { match vm_kind { VMKind::NearVm => {} @@ -75,7 +75,7 @@ fn test_does_not_cache_io_error() { cache.set_read_fault(true); let result = make_cached_contract_call_vm( - &config, + Arc::clone(&config), &cache, code_hash, None, @@ -91,7 +91,7 @@ fn test_does_not_cache_io_error() { cache.set_write_fault(true); let result = make_cached_contract_call_vm( - &config, + Arc::clone(&config), &cache, code_hash, Some(&code), @@ -108,7 +108,7 @@ fn test_does_not_cache_io_error() { } fn make_cached_contract_call_vm( - config: &Config, + config: Arc, cache: &dyn ContractRuntimeCache, code_hash: CryptoHash, code: Option<&ContractCode>, @@ -123,11 +123,11 @@ fn make_cached_contract_call_vm( }; fake_external.code_hash = code_hash; let mut context = create_context(vec![]); - let fees = RuntimeFeesConfig::test(); - let promise_results = vec![]; + let fees = Arc::new(RuntimeFeesConfig::test()); + let promise_results = [].into(); context.prepaid_gas = prepaid_gas; - let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); - runtime.run(method_name, &mut fake_external, &context, &fees, &promise_results, Some(cache)) + let runtime = vm_kind.runtime(config).expect("runtime has not been compiled"); + runtime.run(method_name, &mut fake_external, &context, fees, promise_results, Some(cache)) } #[test] @@ -166,7 +166,7 @@ fn test_wasmer2_artifact_output_stability() { for seed in seeds { let contract = ContractCode::new(near_test_contracts::arbitrary_contract(seed), None); - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); let prepared_code = prepare::prepare_contract(contract.code(), &config, VMKind::Wasmer2).unwrap(); got_prepared_hashes.push(crate::utils::stable_hash((&contract.code(), &prepared_code))); @@ -241,7 +241,7 @@ fn test_near_vm_artifact_output_stability() { for seed in seeds { let contract = ContractCode::new(near_test_contracts::arbitrary_contract(seed), None); - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); let prepared_code = prepare::prepare_contract(contract.code(), &config, VMKind::NearVm).unwrap(); got_prepared_hashes.push(crate::utils::stable_hash((&contract.code(), &prepared_code))); diff --git a/runtime/near-vm-runner/src/tests/fuzzers.rs b/runtime/near-vm-runner/src/tests/fuzzers.rs index c58848fce64..71a2819477b 100644 --- a/runtime/near-vm-runner/src/tests/fuzzers.rs +++ b/runtime/near-vm-runner/src/tests/fuzzers.rs @@ -10,6 +10,7 @@ use arbitrary::Arbitrary; use core::fmt; use near_parameters::vm::{ContractPrepareVersion, VMKind}; use near_parameters::RuntimeFeesConfig; +use std::sync::Arc; /// Finds a no-parameter exported function, something like `(func (export "entry-point"))`. pub fn find_entry_point(contract: &ContractCode) -> Option { @@ -114,17 +115,15 @@ fn run_fuzz(code: &ContractCode, vm_kind: VMKind) -> VMResult { config.limit_config.wasmer2_stack_limit = i32::MAX; // If we can crash wasmer2 even without the secondary stack limit it's still good to know config.limit_config.contract_prepare_version = ContractPrepareVersion::V2; - let fees = RuntimeFeesConfig::test(); - - let promise_results = vec![]; - + let fees = Arc::new(RuntimeFeesConfig::test()); + let promise_results = [].into(); let method_name = find_entry_point(code).unwrap_or_else(|| "main".to_string()); - let mut res = vm_kind.runtime(config).unwrap().run( + let mut res = vm_kind.runtime(config.into()).unwrap().run( &method_name, &mut fake_external, &context, - &fees, - &promise_results, + Arc::clone(&fees), + promise_results, None, ); @@ -175,7 +174,7 @@ fn near_vm_is_reproducible_fuzzer() { bolero::check!().with_arbitrary::().for_each(|module: &ArbitraryModule| { let code = ContractCode::new(module.0.module.to_bytes(), None); - let config = test_vm_config(); + let config = std::sync::Arc::new(test_vm_config()); let mut first_hash = None; for _ in 0..3 { let vm = NearVM::new(config.clone()); diff --git a/runtime/near-vm-runner/src/tests/rs_contract.rs b/runtime/near-vm-runner/src/tests/rs_contract.rs index 7ff406f2da6..28becc703ce 100644 --- a/runtime/near-vm-runner/src/tests/rs_contract.rs +++ b/runtime/near-vm-runner/src/tests/rs_contract.rs @@ -7,6 +7,7 @@ use crate::ContractCode; use near_parameters::RuntimeFeesConfig; use near_primitives_core::types::Balance; use std::mem::size_of; +use std::sync::Arc; use super::test_vm_config; use crate::runner::VMResult; @@ -49,28 +50,34 @@ fn assert_run_result(result: VMResult, expected_value: u64) { #[test] pub fn test_read_write() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); + let fees = Arc::new(RuntimeFeesConfig::test()); with_vm_variants(&config, |vm_kind: VMKind| { let code = test_contract(vm_kind); let mut fake_external = MockedExternal::with_code(code); let context = create_context(encode(&[10u64, 20u64])); - let fees = RuntimeFeesConfig::test(); - let promise_results = vec![]; + let promise_results = [].into(); let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); let result = runtime.run( "write_key_value", &mut fake_external, &context, - &fees, - &promise_results, + Arc::clone(&fees), + Arc::clone(&promise_results), None, ); assert_run_result(result, 0); let context = create_context(encode(&[10u64])); - let result = - runtime.run("read_value", &mut fake_external, &context, &fees, &promise_results, None); + let result = runtime.run( + "read_value", + &mut fake_external, + &context, + Arc::clone(&fees), + promise_results, + None, + ); assert_run_result(result, 20); }); } @@ -79,34 +86,34 @@ macro_rules! def_test_ext { ($name:ident, $method:expr, $expected:expr, $input:expr, $validator:expr) => { #[test] pub fn $name() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { - run_test_ext(&config, $method, $expected, $input, $validator, vm_kind) + run_test_ext(Arc::clone(&config), $method, $expected, $input, $validator, vm_kind) }); } }; ($name:ident, $method:expr, $expected:expr, $input:expr) => { #[test] pub fn $name() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { - run_test_ext(&config, $method, $expected, $input, vec![], vm_kind) + run_test_ext(Arc::clone(&config), $method, $expected, $input, vec![], vm_kind) }); } }; ($name:ident, $method:expr, $expected:expr) => { #[test] pub fn $name() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { - run_test_ext(&config, $method, $expected, &[], vec![], vm_kind) + run_test_ext(Arc::clone(&config), $method, $expected, &[], vec![], vm_kind) }) } }; } fn run_test_ext( - config: &Config, + config: Arc, method: &str, expected: &[u8], input: &[u8], @@ -117,12 +124,12 @@ fn run_test_ext( let mut fake_external = MockedExternal::with_code(code); fake_external.validators = validators.into_iter().map(|(s, b)| (s.parse().unwrap(), b)).collect(); - let fees = RuntimeFeesConfig::test(); + let fees = Arc::new(RuntimeFeesConfig::test()); let context = create_context(input.to_vec()); - let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); + let runtime = vm_kind.runtime(config).expect("runtime has not been compiled"); let outcome = runtime - .run(method, &mut fake_external, &context, &fees, &[], None) + .run(method, &mut fake_external, &context, Arc::clone(&fees), [].into(), None) .unwrap_or_else(|err| panic!("Failed execution: {:?}", err)); assert_eq!(outcome.profile.action_gas(), 0); @@ -153,7 +160,7 @@ def_test_ext!(ext_storage_usage, "ext_storage_usage", &12u64.to_le_bytes()); #[test] pub fn ext_used_gas() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { // Note, the used_gas is not a global used_gas at the beginning of method, but instead a // diff in used_gas for computing fib(30) in a loop @@ -162,7 +169,7 @@ pub fn ext_used_gas() { crate::logic::ContractPrepareVersion::V1 => [111, 10, 200, 15, 0, 0, 0, 0], crate::logic::ContractPrepareVersion::V2 => [27, 180, 237, 15, 0, 0, 0, 0], }; - run_test_ext(&config, "ext_used_gas", &expected, &[], vec![], vm_kind) + run_test_ext(Arc::clone(&config), "ext_used_gas", &expected, &[], vec![], vm_kind) }) } @@ -213,6 +220,7 @@ def_test_ext!( pub fn test_out_of_memory() { let mut config = test_vm_config(); config.make_free(); + let config = Arc::new(config); with_vm_variants(&config, |vm_kind: VMKind| { // TODO: currently we only run this test on Wasmer. match vm_kind { @@ -223,12 +231,11 @@ pub fn test_out_of_memory() { let code = test_contract(vm_kind); let mut fake_external = MockedExternal::with_code(code); let context = create_context(Vec::new()); - let fees = RuntimeFeesConfig::free(); + let fees = Arc::new(RuntimeFeesConfig::free()); let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); - - let promise_results = vec![]; + let promise_results = [].into(); let result = runtime - .run("out_of_memory", &mut fake_external, &context, &fees, &promise_results, None) + .run("out_of_memory", &mut fake_external, &context, fees, promise_results, None) .expect("execution failed"); assert_eq!( result.aborted, @@ -252,15 +259,23 @@ fn attach_unspent_gas_but_use_all_gas() { let mut config = test_vm_config(); config.limit_config.max_gas_burnt = context.prepaid_gas / 3; + let config = Arc::new(config); with_vm_variants(&config, |vm_kind: VMKind| { let code = function_call_weight_contract(); let mut external = MockedExternal::with_code(code); - let fees = RuntimeFeesConfig::test(); + let fees = Arc::new(RuntimeFeesConfig::test()); let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); let outcome = runtime - .run("attach_unspent_gas_but_use_all_gas", &mut external, &context, &fees, &[], None) + .run( + "attach_unspent_gas_but_use_all_gas", + &mut external, + &context, + fees, + [].into(), + None, + ) .unwrap_or_else(|err| panic!("Failed execution: {:?}", err)); let err = outcome.aborted.as_ref().unwrap(); diff --git a/runtime/near-vm-runner/src/tests/test_builder.rs b/runtime/near-vm-runner/src/tests/test_builder.rs index aeef31b045b..2e099f2358e 100644 --- a/runtime/near-vm-runner/src/tests/test_builder.rs +++ b/runtime/near-vm-runner/src/tests/test_builder.rs @@ -214,17 +214,17 @@ impl TestBuilder { let mut fake_external = MockedExternal::with_code(self.code.clone_for_tests()); let config = runtime_config.wasm_config.clone(); - let fees = RuntimeFeesConfig::test(); + let fees = Arc::new(RuntimeFeesConfig::test()); let context = self.context.clone(); - let promise_results = vec![]; + let promise_results = [].into(); let Some(runtime) = vm_kind.runtime(config) else { panic!("runtime for {:?} has not been compiled", vm_kind); }; println!("Running {:?} for protocol version {}", vm_kind, protocol_version); let outcome = runtime - .run(&self.method, &mut fake_external, &context, &fees, &promise_results, None) + .run(&self.method, &mut fake_external, &context, fees, promise_results, None) .expect("execution failed"); let mut got = String::new(); diff --git a/runtime/near-vm-runner/src/tests/ts_contract.rs b/runtime/near-vm-runner/src/tests/ts_contract.rs index 2ddbb5cb3d6..6a317c88c20 100644 --- a/runtime/near-vm-runner/src/tests/ts_contract.rs +++ b/runtime/near-vm-runner/src/tests/ts_contract.rs @@ -8,21 +8,28 @@ use crate::tests::{create_context, with_vm_variants}; use crate::ContractCode; use near_parameters::vm::VMKind; use near_parameters::RuntimeFeesConfig; +use std::sync::Arc; #[test] pub fn test_ts_contract() { - let config = test_vm_config(); + let config = Arc::new(test_vm_config()); with_vm_variants(&config, |vm_kind: VMKind| { let code = ContractCode::new(near_test_contracts::ts_contract().to_vec(), None); let mut fake_external = MockedExternal::with_code(code); let context = create_context(Vec::new()); - let fees = RuntimeFeesConfig::test(); + let fees = Arc::new(RuntimeFeesConfig::test()); // Call method that panics. - let promise_results = vec![]; + let promise_results = [].into(); let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled"); - let result = - runtime.run("try_panic", &mut fake_external, &context, &fees, &promise_results, None); + let result = runtime.run( + "try_panic", + &mut fake_external, + &context, + Arc::clone(&fees), + Arc::clone(&promise_results), + None, + ); let outcome = result.expect("execution failed"); assert_eq!( outcome.aborted, @@ -34,7 +41,14 @@ pub fn test_ts_contract() { // Call method that writes something into storage. let context = create_context(b"foo bar".to_vec()); runtime - .run("try_storage_write", &mut fake_external, &context, &fees, &promise_results, None) + .run( + "try_storage_write", + &mut fake_external, + &context, + Arc::clone(&fees), + Arc::clone(&promise_results), + None, + ) .expect("bad failure"); // Verify by looking directly into the storage of the host. { @@ -48,7 +62,14 @@ pub fn test_ts_contract() { // Call method that reads the value from storage using registers. let context = create_context(b"foo".to_vec()); let outcome = runtime - .run("try_storage_read", &mut fake_external, &context, &fees, &promise_results, None) + .run( + "try_storage_read", + &mut fake_external, + &context, + Arc::clone(&fees), + Arc::clone(&promise_results), + None, + ) .expect("execution failed"); if let ReturnData::Value(value) = outcome.return_data { diff --git a/runtime/near-vm-runner/src/wasmer2_runner.rs b/runtime/near-vm-runner/src/wasmer2_runner.rs index dcf3e7e173e..b42ceb10a39 100644 --- a/runtime/near-vm-runner/src/wasmer2_runner.rs +++ b/runtime/near-vm-runner/src/wasmer2_runner.rs @@ -228,12 +228,12 @@ pub(crate) fn wasmer2_vm_hash() -> u64 { pub(crate) type VMArtifact = Arc; pub(crate) struct Wasmer2VM { - pub(crate) config: Config, + pub(crate) config: Arc, pub(crate) engine: UniversalEngine, } impl Wasmer2VM { - pub(crate) fn new_for_target(config: Config, target: wasmer_compiler::Target) -> Self { + pub(crate) fn new_for_target(config: Arc, target: wasmer_compiler::Target) -> Self { // We only support singlepass compiler at the moment. assert_eq!(WASMER2_CONFIG.compiler, WasmerCompiler::Singlepass); let compiler = Singlepass::new(); @@ -247,7 +247,7 @@ impl Wasmer2VM { } } - pub(crate) fn new(config: Config) -> Self { + pub(crate) fn new(config: Arc) -> Self { use wasmer_compiler::{CpuFeature, Target, Triple}; let target_features = if cfg!(feature = "no_cpu_compatibility_checks") { let mut fs = CpuFeature::set(); @@ -567,8 +567,8 @@ impl crate::runner::VM for Wasmer2VM { method_name: &str, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> Result { let Some(code) = ext.get_contract() else { @@ -583,8 +583,14 @@ impl crate::runner::VM for Wasmer2VM { // FIXME: this mostly duplicates the `run_module` method. // Note that we don't clone the actual backing memory, just increase the RC. let vmmemory = memory.vm(); - let mut logic = - VMLogic::new(ext, context, &self.config, fees_config, promise_results, memory); + let mut logic = VMLogic::new( + ext, + context, + Arc::clone(&self.config), + fees_config, + promise_results, + memory, + ); let result = logic.before_loading_executable(method_name, code.code().len() as u64); if let Err(e) = result { diff --git a/runtime/near-vm-runner/src/wasmer_runner.rs b/runtime/near-vm-runner/src/wasmer_runner.rs index b9a983f6946..959aab3c8e6 100644 --- a/runtime/near-vm-runner/src/wasmer_runner.rs +++ b/runtime/near-vm-runner/src/wasmer_runner.rs @@ -13,6 +13,7 @@ use near_parameters::vm::{Config, VMKind}; use near_parameters::RuntimeFeesConfig; use std::borrow::Cow; use std::ffi::c_void; +use std::sync::Arc; use wasmer_runtime::units::Pages; use wasmer_runtime::wasm::MemoryDescriptor; use wasmer_runtime::Memory; @@ -295,11 +296,11 @@ pub(crate) fn wasmer0_vm_hash() -> u64 { } pub(crate) struct Wasmer0VM { - config: Config, + config: Arc, } impl Wasmer0VM { - pub(crate) fn new(config: Config) -> Self { + pub(crate) fn new(config: Arc) -> Self { Self { config } } @@ -419,8 +420,8 @@ impl crate::runner::VM for Wasmer0VM { method_name: &str, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: std::sync::Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> Result { let Some(code) = ext.get_contract() else { @@ -445,8 +446,14 @@ impl crate::runner::VM for Wasmer0VM { // Note that we don't clone the actual backing memory, just increase the RC. let memory_copy = memory.clone(); - let mut logic = - VMLogic::new(ext, context, &self.config, fees_config, promise_results, memory); + let mut logic = VMLogic::new( + ext, + context, + Arc::clone(&self.config), + fees_config, + promise_results, + memory, + ); let result = logic.before_loading_executable(method_name, code.code().len() as u64); if let Err(e) = result { diff --git a/runtime/near-vm-runner/src/wasmtime_runner.rs b/runtime/near-vm-runner/src/wasmtime_runner.rs index d9ebcbdb714..0bd770daceb 100644 --- a/runtime/near-vm-runner/src/wasmtime_runner.rs +++ b/runtime/near-vm-runner/src/wasmtime_runner.rs @@ -16,6 +16,7 @@ use near_parameters::RuntimeFeesConfig; use std::borrow::Cow; use std::cell::{RefCell, UnsafeCell}; use std::ffi::c_void; +use std::sync::Arc; use wasmtime::ExternType::Func; use wasmtime::{Engine, Linker, Memory, MemoryType, Module, Store}; @@ -143,12 +144,12 @@ pub(crate) fn wasmtime_vm_hash() -> u64 { } pub(crate) struct WasmtimeVM { - config: Config, + config: Arc, engine: wasmtime::Engine, } impl WasmtimeVM { - pub(crate) fn new(config: Config) -> Self { + pub(crate) fn new(config: Arc) -> Self { Self { engine: get_engine(&default_wasmtime_config(&config)), config } } @@ -188,8 +189,8 @@ impl WasmtimeVM { cache: &dyn ContractRuntimeCache, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, method_name: &str, closure: impl FnOnce(VMLogic, Memory, Store<()>, Module) -> Result, ) -> VMResult { @@ -257,8 +258,14 @@ impl WasmtimeVM { ) .unwrap(); let memory_copy = memory.0; - let mut logic = - VMLogic::new(ext, context, &self.config, fees_config, promise_results, memory); + let mut logic = VMLogic::new( + ext, + context, + Arc::clone(&self.config), + fees_config, + promise_results, + memory, + ); let result = logic.before_loading_executable(method_name, wasm_bytes); if let Err(e) = result { return Ok(VMOutcome::abort(logic, e)); @@ -282,8 +289,8 @@ impl crate::runner::VM for WasmtimeVM { method_name: &str, ext: &mut dyn External, context: &VMContext, - fees_config: &RuntimeFeesConfig, - promise_results: &[PromiseResult], + fees_config: Arc, + promise_results: Arc<[PromiseResult]>, cache: Option<&dyn ContractRuntimeCache>, ) -> Result { let cache = cache.unwrap_or(&NoContractRuntimeCache); diff --git a/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs b/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs index 4b4d8c521b5..9a70cd38d7e 100644 --- a/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs +++ b/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs @@ -1,14 +1,13 @@ +use crate::cost::Cost; +use crate::cost_table::CostTable; +use anyhow::Context; use near_parameters::vm::Config as VMConfig; use near_parameters::{ AccountCreationConfig, ActionCosts, ExtCosts, ExtCostsConfig, Fee, ParameterCost, RuntimeConfig, RuntimeConfigStore, RuntimeFeesConfig, }; use near_primitives::version::PROTOCOL_VERSION; - -use anyhow::Context; - -use crate::cost::Cost; -use crate::cost_table::CostTable; +use std::sync::Arc; /// Turn a [`CostTable`] into a [`RuntimeConfig`]. /// @@ -29,14 +28,14 @@ pub fn costs_to_runtime_config(cost_table: &CostTable) -> anyhow::Result anyhow::Result fee(Cost::DataReceiptCreationBase)?, ActionCosts::new_data_receipt_byte => fee(Cost::DataReceiptCreationPerByte)?, }, - ..actual_fees_config.clone() + ..RuntimeFeesConfig::clone(&actual_fees_config) }; Ok(res) } diff --git a/runtime/runtime-params-estimator/src/estimator_context.rs b/runtime/runtime-params-estimator/src/estimator_context.rs index 3e34e77fec0..a11f87314da 100644 --- a/runtime/runtime-params-estimator/src/estimator_context.rs +++ b/runtime/runtime-params-estimator/src/estimator_context.rs @@ -123,11 +123,11 @@ impl<'c> EstimatorContext<'c> { fn make_apply_state(cache: FilesystemContractRuntimeCache) -> ApplyState { let mut runtime_config = RuntimeConfigStore::new(None).get_config(PROTOCOL_VERSION).as_ref().clone(); - runtime_config.wasm_config.enable_all_features(); - runtime_config.wasm_config.make_free(); - + let wasm_config = Arc::make_mut(&mut runtime_config.wasm_config); + wasm_config.enable_all_features(); + wasm_config.make_free(); // Override vm limits config to simplify block processing. - runtime_config.wasm_config.limit_config = LimitConfig { + wasm_config.limit_config = LimitConfig { max_total_log_length: u64::MAX, max_number_registers: u64::MAX, max_gas_burnt: u64::MAX, @@ -141,7 +141,7 @@ impl<'c> EstimatorContext<'c> { max_total_prepaid_gas: u64::MAX, - ..runtime_config.wasm_config.limit_config + ..wasm_config.limit_config }; runtime_config.account_creation_config.min_allowed_top_level_account_length = 0; diff --git a/runtime/runtime-params-estimator/src/function_call.rs b/runtime/runtime-params-estimator/src/function_call.rs index 90f962f3953..a5b684ae041 100644 --- a/runtime/runtime-params-estimator/src/function_call.rs +++ b/runtime/runtime-params-estimator/src/function_call.rs @@ -8,6 +8,7 @@ use near_vm_runner::internal::VMKindExt; use near_vm_runner::logic::mocks::mock_external::MockedExternal; use near_vm_runner::{ContractCode, ContractRuntimeCache, FilesystemContractRuntimeCache}; use std::fmt::Write; +use std::sync::Arc; /// Estimates linear cost curve for a function call execution cost per byte of /// total contract code. The contract size is increased by adding more methods @@ -72,12 +73,19 @@ fn compute_function_call_cost( let fees = runtime_config.fees.clone(); let mut fake_external = MockedExternal::with_code(contract.clone_for_tests()); let fake_context = create_context(vec![]); - let promise_results = vec![]; + let promise_results = Arc::from([]); // Warmup. for _ in 0..warmup_repeats { let result = runtime - .run("hello0", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello0", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal error"); assert!(result.aborted.is_none()); } @@ -85,7 +93,14 @@ fn compute_function_call_cost( let start = GasCost::measure(gas_metric); for _ in 0..repeats { let result = runtime - .run("hello0", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello0", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal_error"); assert!(result.aborted.is_none()); } diff --git a/runtime/runtime-params-estimator/src/gas_metering.rs b/runtime/runtime-params-estimator/src/gas_metering.rs index 997babb2ef3..62670052dee 100644 --- a/runtime/runtime-params-estimator/src/gas_metering.rs +++ b/runtime/runtime-params-estimator/src/gas_metering.rs @@ -7,6 +7,7 @@ use near_vm_runner::internal::VMKindExt; use near_vm_runner::logic::mocks::mock_external::MockedExternal; use near_vm_runner::{ContractCode, ContractRuntimeCache, FilesystemContractRuntimeCache}; use std::fmt::Write; +use std::sync::Arc; pub(crate) fn gas_metering_cost(config: &Config) -> (GasCost, GasCost) { let mut xs1 = vec![]; @@ -129,23 +130,30 @@ pub(crate) fn compute_gas_metering_cost(config: &Config, contract: &ContractCode let config_store = RuntimeConfigStore::new(None); let runtime_config = config_store.get_config(PROTOCOL_VERSION).as_ref(); let vm_config_gas = runtime_config.wasm_config.clone(); - let vm_config_free = { - let mut cfg = vm_config_gas.clone(); + let vm_config_free = Arc::new({ + let mut cfg = near_parameters::vm::Config::clone(&vm_config_gas); cfg.make_free(); cfg.enable_all_features(); cfg - }; + }); let runtime = vm_kind.runtime(vm_config_gas).expect("runtime has not been enabled"); let runtime_free_gas = vm_kind.runtime(vm_config_free).expect("runtime has not been enabled"); let fees = runtime_config.fees.clone(); let mut fake_external = MockedExternal::with_code(contract.clone_for_tests()); let fake_context = create_context(vec![]); - let promise_results = vec![]; + let promise_results = Arc::from([]); // Warmup with gas metering for _ in 0..warmup_repeats { let result = runtime - .run("hello", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal_error"); if let Some(err) = &result.aborted { eprintln!("error: {}", err); @@ -157,7 +165,14 @@ pub(crate) fn compute_gas_metering_cost(config: &Config, contract: &ContractCode let start = GasCost::measure(gas_metric); for _ in 0..repeats { let result = runtime - .run("hello", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal_error"); assert!(result.aborted.is_none()); } @@ -166,7 +181,14 @@ pub(crate) fn compute_gas_metering_cost(config: &Config, contract: &ContractCode // Warmup without gas metering for _ in 0..warmup_repeats { let result = runtime_free_gas - .run("hello", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal_error"); assert!(result.aborted.is_none()); } @@ -175,7 +197,14 @@ pub(crate) fn compute_gas_metering_cost(config: &Config, contract: &ContractCode let start = GasCost::measure(gas_metric); for _ in 0..repeats { let result = runtime_free_gas - .run("hello", &mut fake_external, &fake_context, &fees, &promise_results, cache) + .run( + "hello", + &mut fake_external, + &fake_context, + Arc::clone(&fees), + Arc::clone(&promise_results), + cache, + ) .expect("fatal_error"); assert!(result.aborted.is_none()); } diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index bcc8122cf1d..18642023c5d 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -114,6 +114,7 @@ use near_vm_runner::MockContractRuntimeCache; use serde_json::json; use std::convert::TryFrom; use std::iter; +use std::sync::Arc; use std::time::Instant; use utils::{ average_cost, fn_cost, fn_cost_count, fn_cost_in_contract, fn_cost_with_setup, @@ -887,8 +888,8 @@ fn wasm_instruction(ctx: &mut EstimatorContext) -> GasCost { let mut fake_external = MockedExternal::with_code(code.clone_for_tests()); let config_store = RuntimeConfigStore::new(None); let config = config_store.get_config(PROTOCOL_VERSION).wasm_config.clone(); - let fees = RuntimeFeesConfig::test(); - let promise_results = vec![]; + let fees = Arc::new(RuntimeFeesConfig::test()); + let promise_results = [].into(); let cache = MockContractRuntimeCache::default(); let mut run = || { @@ -900,8 +901,8 @@ fn wasm_instruction(ctx: &mut EstimatorContext) -> GasCost { "cpu_ram_soak_test", &mut fake_external, &context, - &fees, - &promise_results, + Arc::clone(&fees), + Arc::clone(&promise_results), Some(&cache), ) .expect("fatal_error"); diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index f51e1e0001e..ea39ee26d40 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -5,7 +5,6 @@ use crate::config::{ use crate::ext::{ExternalError, RuntimeExt}; use crate::receipt_manager::ReceiptManager; use crate::{metrics, ActionResult, ApplyState}; - use near_crypto::PublicKey; use near_parameters::{AccountCreationConfig, ActionCosts, RuntimeConfig, RuntimeFeesConfig}; use near_primitives::account::{AccessKey, AccessKeyPermission, Account}; @@ -43,6 +42,7 @@ use near_vm_runner::logic::{VMContext, VMOutcome}; use near_vm_runner::precompile_contract; use near_vm_runner::ContractCode; use near_wallet_contract::{wallet_contract, wallet_contract_magic_bytes}; +use std::sync::Arc; /// Runs given function call with given context / apply state. pub(crate) fn execute_function_call( @@ -50,7 +50,7 @@ pub(crate) fn execute_function_call( runtime_ext: &mut RuntimeExt, predecessor_id: &AccountId, action_receipt: &ActionReceipt, - promise_results: &[PromiseResult], + promise_results: Arc<[PromiseResult]>, function_call: &FunctionCallAction, action_hash: &CryptoHash, config: &RuntimeConfig, @@ -105,8 +105,8 @@ pub(crate) fn execute_function_call( &function_call.method_name, runtime_ext, &context, - &config.wasm_config, - &config.fees, + Arc::clone(&config.wasm_config), + Arc::clone(&config.fees), promise_results, apply_state.cache.as_deref(), ); @@ -173,7 +173,7 @@ pub(crate) fn action_function_call( account: &mut Account, receipt: &Receipt, action_receipt: &ActionReceipt, - promise_results: &[PromiseResult], + promise_results: Arc<[PromiseResult]>, result: &mut ActionResult, account_id: &AccountId, function_call: &FunctionCallAction, @@ -586,7 +586,7 @@ pub(crate) fn action_implicit_account_creation_transfer( // is a no-op if the contract was already compiled. precompile_contract( &wallet_contract(&chain_id), - &apply_state.config.wasm_config, + Arc::clone(&apply_state.config.wasm_config), apply_state.cache.as_deref(), ) .ok(); @@ -628,7 +628,12 @@ pub(crate) fn action_deploy_contract( // Precompile the contract and store result (compiled code or error) in the database. // Note, that contract compilation costs are already accounted in deploy cost using // special logic in estimator (see get_runtime_config() function). - precompile_contract(&code, &apply_state.config.wasm_config, apply_state.cache.as_deref()).ok(); + precompile_contract( + &code, + Arc::clone(&apply_state.config.wasm_config), + apply_state.cache.as_deref(), + ) + .ok(); Ok(()) } diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 2fd3c28cd52..53434e97c2e 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -369,7 +369,7 @@ impl Runtime { actor_id: &mut AccountId, receipt: &Receipt, action_receipt: &ActionReceipt, - promise_results: &[PromiseResult], + promise_results: Arc<[PromiseResult]>, action_hash: &CryptoHash, action_index: usize, actions: &[Action], @@ -582,7 +582,7 @@ impl Runtime { None => Ok(PromiseResult::Failed), } }) - .collect::, RuntimeError>>()?; + .collect::, RuntimeError>>()?; // state_update might already have some updates so we need to make sure we commit it before // executing the actual receipt @@ -618,7 +618,7 @@ impl Runtime { &mut actor_id, receipt, action_receipt, - &promise_results, + Arc::clone(&promise_results), &action_hash, action_index, &action_receipt.actions, @@ -2795,8 +2795,8 @@ mod tests { let receipt_exec_gas_fee = 1000; let mut free_config = RuntimeConfig::free(); - free_config.fees.action_fees[ActionCosts::new_action_receipt].execution = - receipt_exec_gas_fee; + let fees = Arc::make_mut(&mut free_config.fees); + fees.action_fees[ActionCosts::new_action_receipt].execution = receipt_exec_gas_fee; apply_state.config = Arc::new(free_config); // This allows us to execute 3 receipts per apply. apply_state.gas_limit = Some(receipt_exec_gas_fee * 3); @@ -3317,7 +3317,8 @@ mod tests { gas: Gas::from(1_000_000u64), compute: Compute::from(10_000_000_000_000u64), }; - free_config.wasm_config.ext_costs.costs[ExtCosts::sha256_base] = sha256_cost.clone(); + let wasm_config = Arc::make_mut(&mut free_config.wasm_config); + wasm_config.ext_costs.costs[ExtCosts::sha256_base] = sha256_cost.clone(); apply_state.config = Arc::new(free_config); // This allows us to execute 1 receipt with a function call per apply. apply_state.gas_limit = Some(sha256_cost.compute); diff --git a/runtime/runtime/src/state_viewer/mod.rs b/runtime/runtime/src/state_viewer/mod.rs index 4f41512bf71..b59d493e654 100644 --- a/runtime/runtime/src/state_viewer/mod.rs +++ b/runtime/runtime/src/state_viewer/mod.rs @@ -254,7 +254,7 @@ impl TrieViewer { &mut runtime_ext, originator_id, &action_receipt, - &[], + [].into(), &function_call, &empty_hash, config, diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 81dd2133856..8930b78a10a 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -954,7 +954,8 @@ mod tests { let (signer, mut state_update, gas_price) = setup_common(TESTING_INIT_BALANCE, 0, Some(AccessKey::full_access())); - config.wasm_config.limit_config.max_total_prepaid_gas = 100; + let wasm_config = Arc::make_mut(&mut config.wasm_config); + wasm_config.limit_config.max_total_prepaid_gas = 100; assert_err_both_validations( &config, @@ -1178,7 +1179,8 @@ mod tests { #[test] fn test_validate_transaction_invalid_low_balance() { let mut config = RuntimeConfig::free(); - config.fees.storage_usage_config.storage_amount_per_byte = 10_000_000; + let fees = Arc::make_mut(&mut config.fees); + fees.storage_usage_config.storage_amount_per_byte = 10_000_000; let initial_balance = 1_000_000_000; let transfer_amount = 950_000_000; let (signer, mut state_update, gas_price) = @@ -1209,7 +1211,8 @@ mod tests { #[test] fn test_validate_transaction_invalid_low_balance_many_keys() { let mut config = RuntimeConfig::free(); - config.fees.storage_usage_config.storage_amount_per_byte = 10_000_000; + let fees = Arc::make_mut(&mut config.fees); + fees.storage_usage_config.storage_amount_per_byte = 10_000_000; let initial_balance = 1_000_000_000; let transfer_amount = 950_000_000; let account_id = alice_account(); @@ -1498,7 +1501,8 @@ mod tests { let mut config = RuntimeConfig::test(); let max_transaction_size = transaction_size - 1; - config.wasm_config.limit_config.max_transaction_size = transaction_size - 1; + let wasm_config = Arc::make_mut(&mut config.wasm_config); + wasm_config.limit_config.max_transaction_size = transaction_size - 1; assert_eq!( verify_and_charge_transaction( @@ -1517,7 +1521,8 @@ mod tests { }, ); - config.wasm_config.limit_config.max_transaction_size = transaction_size + 1; + let wasm_config = Arc::make_mut(&mut config.wasm_config); + wasm_config.limit_config.max_transaction_size = transaction_size + 1; verify_and_charge_transaction( &config, &mut state_update, diff --git a/runtime/runtime/tests/runtime_group_tools/mod.rs b/runtime/runtime/tests/runtime_group_tools/mod.rs index 42de900fa4f..da4cab147fb 100644 --- a/runtime/runtime/tests/runtime_group_tools/mod.rs +++ b/runtime/runtime/tests/runtime_group_tools/mod.rs @@ -55,11 +55,13 @@ impl StandaloneRuntime { validators: Vec, ) -> Self { let mut runtime_config = random_config(); + let wasm_config = Arc::make_mut(&mut runtime_config.wasm_config); // Bumping costs to avoid inflation overflows. - runtime_config.wasm_config.limit_config.max_total_prepaid_gas = 10u64.pow(15); - runtime_config.fees.action_fees[ActionCosts::new_action_receipt].execution = + wasm_config.limit_config.max_total_prepaid_gas = 10u64.pow(15); + let fees = Arc::make_mut(&mut runtime_config.fees); + fees.action_fees[ActionCosts::new_action_receipt].execution = runtime_config.wasm_config.limit_config.max_total_prepaid_gas / 64; - runtime_config.fees.action_fees[ActionCosts::new_data_receipt_base].execution = + fees.action_fees[ActionCosts::new_data_receipt_base].execution = runtime_config.wasm_config.limit_config.max_total_prepaid_gas / 64; let runtime = Runtime::new(); diff --git a/runtime/runtime/tests/runtime_group_tools/random_config.rs b/runtime/runtime/tests/runtime_group_tools/random_config.rs index 80de3116371..1ae6f7bb986 100644 --- a/runtime/runtime/tests/runtime_group_tools/random_config.rs +++ b/runtime/runtime/tests/runtime_group_tools/random_config.rs @@ -10,7 +10,7 @@ pub fn random_config() -> RuntimeConfig { execution: rng.next_u64() % 1000, }; RuntimeConfig { - fees: RuntimeFeesConfig { + fees: std::sync::Arc::new(RuntimeFeesConfig { action_fees: enum_map::enum_map! { _ => random_fee(), }, @@ -24,7 +24,7 @@ pub fn random_config() -> RuntimeConfig { (101 + rng.next_u32() % 10).try_into().unwrap(), 100, ), - }, + }), ..RuntimeConfig::test() } } diff --git a/test-utils/runtime-tester/src/run_test.rs b/test-utils/runtime-tester/src/run_test.rs index 12ff6b5602e..63597a937e2 100644 --- a/test-utils/runtime-tester/src/run_test.rs +++ b/test-utils/runtime-tester/src/run_test.rs @@ -16,6 +16,7 @@ use near_vm_runner::{ContractRuntimeCache, FilesystemContractRuntimeCache}; use nearcore::NightshadeRuntime; use std::io; use std::path::Path; +use std::sync::Arc; use std::time::Duration; pub struct ScenarioResult { @@ -38,8 +39,8 @@ impl Scenario { let clients = vec![accounts[0].clone()]; let mut genesis = Genesis::test(accounts, 1); let mut runtime_config = near_parameters::RuntimeConfig::test(); - runtime_config.wasm_config.limit_config.max_total_prepaid_gas = - self.runtime_config.max_total_prepaid_gas; + let wasm_config = Arc::make_mut(&mut runtime_config.wasm_config); + wasm_config.limit_config.max_total_prepaid_gas = self.runtime_config.max_total_prepaid_gas; genesis.config.epoch_length = self.runtime_config.epoch_length; genesis.config.gas_limit = self.runtime_config.gas_limit; let runtime_config_store = RuntimeConfigStore::with_one_config(runtime_config);