diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 09416233ea9b..b6f7b07f55d3 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -363,13 +363,11 @@ where Ok(x) => x, }; - let validation_code_hash = match params.code_hash_provider.code_hash_at(parent_hash) - { - None => { - tracing::error!(target: crate::LOG_TARGET, ?parent_hash, "Could not fetch validation code hash"); - break - }, - Some(v) => v, + let Some(validation_code_hash) = + params.code_hash_provider.code_hash_at(parent_hash) + else { + tracing::error!(target: crate::LOG_TARGET, ?parent_hash, "Could not fetch validation code hash"); + break }; super::check_validation_code_or_log( diff --git a/cumulus/client/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs index 6e0067d0cedb..0abc034c1ed6 100644 --- a/cumulus/client/consensus/aura/src/collators/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/mod.rs @@ -64,7 +64,7 @@ async fn check_validation_code_or_log( ?relay_parent, ?local_validation_code_hash, relay_validation_code_hash = ?state, - "Parachain code doesn't match validation code stored in the relay chain state", + "Parachain code doesn't match validation code stored in the relay chain state.", ); }, None => { diff --git a/prdoc/pr_4618.prdoc b/prdoc/pr_4618.prdoc new file mode 100644 index 000000000000..3dd0fce81eee --- /dev/null +++ b/prdoc/pr_4618.prdoc @@ -0,0 +1,20 @@ +title: Unify logic for fetching the `:code` of a block + +doc: + - audience: Node Operator + description: | + Fixes an issue on parachains when running with a custom `substitute` of the on chain wasm code + and having replaced the wasm code on the relay chain. The relay chain was rejecting blocks + build this way, because the collator was reporting the actual on chain wasm code hash + to the relay chain. However, the relay chain was expecting the code hash of the wasm code substitute + that was also registered on the relay chain. + - audience: Node Dev + description: | + `Client::code_at` will now use the same `substitute` to determine the code for a given block as it is + done when executing any runtime call. + +crates: + - name: cumulus-client-consensus-aura + bump: minor + - name: sc-service + bump: minor diff --git a/substrate/client/service/src/client/call_executor.rs b/substrate/client/service/src/client/call_executor.rs index 9da4d2192576..1341aa0e7205 100644 --- a/substrate/client/service/src/client/call_executor.rs +++ b/substrate/client/service/src/client/call_executor.rs @@ -16,19 +16,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; +use super::{code_provider::CodeProvider, ClientConfig}; use sc_client_api::{ backend, call_executor::CallExecutor, execution_extensions::ExecutionExtensions, HeaderBackend, }; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_api::ProofRecorder; -use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode}; +use sp_core::traits::{CallContext, CodeExecutor}; use sp_externalities::Extensions; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, HashingFor}, }; -use sp_state_machine::{backend::AsTrieBackend, Ext, OverlayedChanges, StateMachine, StorageProof}; +use sp_state_machine::{backend::AsTrieBackend, OverlayedChanges, StateMachine, StorageProof}; use std::{cell::RefCell, sync::Arc}; /// Call executor that executes methods locally, querying all required @@ -36,8 +36,7 @@ use std::{cell::RefCell, sync::Arc}; pub struct LocalCallExecutor { backend: Arc, executor: E, - wasm_override: Arc>, - wasm_substitutes: WasmSubstitutes, + code_provider: CodeProvider, execution_extensions: Arc>, } @@ -53,81 +52,15 @@ where client_config: ClientConfig, execution_extensions: ExecutionExtensions, ) -> sp_blockchain::Result { - let wasm_override = client_config - .wasm_runtime_overrides - .as_ref() - .map(|p| WasmOverride::new(p.clone(), &executor)) - .transpose()?; - - let wasm_substitutes = WasmSubstitutes::new( - client_config.wasm_runtime_substitutes, - executor.clone(), - backend.clone(), - )?; + let code_provider = CodeProvider::new(&client_config, executor.clone(), backend.clone())?; Ok(LocalCallExecutor { backend, executor, - wasm_override: Arc::new(wasm_override), - wasm_substitutes, + code_provider, execution_extensions: Arc::new(execution_extensions), }) } - - /// Check if local runtime code overrides are enabled and one is available - /// for the given `BlockId`. If yes, return it; otherwise return the same - /// `RuntimeCode` instance that was passed. - fn check_override<'a>( - &'a self, - onchain_code: RuntimeCode<'a>, - state: &B::State, - hash: Block::Hash, - ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> - where - Block: BlockT, - B: backend::Backend, - { - let on_chain_version = self.on_chain_runtime_version(&onchain_code, state)?; - let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| { - o.get( - &on_chain_version.spec_version, - onchain_code.heap_pages, - &on_chain_version.spec_name, - ) - }) { - log::debug!(target: "wasm_overrides", "using WASM override for block {}", hash); - d - } else if let Some(s) = - self.wasm_substitutes - .get(on_chain_version.spec_version, onchain_code.heap_pages, hash) - { - log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", hash); - s - } else { - log::debug!( - target: "wasm_overrides", - "Neither WASM override nor substitute available for block {hash}, using onchain code", - ); - (onchain_code, on_chain_version) - }; - - Ok(code_and_version) - } - - /// Returns the on chain runtime version. - fn on_chain_runtime_version( - &self, - code: &RuntimeCode, - state: &B::State, - ) -> sp_blockchain::Result { - let mut overlay = OverlayedChanges::default(); - - let mut ext = Ext::new(&mut overlay, state, None); - - self.executor - .runtime_version(&mut ext, code) - .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string())) - } } impl Clone for LocalCallExecutor @@ -138,8 +71,7 @@ where LocalCallExecutor { backend: self.backend.clone(), executor: self.executor.clone(), - wasm_override: self.wasm_override.clone(), - wasm_substitutes: self.wasm_substitutes.clone(), + code_provider: self.code_provider.clone(), execution_extensions: self.execution_extensions.clone(), } } @@ -175,7 +107,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; + let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0; let mut extensions = self.execution_extensions.extensions(at_hash, at_number); @@ -215,7 +147,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; + let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0; let mut extensions = extensions.borrow_mut(); match recorder { @@ -263,7 +195,9 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - self.check_override(runtime_code, &state, at_hash).map(|(_, v)| v) + self.code_provider + .maybe_override_code(runtime_code, &state, at_hash) + .map(|(_, v)| v) } fn prove_execution( @@ -281,7 +215,7 @@ where let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; + let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0; sp_state_machine::prove_execution_on_trie_backend( trie_backend, @@ -331,133 +265,3 @@ where self.executor.native_version() } } - -#[cfg(test)] -mod tests { - use super::*; - use backend::Backend; - use sc_client_api::in_mem; - use sc_executor::WasmExecutor; - use sp_core::{ - testing::TaskExecutor, - traits::{FetchRuntimeCode, WrappedRuntimeCode}, - }; - use std::collections::HashMap; - use substrate_test_runtime_client::{runtime, GenesisInit}; - - #[test] - fn should_get_override_if_exists() { - let executor = WasmExecutor::default(); - - let overrides = crate::client::wasm_override::dummy_overrides(); - let onchain_code = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); - let onchain_code = RuntimeCode { - code_fetcher: &onchain_code, - heap_pages: Some(128), - hash: vec![0, 0, 0, 0], - }; - - let backend = Arc::new(in_mem::Backend::::new()); - - // wasm_runtime_overrides is `None` here because we construct the - // LocalCallExecutor directly later on - let client_config = ClientConfig::default(); - - let genesis_block_builder = crate::GenesisBlockBuilder::new( - &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), - !client_config.no_genesis, - backend.clone(), - executor.clone(), - ) - .expect("Creates genesis block builder"); - - // client is used for the convenience of creating and inserting the genesis block. - let _client = - crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( - backend.clone(), - executor.clone(), - genesis_block_builder, - Box::new(TaskExecutor::new()), - None, - None, - client_config, - ) - .expect("Creates a client"); - - let call_executor = LocalCallExecutor { - backend: backend.clone(), - executor: executor.clone(), - wasm_override: Arc::new(Some(overrides)), - wasm_substitutes: WasmSubstitutes::new( - Default::default(), - executor.clone(), - backend.clone(), - ) - .unwrap(), - execution_extensions: Arc::new(ExecutionExtensions::new( - None, - Arc::new(executor.clone()), - )), - }; - - let check = call_executor - .check_override( - onchain_code, - &backend.state_at(backend.blockchain().info().genesis_hash).unwrap(), - backend.blockchain().info().genesis_hash, - ) - .expect("RuntimeCode override") - .0; - - assert_eq!(Some(vec![2, 2, 2, 2, 2, 2, 2, 2]), check.fetch_runtime_code().map(Into::into)); - } - - #[test] - fn returns_runtime_version_from_substitute() { - const SUBSTITUTE_SPEC_NAME: &str = "substitute-spec-name-cool"; - - let executor = WasmExecutor::default(); - - let backend = Arc::new(in_mem::Backend::::new()); - - // Let's only override the `spec_name` for our testing purposes. - let substitute = sp_version::embed::embed_runtime_version( - &substrate_test_runtime::WASM_BINARY_BLOATY.unwrap(), - sp_version::RuntimeVersion { - spec_name: SUBSTITUTE_SPEC_NAME.into(), - ..substrate_test_runtime::VERSION - }, - ) - .unwrap(); - - let client_config = crate::client::ClientConfig { - wasm_runtime_substitutes: vec![(0, substitute)].into_iter().collect::>(), - ..Default::default() - }; - - let genesis_block_builder = crate::GenesisBlockBuilder::new( - &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), - !client_config.no_genesis, - backend.clone(), - executor.clone(), - ) - .expect("Creates genesis block builder"); - - // client is used for the convenience of creating and inserting the genesis block. - let client = - crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( - backend.clone(), - executor.clone(), - genesis_block_builder, - Box::new(TaskExecutor::new()), - None, - None, - client_config, - ) - .expect("Creates a client"); - - let version = client.runtime_version_at(client.chain_info().genesis_hash).unwrap(); - - assert_eq!(SUBSTITUTE_SPEC_NAME, &*version.spec_name); - } -} diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 3c25c233775b..2fbcc3ba4f75 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -18,7 +18,10 @@ //! Substrate Client -use super::block_rules::{BlockRules, LookupResult as BlockLookupResult}; +use super::{ + block_rules::{BlockRules, LookupResult as BlockLookupResult}, + CodeProvider, +}; use crate::client::notification_pinning::NotificationPinningWorker; use log::{debug, info, trace, warn}; use parking_lot::{Mutex, RwLock}; @@ -57,10 +60,7 @@ use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_core::{ - storage::{ - well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, - StorageKey, - }, + storage::{ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, StorageKey}, traits::{CallContext, SpawnNamed}, }; use sp_runtime::{ @@ -115,6 +115,7 @@ where config: ClientConfig, telemetry: Option, unpin_worker_sender: TracingUnboundedSender>, + code_provider: CodeProvider, _phantom: PhantomData, } @@ -410,6 +411,7 @@ where Block, BlockImportOperation = >::BlockImportOperation, >, + E: Clone, B: 'static, { let info = backend.blockchain().info(); @@ -438,6 +440,7 @@ where ); let unpin_worker = NotificationPinningWorker::new(rx, backend.clone()); spawn_handle.spawn("notification-pinning-worker", None, Box::pin(unpin_worker.run())); + let code_provider = CodeProvider::new(&config, executor.clone(), backend.clone())?; Ok(Client { backend, @@ -453,6 +456,7 @@ where config, telemetry, unpin_worker_sender, + code_provider, _phantom: Default::default(), }) } @@ -475,13 +479,10 @@ where } /// Get the code at a given block. + /// + /// This takes any potential substitutes into account, but ignores overrides. pub fn code_at(&self, hash: Block::Hash) -> sp_blockchain::Result> { - Ok(StorageProvider::storage(self, hash, &StorageKey(well_known_keys::CODE.to_vec()))? - .expect( - "None is returned if there's no value stored for the given key;\ - ':code' key is always defined; qed", - ) - .0) + self.code_provider.code_at_ignoring_overrides(hash) } /// Get the RuntimeVersion at a given block. diff --git a/substrate/client/service/src/client/code_provider.rs b/substrate/client/service/src/client/code_provider.rs new file mode 100644 index 000000000000..8ba7766ea65b --- /dev/null +++ b/substrate/client/service/src/client/code_provider.rs @@ -0,0 +1,348 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; +use sc_client_api::backend; +use sc_executor::{RuntimeVersion, RuntimeVersionOf}; +use sp_core::traits::{FetchRuntimeCode, RuntimeCode}; +use sp_runtime::traits::Block as BlockT; +use sp_state_machine::{Ext, OverlayedChanges}; +use std::sync::Arc; + +/// Provider for fetching `:code` of a block. +/// +/// As a node can run with code overrides or substitutes, this will ensure that these are taken into +/// account before returning the actual `code` for a block. +pub struct CodeProvider { + backend: Arc, + executor: Arc, + wasm_override: Arc>, + wasm_substitutes: WasmSubstitutes, +} + +impl Clone for CodeProvider { + fn clone(&self) -> Self { + Self { + backend: self.backend.clone(), + executor: self.executor.clone(), + wasm_override: self.wasm_override.clone(), + wasm_substitutes: self.wasm_substitutes.clone(), + } + } +} + +impl CodeProvider +where + Block: BlockT, + Backend: backend::Backend, + Executor: RuntimeVersionOf, +{ + /// Create a new instance. + pub fn new( + client_config: &ClientConfig, + executor: Executor, + backend: Arc, + ) -> sp_blockchain::Result { + let wasm_override = client_config + .wasm_runtime_overrides + .as_ref() + .map(|p| WasmOverride::new(p.clone(), &executor)) + .transpose()?; + + let executor = Arc::new(executor); + + let wasm_substitutes = WasmSubstitutes::new( + client_config.wasm_runtime_substitutes.clone(), + executor.clone(), + backend.clone(), + )?; + + Ok(Self { backend, executor, wasm_override: Arc::new(wasm_override), wasm_substitutes }) + } + + /// Returns the `:code` for the given `block`. + /// + /// This takes into account potential overrides/substitutes. + pub fn code_at_ignoring_overrides(&self, block: Block::Hash) -> sp_blockchain::Result> { + let state = self.backend.state_at(block)?; + + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); + let runtime_code = + state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; + + self.maybe_override_code_internal(runtime_code, &state, block, true) + .and_then(|r| { + r.0.fetch_runtime_code().map(Into::into).ok_or_else(|| { + sp_blockchain::Error::Backend("Could not find `:code` in backend.".into()) + }) + }) + } + + /// Maybe override the given `onchain_code`. + /// + /// This takes into account potential overrides/substitutes. + pub fn maybe_override_code<'a>( + &'a self, + onchain_code: RuntimeCode<'a>, + state: &Backend::State, + hash: Block::Hash, + ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> { + self.maybe_override_code_internal(onchain_code, state, hash, false) + } + + /// Maybe override the given `onchain_code`. + /// + /// This takes into account potential overrides(depending on `ignore_overrides`)/substitutes. + fn maybe_override_code_internal<'a>( + &'a self, + onchain_code: RuntimeCode<'a>, + state: &Backend::State, + hash: Block::Hash, + ignore_overrides: bool, + ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> { + let on_chain_version = self.on_chain_runtime_version(&onchain_code, state)?; + let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| { + if ignore_overrides { + return None + } + + o.get( + &on_chain_version.spec_version, + onchain_code.heap_pages, + &on_chain_version.spec_name, + ) + }) { + tracing::debug!(target: "code-provider::overrides", block = ?hash, "using WASM override"); + d + } else if let Some(s) = + self.wasm_substitutes + .get(on_chain_version.spec_version, onchain_code.heap_pages, hash) + { + tracing::debug!(target: "code-provider::substitutes", block = ?hash, "Using WASM substitute"); + s + } else { + tracing::debug!( + target: "code-provider", + block = ?hash, + "Neither WASM override nor substitute available, using onchain code", + ); + (onchain_code, on_chain_version) + }; + + Ok(code_and_version) + } + + /// Returns the on chain runtime version. + fn on_chain_runtime_version( + &self, + code: &RuntimeCode, + state: &Backend::State, + ) -> sp_blockchain::Result { + let mut overlay = OverlayedChanges::default(); + + let mut ext = Ext::new(&mut overlay, state, None); + + self.executor + .runtime_version(&mut ext, code) + .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use backend::Backend; + use sc_client_api::{in_mem, HeaderBackend}; + use sc_executor::WasmExecutor; + use sp_core::{ + testing::TaskExecutor, + traits::{FetchRuntimeCode, WrappedRuntimeCode}, + }; + use std::collections::HashMap; + use substrate_test_runtime_client::{runtime, GenesisInit}; + + #[test] + fn no_override_no_substitutes_work() { + let executor = WasmExecutor::default(); + + let code_fetcher = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); + let onchain_code = RuntimeCode { + code_fetcher: &code_fetcher, + heap_pages: Some(128), + hash: vec![0, 0, 0, 0], + }; + + let backend = Arc::new(in_mem::Backend::::new()); + + // wasm_runtime_overrides is `None` here because we construct the + // LocalCallExecutor directly later on + let client_config = ClientConfig::default(); + + let genesis_block_builder = crate::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .expect("Creates genesis block builder"); + + // client is used for the convenience of creating and inserting the genesis block. + let _client = + crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( + backend.clone(), + executor.clone(), + genesis_block_builder, + Box::new(TaskExecutor::new()), + None, + None, + client_config.clone(), + ) + .expect("Creates a client"); + + let executor = Arc::new(executor); + + let code_provider = CodeProvider { + backend: backend.clone(), + executor: executor.clone(), + wasm_override: Arc::new(None), + wasm_substitutes: WasmSubstitutes::new(Default::default(), executor, backend.clone()) + .unwrap(), + }; + + let check = code_provider + .maybe_override_code( + onchain_code, + &backend.state_at(backend.blockchain().info().genesis_hash).unwrap(), + backend.blockchain().info().genesis_hash, + ) + .expect("RuntimeCode override") + .0; + + assert_eq!(code_fetcher.fetch_runtime_code(), check.fetch_runtime_code()); + } + + #[test] + fn should_get_override_if_exists() { + let executor = WasmExecutor::default(); + + let overrides = crate::client::wasm_override::dummy_overrides(); + let onchain_code = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); + let onchain_code = RuntimeCode { + code_fetcher: &onchain_code, + heap_pages: Some(128), + hash: vec![0, 0, 0, 0], + }; + + let backend = Arc::new(in_mem::Backend::::new()); + + // wasm_runtime_overrides is `None` here because we construct the + // LocalCallExecutor directly later on + let client_config = ClientConfig::default(); + + let genesis_block_builder = crate::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .expect("Creates genesis block builder"); + + // client is used for the convenience of creating and inserting the genesis block. + let _client = + crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( + backend.clone(), + executor.clone(), + genesis_block_builder, + Box::new(TaskExecutor::new()), + None, + None, + client_config.clone(), + ) + .expect("Creates a client"); + + let executor = Arc::new(executor); + + let code_provider = CodeProvider { + backend: backend.clone(), + executor: executor.clone(), + wasm_override: Arc::new(Some(overrides)), + wasm_substitutes: WasmSubstitutes::new(Default::default(), executor, backend.clone()) + .unwrap(), + }; + + let check = code_provider + .maybe_override_code( + onchain_code, + &backend.state_at(backend.blockchain().info().genesis_hash).unwrap(), + backend.blockchain().info().genesis_hash, + ) + .expect("RuntimeCode override") + .0; + + assert_eq!(Some(vec![2, 2, 2, 2, 2, 2, 2, 2]), check.fetch_runtime_code().map(Into::into)); + } + + #[test] + fn returns_runtime_version_from_substitute() { + const SUBSTITUTE_SPEC_NAME: &str = "substitute-spec-name-cool"; + + let executor = WasmExecutor::default(); + + let backend = Arc::new(in_mem::Backend::::new()); + + // Let's only override the `spec_name` for our testing purposes. + let substitute = sp_version::embed::embed_runtime_version( + &substrate_test_runtime::WASM_BINARY_BLOATY.unwrap(), + sp_version::RuntimeVersion { + spec_name: SUBSTITUTE_SPEC_NAME.into(), + ..substrate_test_runtime::VERSION + }, + ) + .unwrap(); + + let client_config = crate::client::ClientConfig { + wasm_runtime_substitutes: vec![(0, substitute)].into_iter().collect::>(), + ..Default::default() + }; + + let genesis_block_builder = crate::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .expect("Creates genesis block builder"); + + // client is used for the convenience of creating and inserting the genesis block. + let client = + crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( + backend.clone(), + executor.clone(), + genesis_block_builder, + Box::new(TaskExecutor::new()), + None, + None, + client_config, + ) + .expect("Creates a client"); + + let version = client.runtime_version_at(client.chain_info().genesis_hash).unwrap(); + + assert_eq!(SUBSTITUTE_SPEC_NAME, &*version.spec_name); + } +} diff --git a/substrate/client/service/src/client/mod.rs b/substrate/client/service/src/client/mod.rs index 0703cc2b47d1..ec77a92f162f 100644 --- a/substrate/client/service/src/client/mod.rs +++ b/substrate/client/service/src/client/mod.rs @@ -47,14 +47,14 @@ mod block_rules; mod call_executor; mod client; +mod code_provider; mod notification_pinning; mod wasm_override; mod wasm_substitutes; -pub use self::{ - call_executor::LocalCallExecutor, - client::{Client, ClientConfig}, -}; +pub use call_executor::LocalCallExecutor; +pub use client::{Client, ClientConfig}; +pub(crate) use code_provider::CodeProvider; #[cfg(feature = "test-helpers")] pub use self::client::{new_in_mem, new_with_backend}; diff --git a/substrate/client/service/src/client/wasm_substitutes.rs b/substrate/client/service/src/client/wasm_substitutes.rs index 70db0ef20f5a..07ca6c960628 100644 --- a/substrate/client/service/src/client/wasm_substitutes.rs +++ b/substrate/client/service/src/client/wasm_substitutes.rs @@ -94,7 +94,7 @@ impl From for sp_blockchain::Error { pub struct WasmSubstitutes { /// spec_version -> WasmSubstitute substitutes: Arc>>, - executor: Executor, + executor: Arc, backend: Arc, } @@ -110,14 +110,14 @@ impl Clone for WasmSubstitutes WasmSubstitutes where - Executor: RuntimeVersionOf + Clone + 'static, + Executor: RuntimeVersionOf, Backend: backend::Backend, Block: BlockT, { /// Create a new instance. pub fn new( substitutes: HashMap, Vec>, - executor: Executor, + executor: Arc, backend: Arc, ) -> Result { let substitutes = substitutes diff --git a/substrate/test-utils/client/src/client_ext.rs b/substrate/test-utils/client/src/client_ext.rs index 73581a4f0efa..9dc4739eb795 100644 --- a/substrate/test-utils/client/src/client_ext.rs +++ b/substrate/test-utils/client/src/client_ext.rs @@ -153,7 +153,7 @@ where Self: BlockImport, RA: Send, B: Send + Sync, - E: Send, + E: Send + Sync, { async fn import(&mut self, origin: BlockOrigin, block: Block) -> Result<(), ConsensusError> { let (header, extrinsics) = block.deconstruct();