diff --git a/Cargo.lock b/Cargo.lock index 17895bf28deb0..af55d477afe27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1926,7 +1926,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2720,7 +2720,7 @@ dependencies = [ "triehash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2839,7 +2839,7 @@ dependencies = [ "substrate-serializer 0.1.0", "twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)", - "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3022,7 +3022,7 @@ dependencies = [ "substrate-runtime-io 0.1.0", "substrate-runtime-std 0.1.0", "wabt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3780,7 +3780,7 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4196,7 +4196,7 @@ dependencies = [ "checksum wabt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "182ae543249ccf2705f324d233891c1176fca142e137b55ba43d9dbfe93f18a2" "checksum wabt-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca77c6b934a2b32618941b2f565aac43b8cb7141378c3b4fba4d8fcdcd57da3" "checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" -"checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3" +"checksum wasmi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "522fe3fdd44a56f25cd5ddcd8ccdb1cf2e982ceb28fcb00f41d8a018ae5245a8" "checksum websocket 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eb277e7f4c23dc49176f74ae200e77651764efb2c25f56ad2d22623b63826369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" diff --git a/demo/cli/src/lib.rs b/demo/cli/src/lib.rs index 08834541f52bf..03eb39c919195 100644 --- a/demo/cli/src/lib.rs +++ b/demo/cli/src/lib.rs @@ -114,7 +114,7 @@ pub fn run(args: I) -> error::Result<()> where init_logger(log_pattern); // Create client - let executor = NativeExecutor::with_heap_pages(8, 8); + let executor = NativeExecutor::with_heap_pages(8); let god_key = hex!["3d866ec8a9190c8343c2fc593d21d8a6d0c5c4763aaab2349de3a6111d64d124"]; let genesis_config = GenesisConfig { diff --git a/demo/executor/src/lib.rs b/demo/executor/src/lib.rs index 24ec4e5f573c9..5ebece1f609f5 100644 --- a/demo/executor/src/lib.rs +++ b/demo/executor/src/lib.rs @@ -95,7 +95,7 @@ mod tests { } fn executor() -> ::substrate_executor::NativeExecutor { - ::substrate_executor::NativeExecutor::with_heap_pages(8, 8) + ::substrate_executor::NativeExecutor::with_heap_pages(8) } #[test] @@ -312,14 +312,14 @@ mod tests { fn full_wasm_block_import_works() { let mut t = new_test_ext(); - WasmExecutor::new(8, 8).call(&mut t, COMPACT_CODE, "execute_block", &block1().0, true).0.unwrap(); + WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Staking::voting_balance(&alice()), 41); assert_eq!(Staking::voting_balance(&bob()), 69); }); - WasmExecutor::new(8, 8).call(&mut t, COMPACT_CODE, "execute_block", &block2().0, true).0.unwrap(); + WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Staking::voting_balance(&alice()), 30); @@ -331,7 +331,7 @@ mod tests { fn wasm_big_block_import_fails() { let mut t = new_test_ext(); - let r = WasmExecutor::new(8, 8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0, true).0; + let r = WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0); assert!(!r.is_ok()); } @@ -339,7 +339,7 @@ mod tests { fn native_big_block_import_succeeds() { let mut t = new_test_ext(); - let r = Executor::with_heap_pages(8, 8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0, true).0; + let r = Executor::with_heap_pages(8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0, true).0; assert!(r.is_ok()); } @@ -347,7 +347,7 @@ mod tests { fn native_big_block_import_fails_on_fallback() { let mut t = new_test_ext(); - let r = Executor::with_heap_pages(8, 8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0, false).0; + let r = Executor::with_heap_pages(8).call(&mut t, COMPACT_CODE, "execute_block", &block1big().0, false).0; assert!(!r.is_ok()); } @@ -364,9 +364,9 @@ mod tests { ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm"); - let r = WasmExecutor::new(8, 8).call(&mut t, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = WasmExecutor::new(8).call(&mut t, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64))); assert!(r.is_ok()); - let r = WasmExecutor::new(8, 8).call(&mut t, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); + let r = WasmExecutor::new(8).call(&mut t, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt())).unwrap(); let r = ApplyResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } @@ -384,9 +384,9 @@ mod tests { ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm"); - let r = WasmExecutor::new(8, 8).call(&mut t, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = WasmExecutor::new(8).call(&mut t, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64))); assert!(r.is_ok()); - let r = WasmExecutor::new(8, 8).call(&mut t, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); + let r = WasmExecutor::new(8).call(&mut t, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt())).unwrap(); let r = ApplyResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Ok(ApplyOutcome::Success)); diff --git a/polkadot/api/src/full.rs b/polkadot/api/src/full.rs index caf9a8907281b..7a5aeb31e785c 100644 --- a/polkadot/api/src/full.rs +++ b/polkadot/api/src/full.rs @@ -200,7 +200,7 @@ mod tests { timestamp: Some(Default::default()), }; - ::client::new_in_mem(LocalDispatch::with_heap_pages(8, 8), genesis_config).unwrap() + ::client::new_in_mem(LocalDispatch::with_heap_pages(8), genesis_config).unwrap() } #[test] diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 2b1eeca7e5611..2197911ed42d5 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -6,7 +6,7 @@ description = "Types and utilities for creating and working with parachains" [dependencies] substrate-codec = { path = "../../substrate/codec", default-features = false } -wasmi = { version = "0.3", optional = true } +wasmi = { version = "0.4", optional = true } error-chain = { version = "0.12", optional = true } [dev-dependencies] diff --git a/substrate/cli/src/cli.yml b/substrate/cli/src/cli.yml index 995f773400a71..9c156061add9b 100644 --- a/substrate/cli/src/cli.yml +++ b/substrate/cli/src/cli.yml @@ -95,10 +95,6 @@ args: long: execution value_name: STRATEGY help: The means of execution used when calling into the runtime. Can be either wasm, native or both. - - min-heap-pages: - long: min-heap-pages - value_name: COUNT - help: The number of 64KB pages to allocate for Wasm execution initially. - max-heap-pages: long: max-heap-pages value_name: COUNT @@ -170,10 +166,6 @@ subcommands: long: execution value_name: STRATEGY help: The means of execution used when calling into the runtime. Can be either wasm, native or both. - - min-heap-pages: - long: min-heap-pages - value_name: COUNT - help: The number of 64KB pages to allocate for Wasm execution initially. - max-heap-pages: long: max-heap-pages value_name: COUNT diff --git a/substrate/cli/src/lib.rs b/substrate/cli/src/lib.rs index 324121073eae6..9b3c1ca44d307 100644 --- a/substrate/cli/src/lib.rs +++ b/substrate/cli/src/lib.rs @@ -252,9 +252,6 @@ where service::Roles::FULL }; - if let Some(v) = matches.value_of("min-heap-pages") { - config.min_heap_pages = v.parse().map_err(|_| "Invalid --min-heap-pages argument")?; - } if let Some(v) = matches.value_of("max-heap-pages") { config.max_heap_pages = v.parse().map_err(|_| "Invalid --max-heap-pages argument")?; } @@ -352,9 +349,6 @@ fn import_blocks(matches: &clap::ArgMatches, spec: ChainSpec ::executor::NativeExecutor { - NativeExecutionDispatch::with_heap_pages(8, 8) + NativeExecutionDispatch::with_heap_pages(8) } fn construct_block(backend: &InMemory, number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec) -> (Vec, Hash) { @@ -169,10 +169,10 @@ mod tests { let _ = execute( &backend, &mut overlay, - &WasmExecutor::new(8, 8), + &executor(), "execute_block", &b1data, - ExecutionStrategy::NativeWhenPossible, + ExecutionStrategy::AlwaysWasm, ).unwrap(); } @@ -193,7 +193,7 @@ mod tests { let _ = execute( &backend, &mut overlay, - &Executor::with_heap_pages(8, 8), + &Executor::with_heap_pages(8), "execute_block", &b1data, ExecutionStrategy::NativeWhenPossible, diff --git a/substrate/client/src/light/call_executor.rs b/substrate/client/src/light/call_executor.rs index 40d8665510100..da196b54b7f60 100644 --- a/substrate/client/src/light/call_executor.rs +++ b/substrate/client/src/light/call_executor.rs @@ -155,7 +155,7 @@ mod tests { let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "authorities", &[]).unwrap().1; // check remote execution proof locally - let local_executor = test_client::LocalExecutor::with_heap_pages(8, 8); + let local_executor = test_client::LocalExecutor::with_heap_pages(8); do_check_execution_proof(remote_block_storage_root.into(), &local_executor, &RemoteCallRequest { block: test_client::runtime::Hash::default(), method: "authorities".into(), diff --git a/substrate/executor/Cargo.toml b/substrate/executor/Cargo.toml index 8d537dd3dc78e..f60c686b0ef24 100644 --- a/substrate/executor/Cargo.toml +++ b/substrate/executor/Cargo.toml @@ -14,7 +14,7 @@ substrate-runtime-version = { path = "../runtime/version" } ed25519 = { path = "../ed25519" } serde = "1.0" serde_derive = "1.0" -wasmi = "0.3" +wasmi = "0.4" byteorder = "1.1" rustc-hex = "1.0.0" triehash = "0.1.0" @@ -30,4 +30,4 @@ wabt = "0.4" [features] default = [] -wasm-extern-trace = [] \ No newline at end of file +wasm-extern-trace = [] diff --git a/substrate/executor/src/error.rs b/substrate/executor/src/error.rs index 8cdb157c582e3..00392cbb17b5a 100644 --- a/substrate/executor/src/error.rs +++ b/substrate/executor/src/error.rs @@ -75,21 +75,7 @@ error_chain! { description("invalid memory reference"), display("Invalid memory reference"), } - - /// Retry, please. - PleaseRetry { - description("retry needed"), - display("Retry needed"), - } } } -impl state_machine::Error for Error { - fn needs_retry(&self) -> bool { - if let ErrorKind::PleaseRetry = self.0 { - true - } else { - false - } - } -} +impl state_machine::Error for Error {} diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs index 5101398b0eb7e..0b132ae9ab1fa 100644 --- a/substrate/executor/src/native_executor.rs +++ b/substrate/executor/src/native_executor.rs @@ -28,12 +28,15 @@ use RuntimeInfo; // For the internal Runtime Cache: // Is it compatible enough to run this natively or do we need to fall back on the WasmModule + enum Compatibility { InvalidVersion(WasmModule), - IsCompatible(RuntimeVersion), + IsCompatible(RuntimeVersion, WasmModule), NotCompatible(RuntimeVersion, WasmModule) } +unsafe impl Send for Compatibility {} + type CacheType = HashMap; lazy_static! { @@ -54,6 +57,7 @@ fn gen_cache_key(code: &[u8]) -> u64 { /// the runtime version entry for `code`, determines whether `Compatibility::IsCompatible` /// can be used by by comparing returned RuntimeVersion to `ref_version` fn fetch_cached_runtime_version<'a, E: Externalities>( + wasm_executor: &WasmExecutor, cache: &'a mut MutexGuard, ext: &mut E, code: &[u8], @@ -62,12 +66,12 @@ fn fetch_cached_runtime_version<'a, E: Externalities>( cache.entry(gen_cache_key(code)) .or_insert_with(|| { let module = WasmModule::from_buffer(code).expect("all modules compiled with rustc are valid wasm code; qed"); - let version = WasmExecutor::new(8, 8).call_in_wasm_module(ext, &module, "version", &[]).ok() + let version = wasm_executor.call_in_wasm_module(ext, &module, "version", &[]).ok() .and_then(|v| RuntimeVersion::decode(&mut v.as_slice())); if let Some(v) = version { if ref_version.can_call_with(&v) { - Compatibility::IsCompatible(v) + Compatibility::IsCompatible(v, module) } else { Compatibility::NotCompatible(v, module) } @@ -109,8 +113,8 @@ pub trait NativeExecutionDispatch: Send + Sync { const VERSION: RuntimeVersion; /// Construct corresponding `NativeExecutor` with given `heap_pages`. - fn with_heap_pages(min_heap_pages: usize, max_heap_pages: usize) -> NativeExecutor where Self: Sized { - NativeExecutor::with_heap_pages(min_heap_pages, max_heap_pages) + fn with_heap_pages(max_heap_pages: usize) -> NativeExecutor where Self: Sized { + NativeExecutor::with_heap_pages(max_heap_pages) } } @@ -126,15 +130,10 @@ pub struct NativeExecutor { impl NativeExecutor { /// Create new instance with specific number of pages for wasm fallback's heap. - pub fn with_heap_pages(min_heap_pages: usize, max_heap_pages: usize) -> Self { - // FIXME: set this entry at compile time - RUNTIMES_CACHE.lock().insert( - gen_cache_key(D::native_equivalent()), - Compatibility::IsCompatible(D::VERSION)); - + pub fn with_heap_pages(max_heap_pages: usize) -> Self { NativeExecutor { _dummy: Default::default(), - fallback: WasmExecutor::new(min_heap_pages, max_heap_pages), + fallback: WasmExecutor::new(max_heap_pages), } } } @@ -157,8 +156,8 @@ impl RuntimeInfo for NativeExecutor { code: &[u8], ) -> Option { let mut c = RUNTIMES_CACHE.lock(); - match fetch_cached_runtime_version(&mut c, ext, code, D::VERSION) { - Compatibility::IsCompatible(v) | Compatibility::NotCompatible(v, _) => Some(v.clone()), + match fetch_cached_runtime_version(&self.fallback, &mut c, ext, code, D::VERSION) { + Compatibility::IsCompatible(v, _) | Compatibility::NotCompatible(v, _) => Some(v.clone()), Compatibility::InvalidVersion(_m) => None } } @@ -176,11 +175,9 @@ impl CodeExecutor for NativeExecutor { use_native: bool, ) -> (Result>, bool) { let mut c = RUNTIMES_CACHE.lock(); - match (use_native, fetch_cached_runtime_version(&mut c, ext, code, D::VERSION)) { - (_, Compatibility::NotCompatible(_, m)) | (_, Compatibility::InvalidVersion(m)) => + match (use_native, fetch_cached_runtime_version(&self.fallback, &mut c, ext, code, D::VERSION)) { + (_, Compatibility::NotCompatible(_, m)) | (_, Compatibility::InvalidVersion(m)) | (false, Compatibility::IsCompatible(_, m)) => (self.fallback.call_in_wasm_module(ext, m, method, data), false), - (false, _) => - (self.fallback.call(ext, code, method, data, false).0, false), _ => (D::dispatch(ext, method, data), true), } } @@ -211,8 +208,8 @@ macro_rules! native_executor_instance { .ok_or_else(|| $crate::error::ErrorKind::MethodNotFound(method.to_owned()).into()) } - fn with_heap_pages(min_heap_pages: usize, max_heap_pages: usize) -> $crate::NativeExecutor<$name> { - $crate::NativeExecutor::with_heap_pages(min_heap_pages, max_heap_pages) + fn with_heap_pages(max_heap_pages: usize) -> $crate::NativeExecutor<$name> { + $crate::NativeExecutor::with_heap_pages(max_heap_pages) } } } diff --git a/substrate/executor/src/sandbox.rs b/substrate/executor/src/sandbox.rs index ec0f2e75bbb66..ac91f17433476 100644 --- a/substrate/executor/src/sandbox.rs +++ b/substrate/executor/src/sandbox.rs @@ -524,7 +524,7 @@ impl Store { #[cfg(test)] mod tests { use wasm_executor::WasmExecutor; - use state_machine::{TestExternalities, CodeExecutor}; + use state_machine::TestExternalities; use wabt; #[test] @@ -554,7 +554,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_sandbox", &code, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_sandbox", &code).unwrap(), vec![1], ); } @@ -575,7 +575,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_sandbox", &code, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_sandbox", &code).unwrap(), vec![0], ); } @@ -613,7 +613,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_sandbox", &code, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_sandbox", &code).unwrap(), vec![1], ); } @@ -647,7 +647,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_sandbox_args", &code, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_sandbox_args", &code).unwrap(), vec![1], ); } @@ -669,7 +669,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_sandbox_return_val", &code, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_sandbox_return_val", &code).unwrap(), vec![1], ); } diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index 4582e423b4f43..70571f480096c 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -17,14 +17,13 @@ //! Rust implementation of Substrate contracts. use std::cmp::Ordering; -use parking_lot::Mutex; use std::collections::HashMap; use wasmi::{ - Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder + Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder }; use wasmi::RuntimeValue::{I32, I64}; use wasmi::memory_units::{Pages, Bytes}; -use state_machine::{Externalities, CodeExecutor}; +use state_machine::Externalities; use error::{Error, ErrorKind, Result}; use wasm_utils::UserError; use primitives::{blake2_256, twox_128, twox_256}; @@ -46,9 +45,8 @@ impl Heap { /// This could mean that wasm binary specifies memory /// limit and we are trying to allocate beyond that limit. fn new(memory: &MemoryRef, pages: usize) -> Result { - let prev_page_count = memory - .grow(Pages(pages)) - .map_err(|_| Error::from(ErrorKind::Runtime))?; + let prev_page_count = memory.initial(); + memory.grow(Pages(pages)).map_err(|_| Error::from(ErrorKind::Runtime))?; Ok(Heap { end: Bytes::from(prev_page_count).0 as u32, }) @@ -486,38 +484,41 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, /// Executes the provided code in a sandboxed wasm runtime. #[derive(Debug)] pub struct WasmExecutor { - /// The min number of pages to allocate for the heap. - pub min_heap_pages: usize, /// The max number of pages to allocate for the heap. pub max_heap_pages: usize, - - try_heap_pages: Mutex<(usize, usize)>, } impl Clone for WasmExecutor { fn clone(&self) -> Self { WasmExecutor { - min_heap_pages: self.min_heap_pages, max_heap_pages: self.max_heap_pages, - try_heap_pages: Mutex::new((self.min_heap_pages, 0)), } } } -// Number of executions to continue with the old heap_pages before reducing to the next lowest POT. -const DECAY_TIMEOUT: usize = 16; - impl WasmExecutor { /// Create a new instance. - pub fn new(min_heap_pages: usize, max_heap_pages: usize) -> Self { + pub fn new(max_heap_pages: usize) -> Self { WasmExecutor { - min_heap_pages, max_heap_pages, - try_heap_pages: Mutex::new((min_heap_pages, 0)), } } + + /// Call a given method in the given code. + /// This should be used for tests only. + pub fn call( + &self, + ext: &mut E, + code: &[u8], + method: &str, + data: &[u8], + ) -> Result> { + let module = ::wasmi::Module::from_buffer(code).expect("all modules compiled with rustc are valid wasm code; qed"); + self.call_in_wasm_module(ext, &module, method, data) + } + /// Call a given method in the given wasm-module runtime. pub fn call_in_wasm_module( &self, @@ -549,20 +550,14 @@ impl WasmExecutor { .export_by_name("__indirect_function_table") .and_then(|e| e.as_table().cloned()); - let mut try_heap_pages = self.try_heap_pages.lock(); - let mut fec = FunctionExecutor::new(memory.clone(), try_heap_pages.0, table, ext)?; + let mut fec = FunctionExecutor::new(memory.clone(), self.max_heap_pages, table, ext)?; // finish instantiation by running 'start' function (if any). let instance = intermediate_instance.run_start(&mut fec)?; let size = data.len() as u32; let offset = fec.heap.allocate(size); - if let Err(_) = memory.set(offset, &data) { - let old = try_heap_pages.0; - *try_heap_pages = ((old * 2).min(self.max_heap_pages), DECAY_TIMEOUT); - trace!(target: "wasm-executor", "Shrunk heap size too small at {} pages. Retrying with {}", old, try_heap_pages.0); - return Err(ErrorKind::PleaseRetry.into()) - } + memory.set(offset, &data)?; let result = instance.invoke_export( method, @@ -575,27 +570,12 @@ impl WasmExecutor { let returned = match result { Ok(x) => x, - Err(_) if try_heap_pages.0 < self.max_heap_pages => { - let old = try_heap_pages.0; - *try_heap_pages = ((old * 2).min(self.max_heap_pages), DECAY_TIMEOUT); - trace!(target: "wasm-executor", "Shrunk heap size too small at {} pages. Retrying with {}", old, try_heap_pages.0); - return Err(ErrorKind::PleaseRetry.into()) - } Err(e) => { - trace!(target: "wasm-executor", "Failed to execute code with {} pages", try_heap_pages.0); + trace!(target: "wasm-executor", "Failed to execute code with {} pages", self.max_heap_pages); return Err(e.into()) }, }; - let decay_timeout = try_heap_pages.1; - if decay_timeout == 0 { - if try_heap_pages.0 > self.min_heap_pages { - *try_heap_pages = (self.min_heap_pages.max(try_heap_pages.0 - 1), DECAY_TIMEOUT); - } - } else { - try_heap_pages.1 -= 1; - } - if let Some(I64(r)) = returned { let offset = r as u32; let length = (r >> 32) as u32 as usize; @@ -607,22 +587,6 @@ impl WasmExecutor { } } -impl CodeExecutor for WasmExecutor { - type Error = Error; - - fn call( - &self, - ext: &mut E, - code: &[u8], - method: &str, - data: &[u8], - _use_native: bool - ) -> (Result>, bool) { - (Module::from_buffer(code).map_err(Into::into).and_then(|module| - self.call_in_wasm_module(ext, &module, method, data) - ), false) - } -} #[cfg(test)] mod tests { @@ -643,7 +607,7 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); - let output = WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_empty_return", &[], true).0.unwrap(); + let output = WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_empty_return", &[]).unwrap(); assert_eq!(output, vec![0u8; 0]); } @@ -652,10 +616,10 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); - let output = WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_panic", &[], true).0; + let output = WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_panic", &[]); assert!(output.is_err()); - let output = WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_conditional_panic", &[2], true).0; + let output = WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_conditional_panic", &[2]); assert!(output.is_err()); } @@ -665,7 +629,7 @@ mod tests { ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); - let output = WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_data_in", b"Hello world", true).0.unwrap(); + let output = WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_data_in", b"Hello world").unwrap(); assert_eq!(output, b"all ok!".to_vec()); @@ -688,7 +652,7 @@ mod tests { let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); // This will clear all entries which prefix is "ab". - let output = WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_clear_prefix", b"ab", true).0.unwrap(); + let output = WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_clear_prefix", b"ab").unwrap(); assert_eq!(output, b"all ok!".to_vec()); @@ -705,11 +669,11 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_blake2_256", &[], true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_blake2_256", &[]).unwrap(), blake2_256(&b""[..]).encode() ); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_blake2_256", b"Hello world!", true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_blake2_256", b"Hello world!").unwrap(), blake2_256(&b"Hello world!"[..]).encode() ); } @@ -719,11 +683,11 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_twox_256", &[], true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_twox_256", &[]).unwrap(), FromHex::from_hex("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a").unwrap() ); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_twox_256", b"Hello world!", true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_twox_256", b"Hello world!").unwrap(), FromHex::from_hex("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74").unwrap() ); } @@ -733,11 +697,11 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_twox_128", &[], true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_twox_128", &[]).unwrap(), FromHex::from_hex("99e9d85137db46ef4bbea33613baafd5").unwrap() ); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_twox_128", b"Hello world!", true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_twox_128", b"Hello world!").unwrap(), FromHex::from_hex("b27dfd7f223f177f2a13647b533599af").unwrap() ); } @@ -753,7 +717,7 @@ mod tests { calldata.extend_from_slice(sig.as_ref()); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_ed25519_verify", &calldata, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), vec![1] ); @@ -763,7 +727,7 @@ mod tests { calldata.extend_from_slice(other_sig.as_ref()); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_ed25519_verify", &calldata, true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), vec![0] ); } @@ -773,7 +737,7 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); assert_eq!( - WasmExecutor::new(8, 8).call(&mut ext, &test_code[..], "test_enumerated_trie_root", &[], true).0.unwrap(), + WasmExecutor::new(8).call(&mut ext, &test_code[..], "test_enumerated_trie_root", &[]).unwrap(), ordered_trie_root(vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]).0.encode() ); } diff --git a/substrate/primitives/Cargo.toml b/substrate/primitives/Cargo.toml index 9d844a938b554..19ad354bb01a4 100644 --- a/substrate/primitives/Cargo.toml +++ b/substrate/primitives/Cargo.toml @@ -15,7 +15,7 @@ uint = { git = "https://github.com/rphmeier/primitives.git", branch = "compile-f twox-hash = { version = "1.1.0", optional = true } byteorder = { version = "1.1", default_features = false } blake2-rfc = { version = "0.2.18", optional = true } -wasmi = { version = "0.3", optional = true } +wasmi = { version = "0.4", optional = true } [dev-dependencies] substrate-serializer = { path = "../serializer" } diff --git a/substrate/runtime-sandbox/Cargo.toml b/substrate/runtime-sandbox/Cargo.toml index b624b30f8f89b..c9a7dc0ae1b3c 100755 --- a/substrate/runtime-sandbox/Cargo.toml +++ b/substrate/runtime-sandbox/Cargo.toml @@ -8,7 +8,7 @@ build = "build.rs" rustc_version = "0.2" [dependencies] -wasmi = { version = "0.3", optional = true } +wasmi = { version = "0.4", optional = true } substrate-primitives = { path = "../primitives", default_features = false } substrate-runtime-std = { path = "../runtime-std", default_features = false } substrate-runtime-io = { path = "../runtime-io", default_features = false } diff --git a/substrate/service/src/config.rs b/substrate/service/src/config.rs index b3e42c9b6c0f5..83f3887c5b50b 100644 --- a/substrate/service/src/config.rs +++ b/substrate/service/src/config.rs @@ -59,8 +59,6 @@ pub struct Configuration { pub name: String, /// Execution strategy. pub execution_strategy: ExecutionStrategy, - /// Minimum number of heap pages to allocate for Wasm execution. - pub min_heap_pages: usize, /// Maximum number of heap pages to allocate for Wasm execution. pub max_heap_pages: usize, /// RPC over HTTP binding address. `None` if disabled. @@ -90,7 +88,6 @@ impl Configuration { pub fn new_client(config: FactoryFullConfiguration) -> Result>>, error::Error> { - let executor = NativeExecutor::with_heap_pages(config.min_heap_pages, config.max_heap_pages); + let executor = NativeExecutor::with_heap_pages(config.max_heap_pages); let (client, _) = components::FullComponents::::build_client( &config, executor, @@ -118,7 +118,7 @@ impl Service let (signal, exit) = ::exit_future::signal(); // Create client - let executor = NativeExecutor::with_heap_pages(config.min_heap_pages, config.max_heap_pages); + let executor = NativeExecutor::with_heap_pages(config.max_heap_pages); let mut keystore = Keystore::open(config.keystore_path.as_str().into())?; for seed in &config.keys { diff --git a/substrate/state-machine/src/lib.rs b/substrate/state-machine/src/lib.rs index 17fd85852b6ac..aec2e6acd2399 100644 --- a/substrate/state-machine/src/lib.rs +++ b/substrate/state-machine/src/lib.rs @@ -122,10 +122,7 @@ impl OverlayedChanges { /// State Machine Error bound. /// /// This should reflect WASM error type bound for future compatibility. -pub trait Error: 'static + fmt::Debug + fmt::Display + Send { - /// Error implies execution should be retried. - fn needs_retry(&self) -> bool { false } -} +pub trait Error: 'static + fmt::Debug + fmt::Display + Send {} impl Error for ExecutionError {} @@ -302,7 +299,7 @@ pub fn execute_using_consensus_failure_handler< let result = { let mut orig_prospective = overlay.prospective.clone(); - let (result, was_native, delta) = loop { + let (result, was_native, delta) = { let ((result, was_native), delta) = { let mut externalities = ext::Ext::new(overlay, backend); ( @@ -317,12 +314,7 @@ pub fn execute_using_consensus_failure_handler< externalities.transaction() ) }; - - if result.as_ref().err().map_or(false, |e| e.needs_retry()) { - overlay.prospective = orig_prospective.clone(); - } else { - break (result, was_native, delta) - } + (result, was_native, delta) }; // run wasm separately if we did run native the first time and we're meant to run both @@ -331,7 +323,7 @@ pub fn execute_using_consensus_failure_handler< { overlay.prospective = orig_prospective.clone(); - let (wasm_result, wasm_delta) = loop { + let (wasm_result, wasm_delta) = { let ((result, _), delta) = { let mut externalities = ext::Ext::new(overlay, backend); ( @@ -345,12 +337,7 @@ pub fn execute_using_consensus_failure_handler< externalities.transaction() ) }; - - if result.as_ref().err().map_or(false, |e| e.needs_retry()) { - overlay.prospective = orig_prospective.clone(); - } else { - break (result, delta) - } + (result, delta) }; if (result.is_ok() && wasm_result.is_ok() && result.as_ref().unwrap() == wasm_result.as_ref().unwrap()/* && delta == wasm_delta*/) diff --git a/substrate/test-client/src/client_ext.rs b/substrate/test-client/src/client_ext.rs index be1e9dfe55026..10031f523f5e7 100644 --- a/substrate/test-client/src/client_ext.rs +++ b/substrate/test-client/src/client_ext.rs @@ -39,7 +39,7 @@ pub trait TestClient { impl TestClient for Client { fn new_for_tests() -> Self { - client::new_in_mem(NativeExecutor::with_heap_pages(8, 8), genesis_storage()).unwrap() + client::new_in_mem(NativeExecutor::with_heap_pages(8), genesis_storage()).unwrap() } fn justify_and_import(&self, origin: client::BlockOrigin, block: runtime::Block) -> client::error::Result<()> {