diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index a05893e615..1595bc0272 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -726,10 +726,12 @@ dependencies = [ "assert_matches 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "native-runtime 0.1.0", "parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-primitives 0.1.0", "polkadot-serializer 0.1.0", "polkadot-state-machine 0.1.0", + "runtime-support 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/substrate/executor/Cargo.toml b/substrate/executor/Cargo.toml index 0401bd4c77..dbdef883cc 100644 --- a/substrate/executor/Cargo.toml +++ b/substrate/executor/Cargo.toml @@ -13,6 +13,8 @@ serde_derive = "1.0" parity-wasm = "0.15.0" byteorder = "1.1" rustc-hex = "1.0.0" +native-runtime = { path = "../native-runtime", version = "0.1" } +runtime-support = { path = "../native-runtime/support", version = "0.1" } [dev-dependencies] assert_matches = "1.1" diff --git a/substrate/executor/src/error.rs b/substrate/executor/src/error.rs index 4fd0ec0604..c1f9c2c711 100644 --- a/substrate/executor/src/error.rs +++ b/substrate/executor/src/error.rs @@ -17,7 +17,6 @@ //! Rust executor possible errors. use serializer; -use state_machine; error_chain! { foreign_links { @@ -38,9 +37,9 @@ error_chain! { } /// Externalities have failed. - Externalities(e: Box) { + Externalities { description("externalities failure"), - display("Externalities error: {}", e), + display("Externalities error"), } /// Invalid index. diff --git a/substrate/executor/src/lib.rs b/substrate/executor/src/lib.rs index f1da582538..56c39e5b49 100644 --- a/substrate/executor/src/lib.rs +++ b/substrate/executor/src/lib.rs @@ -34,6 +34,8 @@ extern crate serde; extern crate parity_wasm; extern crate byteorder; extern crate rustc_hex; +extern crate native_runtime; +extern crate runtime_support; #[macro_use] extern crate error_chain; @@ -44,10 +46,13 @@ extern crate assert_matches; #[macro_use] mod wasm_utils; mod wasm_executor; +mod native_executor; pub mod error; /// Creates new RustExecutor for contracts. pub fn executor() -> wasm_executor::WasmExecutor { + // TODO: check what the code to execute is and use NativeExecutor if the wasm is compiled with + // matches. wasm_executor::WasmExecutor::default() } diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs new file mode 100644 index 0000000000..5e588d559c --- /dev/null +++ b/substrate/executor/src/native_executor.rs @@ -0,0 +1,34 @@ +use primitives::contract::CallData; +use state_machine::{Externalities, CodeExecutor}; +use error::{Error, ErrorKind, Result}; +use native_runtime as runtime; +use runtime_support; + +struct NativeExecutor; + +impl CodeExecutor for NativeExecutor { + type Error = Error; + + fn call( + &self, + ext: &mut E, + code: &[u8], + method: &str, + data: &CallData, + ) -> Result> { + // WARNING!!! This assumes that the runtime was built *before* the main project. Until we + // get a proper build script, this must be strictly adhered to or things will go wrong. + let native_equivalent = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm"); + if code == &native_equivalent[..] { + runtime_support::with_externalities(ext, || match method { + // TODO: Panic handler that comes back with error. + "execute_block" => Ok(runtime::execute_block(data.0)), + "execute_transaction" => Ok(runtime::execute_transaction(data.0)), + _ => Err(ErrorKind::MethodNotFound(method.to_owned()).into()), + }) + } else { + // call into wasm. + unimplemented!() + } + } +} diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index d0bc908136..561e557ad9 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -241,15 +241,14 @@ mod tests { use super::*; use rustc_hex::FromHex; + use state_machine::ExternalitiesError; #[derive(Debug, Default)] struct TestExternalities { storage: HashMap, Vec>, } impl Externalities for TestExternalities { - type Error = Error; - - fn storage(&self, key: &[u8]) -> Result<&[u8]> { + fn storage(&self, key: &[u8]) -> ::std::result::Result<&[u8], ExternalitiesError> { Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) } diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index 47755c3f75..68914423b5 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -31,7 +31,7 @@ pub use std::boxed::Box; pub use std::slice; pub use std::mem::{size_of, transmute, swap, uninitialized}; -pub use polkadot_state_machine::Externalities; +pub use polkadot_state_machine::{Externalities, ExternalitiesError}; // TODO: use the real error, not NoError. @@ -42,7 +42,7 @@ impl fmt::Display for NoError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } } -environmental!(ext : Externalities + 'static); +environmental!(ext : Externalities + 'static); /// Get `key` from storage and return a `Vec`, empty if there's a problem. pub fn storage(key: &[u8]) -> Vec { @@ -93,7 +93,7 @@ pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool { /// Execute the given closure with global function available whose functionality routes into the /// externalities `ext`. Forwards the value that the closure returns. -pub fn with_externalities R>(ext: &mut (Externalities + 'static), f: F) -> R { +pub fn with_externalities R>(ext: &mut (Externalities + 'static), f: F) -> R { ext::using(ext, f) } @@ -112,9 +112,7 @@ mod tests { storage: HashMap, Vec>, } impl Externalities for TestExternalities { - type Error = NoError; - - fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> { + fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> { Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) } diff --git a/substrate/state_machine/src/ext.rs b/substrate/state_machine/src/ext.rs index 1452558ccd..764c51de10 100644 --- a/substrate/state_machine/src/ext.rs +++ b/substrate/state_machine/src/ext.rs @@ -19,7 +19,7 @@ use std::{error, fmt}; use backend::Backend; -use {Externalities, OverlayedChanges}; +use {Externalities, ExternalitiesError, OverlayedChanges}; /// Errors that can occur when interacting with the externalities. #[derive(Debug, Copy, Clone)] @@ -61,12 +61,10 @@ pub struct Ext<'a, B: 'a> { impl<'a, B: 'a> Externalities for Ext<'a, B> where B: Backend { - type Error = B::Error; - - fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error> { + fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> { match self.overlay.storage(key) { Some(x) => Ok(x), - None => self.backend.storage(key) + None => self.backend.storage(key).map_err(|_| ExternalitiesError), } } diff --git a/substrate/state_machine/src/lib.rs b/substrate/state_machine/src/lib.rs index cd25cdcb90..cd7f9291bb 100644 --- a/substrate/state_machine/src/lib.rs +++ b/substrate/state_machine/src/lib.rs @@ -113,6 +113,18 @@ impl OverlayedChanges { pub trait Error: 'static + fmt::Debug + fmt::Display + Send {} impl Error for E where E: 'static + fmt::Debug + fmt::Display + Send {} +/// Externalities Error. +/// +/// Externalities are not really allowed to have errors, since it's assumed that dependent code +/// would not be executed unless externalities were available. This is included for completeness, +/// and as a transition away from the pre-existing framework. +#[derive(Debug, Eq, PartialEq)] +pub struct ExternalitiesError; + +impl fmt::Display for ExternalitiesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Externalities Error") } +} + fn to_keyed_vec(value: u32, mut prepend: Vec) -> Vec { prepend.extend((0..::std::mem::size_of::()).into_iter().map(|i| (value >> (i * 8)) as u8)); prepend @@ -120,11 +132,8 @@ fn to_keyed_vec(value: u32, mut prepend: Vec) -> Vec { /// Externalities: pinned to specific active address. pub trait Externalities { - /// Externalities error type. - type Error: Error; - /// Read storage of current contract being called. - fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error>; + fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError>; /// Set storage of current contract being called (effective immediately). fn set_storage(&mut self, key: Vec, value: Vec); @@ -133,7 +142,7 @@ pub trait Externalities { fn chain_id(&self) -> u64; /// Get the current set of authorities from storage. - fn authorities(&self) -> Result, Self::Error> { + fn authorities(&self) -> Result, ExternalitiesError> { (0..self.storage(b"con:aut:len")?.into_iter() .rev() .fold(0, |acc, &i| (acc << 8) + (i as u32))) @@ -202,7 +211,7 @@ pub fn execute( #[cfg(test)] mod tests { use std::collections::HashMap; - use super::{OverlayedChanges, Externalities}; + use super::{OverlayedChanges, Externalities, ExternalitiesError}; #[test] fn overlayed_storage_works() { @@ -234,9 +243,7 @@ mod tests { storage: HashMap, Vec>, } impl Externalities for TestExternalities { - type Error = u8; - - fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error> { + fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> { Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) } diff --git a/substrate/wasm-runtime/polkadot/src/support/testing.rs b/substrate/wasm-runtime/polkadot/src/support/testing.rs index e2e7b40562..63aca0f8ae 100644 --- a/substrate/wasm-runtime/polkadot/src/support/testing.rs +++ b/substrate/wasm-runtime/polkadot/src/support/testing.rs @@ -16,7 +16,7 @@ //! Testing helpers. -use runtime_support::{NoError, Externalities}; +use runtime_support::{Externalities, ExternalitiesError}; use std::collections::HashMap; use primitives::AccountID; use statichex::StaticHexInto; @@ -29,9 +29,7 @@ pub struct TestExternalities { } impl Externalities for TestExternalities { - type Error = NoError; - - fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> { + fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> { Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) }