diff --git a/polkadot/core-primitives/src/lib.rs b/polkadot/core-primitives/src/lib.rs index d72322cf3ff402e39ed6783a38b3b1d9b2e0b6cb..96d4c0039915c1701d41c4ead2dbd09aa8e197b8 100644 --- a/polkadot/core-primitives/src/lib.rs +++ b/polkadot/core-primitives/src/lib.rs @@ -20,11 +20,13 @@ //! //! These core Polkadot types are used by the relay chain and the Parachains. -use sp_runtime::{generic, MultiSignature, traits::{Verify, BlakeTwo256, IdentifyAccount}}; +use sp_runtime::{generic, MultiSignature, traits::{Verify, IdentifyAccount}}; use parity_scale_codec::{Encode, Decode}; #[cfg(feature = "std")] use parity_util_mem::MallocSizeOf; +pub use sp_runtime::traits::{BlakeTwo256, Hash as HashT}; + /// The block number type used by Polkadot. /// 32-bits will allow for 136 years of blocks assuming 1 block per second. pub type BlockNumber = u32; diff --git a/polkadot/parachain/src/wasm_executor/mod.rs b/polkadot/parachain/src/wasm_executor/mod.rs index 90c689f49050ea87a369d7c4c61aba3f1be6fef1..5192bf115de021b237385d346be025da8831397e 100644 --- a/polkadot/parachain/src/wasm_executor/mod.rs +++ b/polkadot/parachain/src/wasm_executor/mod.rs @@ -160,6 +160,25 @@ pub enum InternalError { WasmWorker(String), } +/// A cache of executors for different parachain Wasm instances. +/// +/// This should be reused across candidate validation instances. +pub struct ExecutorCache(sc_executor::WasmExecutor); + +impl Default for ExecutorCache { + fn default() -> Self { + ExecutorCache(sc_executor::WasmExecutor::new( + #[cfg(all(feature = "wasmtime", not(any(target_os = "android", target_os = "unknown"))))] + sc_executor::WasmExecutionMethod::Compiled, + #[cfg(any(not(feature = "wasmtime"), target_os = "android", target_os = "unknown"))] + sc_executor::WasmExecutionMethod::Interpreted, + // TODO: Make sure we don't use more than 1GB: https://github.com/paritytech/polkadot/issues/699 + Some(1024), + HostFunctions::host_functions(), + 8 + )) + } +} /// Validate a candidate under the given validation code. /// @@ -172,7 +191,12 @@ pub fn validate_candidate( ) -> Result<ValidationResult, ValidationError> { match isolation_strategy { IsolationStrategy::InProcess => { - validate_candidate_internal(validation_code, ¶ms.encode(), spawner) + validate_candidate_internal( + &ExecutorCache::default(), + validation_code, + ¶ms.encode(), + spawner, + ) }, #[cfg(not(any(target_os = "android", target_os = "unknown")))] IsolationStrategy::ExternalProcessSelfHost(pool) => { @@ -193,20 +217,12 @@ type HostFunctions = sp_io::SubstrateHostFunctions; /// /// This will fail if the validation code is not a proper parachain validation module. pub fn validate_candidate_internal( + executor: &ExecutorCache, validation_code: &[u8], encoded_call_data: &[u8], spawner: impl SpawnNamed + 'static, ) -> Result<ValidationResult, ValidationError> { - let executor = sc_executor::WasmExecutor::new( - #[cfg(all(feature = "wasmtime", not(any(target_os = "android", target_os = "unknown"))))] - sc_executor::WasmExecutionMethod::Compiled, - #[cfg(any(not(feature = "wasmtime"), target_os = "android", target_os = "unknown"))] - sc_executor::WasmExecutionMethod::Interpreted, - // TODO: Make sure we don't use more than 1GB: https://github.com/paritytech/polkadot/issues/699 - Some(1024), - HostFunctions::host_functions(), - 8 - ); + let executor = &executor.0; let mut extensions = Extensions::new(); extensions.register(sp_core::traits::TaskExecutorExt::new(spawner)); @@ -214,9 +230,16 @@ pub fn validate_candidate_internal( let mut ext = ValidationExternalities(extensions); + // Expensive, but not more-so than recompiling the wasm module. + // And we need this hash to access the `sc_executor` cache. + let code_hash = { + use polkadot_core_primitives::{BlakeTwo256, HashT}; + BlakeTwo256::hash(validation_code) + }; + let res = executor.call_in_wasm( validation_code, - None, + Some(code_hash.as_bytes().to_vec()), "validate_block", encoded_call_data, &mut ext, diff --git a/polkadot/parachain/src/wasm_executor/validation_host.rs b/polkadot/parachain/src/wasm_executor/validation_host.rs index 79de6851994744cf757d0a20f22593ae048d4553..2db89b4bbaa131a9d057a51e78bab87d12907a90 100644 --- a/polkadot/parachain/src/wasm_executor/validation_host.rs +++ b/polkadot/parachain/src/wasm_executor/validation_host.rs @@ -151,6 +151,8 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> { memory.set(Event::WorkerReady as usize, EventState::Signaled) .map_err(|e| format!("{} Error setting shared event: {:?}", process::id(), e))?; + let executor = super::ExecutorCache::default(); + loop { if watch_exit.load(atomic::Ordering::Relaxed) { break; @@ -184,7 +186,7 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> { let (call_data, _) = rest.split_at_mut(MAX_RUNTIME_MEM); let (call_data, _) = call_data.split_at_mut(header.params_size as usize); - let result = validate_candidate_internal(code, call_data, task_executor.clone()); + let result = validate_candidate_internal(&executor, code, call_data, task_executor.clone()); debug!(target: LOG_TARGET, "{} Candidate validated: {:?}", process::id(), result); match result {