diff --git a/Cargo.lock b/Cargo.lock index 5a17eaed3199d..d2b9b24556497 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3826,12 +3826,14 @@ dependencies = [ "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-sandbox 2.0.0", "sr-std 2.0.0", "substrate-externalities 2.0.0", "substrate-primitives 2.0.0", "substrate-state-machine 2.0.0", "substrate-trie 2.0.0", "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6248,6 +6250,17 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wabt" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wabt" version = "0.9.2" @@ -6259,6 +6272,16 @@ dependencies = [ "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wabt-sys" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wabt-sys" version = "0.7.0" @@ -7055,7 +7078,9 @@ dependencies = [ "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" +"checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" diff --git a/core/executor/src/host_interface.rs b/core/executor/src/host_interface.rs index 7c99415f6c752..4e6a8cc4b1584 100644 --- a/core/executor/src/host_interface.rs +++ b/core/executor/src/host_interface.rs @@ -132,6 +132,11 @@ impl_wasm_host_interface! { context.sandbox().memory_teardown(memory_idx) } + ext_run_wasm() { + runtime_io::run_wasm(); + Ok(()) + } + ext_print_utf8(utf8_data: Pointer, utf8_len: WordSize) { if let Ok(utf8) = context.read_memory(utf8_data, utf8_len) { runtime_io::print_utf8(&utf8); diff --git a/core/rpc/api/src/state/mod.rs b/core/rpc/api/src/state/mod.rs index 0d06092ca1659..29760a2ccb465 100644 --- a/core/rpc/api/src/state/mod.rs +++ b/core/rpc/api/src/state/mod.rs @@ -99,6 +99,10 @@ pub trait StateApi { #[rpc(name = "state_getRuntimeVersion", alias("chain_getRuntimeVersion"))] fn runtime_version(&self, hash: Option) -> FutureResult; + /// Reads storage value at a given block + key, returning read proof. + #[rpc(name = "state_getReadProof")] + fn read_proof(&self, id: Option, key: StorageKey) -> FutureResult>>; + /// Query historical storage entries (by key) starting from a block given as the second parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. diff --git a/core/rpc/src/state/mod.rs b/core/rpc/src/state/mod.rs index b922601b0a5b2..a65b5ada982f3 100644 --- a/core/rpc/src/state/mod.rs +++ b/core/rpc/src/state/mod.rs @@ -136,6 +136,9 @@ pub trait StateBackend: Send + Sync + 'static /// Get the runtime version. fn runtime_version(&self, block: Option) -> FutureResult; + /// Reads storage value at a given block + key, returning read proof. + fn read_proof(&self, block: Option, key: StorageKey) -> FutureResult>>; + /// Query historical storage entries (by key) starting from a block given as the second parameter. /// /// NOTE This first returned result contains the initial state of storage for all keys. @@ -323,6 +326,10 @@ impl StateApi for State self.backend.runtime_version(at) } + fn read_proof(&self, block: Option, key: StorageKey) -> FutureResult>> { + self.backend.read_proof(block, key) + } + fn subscribe_runtime_version(&self, meta: Self::Metadata, subscriber: Subscriber) { self.backend.subscribe_runtime_version(meta, subscriber); } diff --git a/core/rpc/src/state/state_full.rs b/core/rpc/src/state/state_full.rs index cd05093c3a8cb..d70e5179327a1 100644 --- a/core/rpc/src/state/state_full.rs +++ b/core/rpc/src/state/state_full.rs @@ -337,6 +337,17 @@ impl StateBackend for FullState, + key: StorageKey, + ) -> FutureResult>> { + Box::new(result( + self.block_or_best(block) + .and_then(|block| self.client.read_proof(&BlockId::Hash(block), &[key.0])) + .map_err(client_err))) + } + fn query_storage( &self, from: Block::Hash, diff --git a/core/rpc/src/state/state_light.rs b/core/rpc/src/state/state_light.rs index 3d0c7979e3995..051fc4d5fdb83 100644 --- a/core/rpc/src/state/state_light.rs +++ b/core/rpc/src/state/state_light.rs @@ -304,6 +304,14 @@ impl StateBackend for LightState, + key: StorageKey, + ) -> FutureResult>> { + Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient)))) + } + fn query_storage( &self, _from: Block::Hash, diff --git a/core/sr-io/Cargo.toml b/core/sr-io/Cargo.toml index e2b681b75bfd1..bab2da2650613 100644 --- a/core/sr-io/Cargo.toml +++ b/core/sr-io/Cargo.toml @@ -18,10 +18,15 @@ tiny-keccak = { version = "1.5.0", optional = true } substrate-state-machine = { path = "../state-machine", optional = true } trie = { package = "substrate-trie", path = "../trie", optional = true } externalities = { package = "substrate-externalities", path = "../externalities", optional = true } +sandbox = { package = "sr-sandbox", path = "../sr-sandbox", default-features = false } + +[dev-dependencies] +wabt = "~0.7.4" [features] default = ["std"] std = [ + "sandbox/std", "primitives/std", "codec/std", "rstd/std", diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 24f964c7b5823..fb78f88fdf9cd 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -151,6 +151,7 @@ export_api! { pub(crate) trait OtherApi { /// The current relay chain identifier. fn chain_id() -> u64; + fn run_wasm(); /// Print a number. fn print_num(val: u64); diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index e431ae1f6e6bf..3bd48214bc6ea 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -28,6 +28,74 @@ use trie::{TrieConfiguration, trie_types::Layout}; use std::{collections::HashMap, convert::TryFrom}; use externalities::{with_externalities, set_and_run_with_externalities, ExternalitiesExt}; +use sandbox::{EnvironmentDefinitionBuilder, Error, HostError, Instance, ReturnValue, TypedValue}; + +// environmental!(ext: trait Externalities); + +fn execute_wasm(code: &[u8], args: &[TypedValue]) -> Result { + struct State { + counter: u32, + } + fn check_read_proof(_e: &mut State, _args: &[TypedValue]) -> Result { + // TODO: Add true verification here + Ok(ReturnValue::Value(TypedValue::I32(1))) + } + + let mut env_builder = EnvironmentDefinitionBuilder::new(); + + let mut state = State {counter: 0}; + + env_builder.add_host_func("env", "ext_check_read_proof", check_read_proof); + + let memory = match sandbox::Memory::new(100, Some(100)) { + Ok(m) => m, + Err(_) => unreachable!(" + Memory::new() can return Err only if parameters are borked; \ + We passing params here explicitly and they're correct; \ + Memory::new() can't return a Error qed" + ), + }; + + env_builder.add_memory("env", "memory", memory); + let mut instance = Instance::new(code, &env_builder, &mut state)?; + let result = instance.invoke(b"check_read_proof", args, &mut state); + + result.map_err(|err| { + HostError + }) +} + +#[test] +fn invoke_proof() { + let code = wabt::wat2wasm(r#" +(module + (type $t0 (func (result i32))) + (import "env" "memory" (memory $env.memory 17)) + (import "env" "ext_check_read_proof" (func $ext_check_read_proof (type $t0))) + (func $check_read_proof (type $t0) (result i32) + (local $l0 i32) + call $ext_check_read_proof + set_local $l0 + get_local $l0 + return) + (table $__indirect_function_table 1 1 anyfunc) + (global $__data_end i32 (i32.const 1048610)) + (global $__heap_base i32 (i32.const 1048610)) + (global $__rustc_debug_gdb_scripts_section__ i32 (i32.const 1048576)) + (export "__indirect_function_table" (table 0)) + (export "__data_end" (global 0)) + (export "__heap_base" (global 1)) + (export "__rustc_debug_gdb_scripts_section__" (global 2)) + (export "check_read_proof" (func $check_read_proof)) +) "#).unwrap(); + + let result = execute_wasm( + &code, + &[], + ); + assert_eq!(result.unwrap(), ReturnValue::Value(TypedValue::I32(1))); +} + /// Additional bounds for `Hasher` trait for with_std. pub trait HasherBounds {} @@ -179,6 +247,16 @@ impl OtherApi for () { ).unwrap_or(0) } + fn run_wasm() { + use std::fs; + + // TODO: Read wasm from chain + let code = fs::read("/tmp/proof.compact.wasm").expect("Wasm file not found"); + let args = []; + let res = execute_wasm(&code, &args); + println!("result: {:?}", res); + } + fn print_num(val: u64) { println!("{}", val); } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 90ec5a9ee4501..e03a0902c5666 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -154,6 +154,7 @@ pub mod ext { /// (most importantly, storage) or perform heavy hash calculations. /// See also "ext_" functions in sr-sandbox and sr-std extern_functions! { + fn ext_run_wasm(); /// Host functions for printing, useful for debugging. fn ext_print_utf8(utf8_data: *const u8, utf8_len: u32); /// Print data as hex. @@ -763,6 +764,12 @@ impl OtherApi for () { } } + fn run_wasm() { + unsafe { + ext_run_wasm.get()(); + } + } + fn print_num(val: u64) { unsafe { ext_print_num.get()(val);