diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 2d02a1799c..d0eee3e39a 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -170,6 +170,10 @@ dependencies = [ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "environmental" +version = "0.1.0" + [[package]] name = "error-chain" version = "0.11.0" @@ -833,8 +837,10 @@ dependencies = [ name = "runtime-support" version = "0.1.0" dependencies = [ + "environmental 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-state-machine 0.1.0", ] [[package]] diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index bfbff56969..21232d39ef 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -12,6 +12,7 @@ members = [ "candidate-agreement", "client", "collator", + "environmental", "executor", "primitives", "rpc", diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs index db46b13158..420c22f44f 100644 --- a/substrate/environmental/src/lib.rs +++ b/substrate/environmental/src/lib.rs @@ -27,20 +27,23 @@ pub fn using_environment<'a, T: 'a, S, F: FnOnce()>( global.with(|r| *r.borrow_mut() = 0 as *mut S); } -pub fn with_environment<'r, S, T: 'r, F: FnOnce(&'r mut T)>( +pub fn with_environment<'r, R, S, T: 'r, F: FnOnce(&'r mut T) -> R>( global: &'static LocalKey>, mutator: F, -) { +) -> Option { + global.with(|r| { let br = r.borrow_mut(); if *br != 0 as *mut S { // safe because it's only non-zero when it in with_environment, which // is holding on to the underlying reference safely unsafe { - mutator(&mut *(*br as *mut S as *mut T)); + Some(mutator(&mut *(*br as *mut S as *mut T))) } + } else { + None } - }); + }) } #[macro_export] @@ -64,16 +67,18 @@ macro_rules! declare_generic_environment { $crate::using_environment(&GLOBAL, protected, f); } - pub fn with FnOnce(&'r mut $t<'t>)>(f: F) { + pub fn with FnOnce(&'r mut $t<'t>) -> R>( + f: F + ) -> Option { let dummy = (); - with_closed(f, &dummy); + with_closed(f, &dummy) } - fn with_closed<'d: 't, 't: 'r, 'r, F: FnOnce(&'r mut $t<'t>)>( + fn with_closed<'d: 't, 't: 'r, 'r, R, F: FnOnce(&'r mut $t<'t>) -> R>( f: F, _dummy: &'d (), - ) { - $crate::with_environment(&GLOBAL, f); + ) -> Option { + $crate::with_environment(&GLOBAL, f) } } } @@ -91,16 +96,18 @@ macro_rules! declare_simple_environment { $crate::using_environment(&GLOBAL, protected, f); } - pub fn with FnOnce(&'r mut $t)>(f: F) { + pub fn with FnOnce(&'r mut $t -> R)>( + f: F + ) -> Option { let dummy = (); - with_closed(f, &dummy); + with_closed(f, &dummy) } - fn with_closed<'d: 'r, 'r, F: FnOnce(&'r mut $t)>( + fn with_closed<'d: 'r, 'r, R, F: FnOnce(&'r mut $t -> R)>( f: F, _dummy: &'d (), - ) { - $crate::with_environment(&GLOBAL, f); + ) -> Option { + $crate::with_environment(&GLOBAL, f) } } } diff --git a/substrate/executor/src/wasm_utils.rs b/substrate/executor/src/wasm_utils.rs index 6d4fedfedb..f6440628b9 100644 --- a/substrate/executor/src/wasm_utils.rs +++ b/substrate/executor/src/wasm_utils.rs @@ -119,13 +119,13 @@ pub trait IntoUserDefinedElements { #[macro_export] macro_rules! impl_function_executor { ( $objectname:ident : $structname:ty, $( $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt ),* => $($pre:tt)+ ) => ( - impl $( $pre ) + $crate::wasm_utils::UserFunctionExecutor<$crate::wasm_utils::DummyUserError> for $structname { + impl $($pre)+ $crate::wasm_utils::UserFunctionExecutor<$crate::wasm_utils::DummyUserError> for $structname { dispatch!($objectname, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*); } - impl $( $pre ) + $structname { + impl $($pre)+ $structname { signatures!($( $name( $( $params ),* ) $( -> $returns )* ),*); } - impl $( $pre ) + $crate::wasm_utils::IntoUserDefinedElements for $structname { + impl $($pre)+ $crate::wasm_utils::IntoUserDefinedElements for $structname { fn into_user_defined_elements(&mut self) -> UserDefinedElements<$crate::wasm_utils::DummyUserError> { $crate::wasm_utils::UserDefinedElements { executor: Some(self), diff --git a/substrate/native-runtime/support/Cargo.toml b/substrate/native-runtime/support/Cargo.toml index 4f4e0202b5..3f979bd4ff 100644 --- a/substrate/native-runtime/support/Cargo.toml +++ b/substrate/native-runtime/support/Cargo.toml @@ -9,3 +9,5 @@ strict = [] [dependencies] lazy_static = "1.0.0" parking_lot = "0.5" +polkadot-state-machine = { path = "../../state_machine" , version = "0.1" } +environmental = { path = "../../environmental", version = "0.1.0" } diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index 0e12d5e678..091e07fbce 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -1,6 +1,6 @@ #[macro_use] -extern crate lazy_static; -extern crate parking_lot; +extern crate environmental; +extern crate polkadot_state_machine; pub use std::vec::Vec; pub use std::rc::Rc; @@ -8,38 +8,51 @@ pub use std::cell::RefCell; pub use std::boxed::Box; pub use std::mem::{size_of, transmute}; -use std::collections::HashMap; -use parking_lot::Mutex; +use polkadot_state_machine::Externalities; +use std::fmt; -lazy_static! { - static ref HASHMAP: Mutex, Vec>> = Mutex::new(HashMap::new()); +// TODO: use the real error, not NoError. + +#[derive(Debug)] +struct NoError; +impl fmt::Display for NoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } } +pub struct ExternalitiesHolder<'a> { + ext: &'a mut Externalities, +} + +declare_generic_environment!(ext : ExternalitiesHolder); + pub fn storage(_key: &[u8]) -> Vec { - HASHMAP.lock().get(_key).cloned().unwrap_or_else(Vec::new) + ext::with(|holder| holder.ext.storage(_key).ok().map(|s| s.to_vec())) + .unwrap_or(None) + .unwrap_or_else(|| vec![]) } pub fn storage_into(_key: &[u8]) -> Option { let size = size_of::(); - if let Some(value) = HASHMAP.lock().get(_key) { - if value.len() == size { - unsafe { - let mut result: T = std::mem::uninitialized(); - std::slice::from_raw_parts_mut(transmute::<*mut T, *mut u8>(&mut result), size) - .copy_from_slice(&value); - return Some(result); + + ext::with(|holder| { + if let Ok(value) = holder.ext.storage(_key) { + if value.len() == size { + unsafe { + let mut result: T = std::mem::uninitialized(); + std::slice::from_raw_parts_mut(transmute::<*mut T, *mut u8>(&mut result), size) + .copy_from_slice(&value); + return Some(result); + } } } - } - None + None + }).unwrap_or(None) } pub fn set_storage(_key: &[u8], _value: &[u8]) { - HASHMAP.lock().insert(_key.to_vec(), _value.to_vec()); -} - -pub fn init_storage(new: HashMap, Vec>) { - *HASHMAP.lock() = new; + ext::with(|holder| + holder.ext.set_storage(_key.to_vec(), _value.to_vec()) + ); } #[macro_export] @@ -50,6 +63,23 @@ macro_rules! impl_stubs { #[cfg(test)] mod tests { use super::*; + use std::collections::HashMap; + + #[derive(Debug, Default)] + struct TestExternalities { + storage: HashMap, Vec>, + } + impl Externalities for TestExternalities { + type Error = NoError; + + fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> { + Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) + } + + fn set_storage(&mut self, key: Vec, value: Vec) { + self.storage.insert(key, value); + } + } macro_rules! map { ($( $name:expr => $value:expr ),*) => ( @@ -59,15 +89,29 @@ mod tests { #[test] fn storage_works() { - assert_eq!(storage(b"hello"), vec![]); - set_storage(b"hello", b"world"); - assert_eq!(storage(b"hello"), b"world".to_vec()); - assert_eq!(storage(b"foo"), vec![]); - set_storage(b"foo", &[1, 2, 3][..]); - assert_eq!(storage_into::<[u8; 3]>(b"foo"), Some([1, 2, 3])); - assert_eq!(storage_into::<[u8; 3]>(b"hello"), None); - init_storage(map![b"foo".to_vec() => b"bar".to_vec()]); - assert_eq!(storage(b"hello"), vec![]); - assert_eq!(storage(b"foo"), b"bar".to_vec()); + let mut t = TestExternalities { storage: map![], }; + + { + let mut h = ExternalitiesHolder { ext: &mut t, }; + ext::using(&mut h, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + set_storage(b"hello", b"world"); + assert_eq!(storage(b"hello"), b"world".to_vec()); + assert_eq!(storage(b"foo"), b"".to_vec()); + set_storage(b"foo", &[1, 2, 3][..]); + assert_eq!(storage_into::<[u8; 3]>(b"foo"), Some([1, 2, 3])); + assert_eq!(storage_into::<[u8; 3]>(b"hello"), None); + }); + } + + t.storage = map![b"foo".to_vec() => b"bar".to_vec()]; + + { + let mut h = ExternalitiesHolder { ext: &mut t, }; + ext::using(&mut h, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + assert_eq!(storage(b"foo"), b"bar".to_vec()); + }); + } } }