Move Externalities into its own crate (#3775)

* Move `Externalities` into `substrate-externalities`

- `Externalities` now support generic extensions
- Split of `primtives-storage` for storage primitive types

* Move the externalities scoping into `substrate-externalities`

* Fix compilation

* Review feedback

* Adds macro for declaring extensions

* Fix benchmarks

* Introduce `ExtensionStore` trait

* Last review comments

* Implement it for `ExtensionStore`
This commit is contained in:
Bastian Köcher
2019-10-09 15:50:30 +02:00
committed by GitHub
parent 984c6ac839
commit 8a39be474e
95 changed files with 1600 additions and 1420 deletions
@@ -53,14 +53,7 @@ impl RuntimePublic for Public {
#[cfg(test)]
mod tests {
use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi};
use primitives::{
testing::{
KeyStore,
ED25519,
},
crypto::Pair,
traits::BareCryptoStore as _,
};
use primitives::{testing::{KeyStore, ED25519}, crypto::Pair};
use test_client::{
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
runtime::{TestAPI, app_crypto::ed25519::{AppPair, AppPublic}},
@@ -53,14 +53,7 @@ impl RuntimePublic for Public {
#[cfg(test)]
mod tests {
use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi};
use primitives::{
testing::{
KeyStore,
SR25519,
},
crypto::Pair,
traits::BareCryptoStore as _,
};
use primitives::{testing::{KeyStore, SR25519}, crypto::Pair};
use test_client::{
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
runtime::{TestAPI, app_crypto::sr25519::{AppPair, AppPublic}},
+2 -3
View File
@@ -224,7 +224,7 @@ pub fn new_client<E, S, Block, RA>(
>
where
Block: BlockT<Hash=H256>,
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
E: CodeExecutor + RuntimeInfo,
S: BuildStorage,
{
let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?);
@@ -456,8 +456,7 @@ impl<Block: BlockT, H: Hasher> BlockImportOperation<Block, H> {
}
impl<Block> client::backend::BlockImportOperation<Block, Blake2Hasher>
for BlockImportOperation<Block, Blake2Hasher>
where Block: BlockT<Hash=H256>,
for BlockImportOperation<Block, Blake2Hasher> where Block: BlockT<Hash=H256>,
{
type State = CachingState<Blake2Hasher, RefTrackingState<Block>, Block>;
+17 -24
View File
@@ -26,8 +26,8 @@ use state_machine::{
use executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
use hash_db::Hasher;
use primitives::{
offchain::{self, NeverOffchainExt}, H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue,
traits::CodeExecutor,
offchain::OffchainExt, H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue,
traits::{CodeExecutor, KeystoreExt},
};
use crate::runtime_api::{ProofRecorder, InitializeBlock};
@@ -47,15 +47,13 @@ where
/// Execute a call to a contract on top of state in a block of given hash.
///
/// No changes are made.
fn call<
O: offchain::Externalities,
>(
fn call(
&self,
id: &BlockId<B>,
method: &str,
call_data: &[u8],
strategy: ExecutionStrategy,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
) -> Result<Vec<u8>, error::Error>;
/// Execute a contextual call on top of state in a block of a given hash.
@@ -65,7 +63,6 @@ where
/// of the execution context.
fn contextual_call<
'a,
O: offchain::Externalities,
IB: Fn() -> error::Result<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -83,7 +80,7 @@ where
initialize_block: InitializeBlock<'a, B>,
execution_manager: ExecutionManager<EM>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
proof_recorder: &Option<Rc<RefCell<ProofRecorder<B>>>>,
enable_keystore: bool,
) -> error::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
@@ -97,11 +94,10 @@ where
///
/// No changes are made.
fn call_at_state<
O: offchain::Externalities,
S: state_machine::Backend<H>,
F: FnOnce(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
Result<NativeOrEncoded<R>, Self::Error>,
) -> Result<NativeOrEncoded<R>, Self::Error>,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
@@ -112,7 +108,7 @@ where
call_data: &[u8],
manager: ExecutionManager<F>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
) -> Result<
(
NativeOrEncoded<R>,
@@ -191,18 +187,18 @@ impl<B, E> Clone for LocalCallExecutor<B, E> where E: Clone {
impl<B, E, Block> CallExecutor<Block, Blake2Hasher> for LocalCallExecutor<B, E>
where
B: backend::Backend<Block, Blake2Hasher>,
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
E: CodeExecutor + RuntimeInfo,
Block: BlockT<Hash=H256>,
{
type Error = E::Error;
fn call<O: offchain::Externalities>(
fn call(
&self,
id: &BlockId<Block>,
method: &str,
call_data: &[u8],
strategy: ExecutionStrategy,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
) -> error::Result<Vec<u8>> {
let mut changes = OverlayedChanges::default();
let state = self.backend.state_at(*id)?;
@@ -214,7 +210,7 @@ where
&self.executor,
method,
call_data,
self.keystore.clone(),
self.keystore.clone().map(KeystoreExt),
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
strategy.get_manager(),
false,
@@ -227,7 +223,6 @@ where
fn contextual_call<
'a,
O: offchain::Externalities,
IB: Fn() -> error::Result<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -245,7 +240,7 @@ where
initialize_block: InitializeBlock<'a, Block>,
execution_manager: ExecutionManager<EM>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
enable_keystore: bool,
) -> Result<NativeOrEncoded<R>, error::Error> where ExecutionManager<EM>: Clone {
@@ -259,7 +254,7 @@ where
}
let keystore = if enable_keystore {
self.keystore.clone()
self.keystore.clone().map(KeystoreExt)
} else {
None
};
@@ -326,7 +321,6 @@ where
&mut overlay,
&state,
self.backend.changes_trie_storage(),
NeverOffchainExt::new(),
None,
);
let version = self.executor.runtime_version(&mut ext);
@@ -335,11 +329,10 @@ where
}
fn call_at_state<
O: offchain::Externalities,
S: state_machine::Backend<Blake2Hasher>,
F: FnOnce(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
Result<NativeOrEncoded<R>, Self::Error>,
) -> Result<NativeOrEncoded<R>, Self::Error>,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
@@ -350,7 +343,7 @@ where
call_data: &[u8],
manager: ExecutionManager<F>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
) -> error::Result<(
NativeOrEncoded<R>,
(S::Transaction, <Blake2Hasher as Hasher>::Out),
@@ -364,7 +357,7 @@ where
&self.executor,
method,
call_data,
self.keystore.clone(),
self.keystore.clone().map(KeystoreExt),
).execute_using_consensus_failure_handler(
manager,
true,
@@ -391,7 +384,7 @@ where
&self.executor,
method,
call_data,
self.keystore.clone(),
self.keystore.clone().map(KeystoreExt),
)
.map_err(Into::into)
}
+31 -21
View File
@@ -28,7 +28,7 @@ use hash_db::{Hasher, Prefix};
use primitives::{
Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue, ExecutionContext,
NativeOrEncoded, storage::{StorageKey, StorageData, well_known_keys},
offchain::{NeverOffchainExt, self}, traits::CodeExecutor,
offchain::{OffchainExt, self}, traits::CodeExecutor,
};
use substrate_telemetry::{telemetry, SUBSTRATE_INFO};
use sr_primitives::{
@@ -248,7 +248,7 @@ pub fn new_in_mem<E, Block, S, RA>(
Block,
RA
>> where
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
E: CodeExecutor + RuntimeInfo,
S: BuildStorage,
Block: BlockT<Hash=H256>,
{
@@ -264,7 +264,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
keystore: Option<primitives::traits::BareCryptoStorePtr>,
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
where
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
E: CodeExecutor + RuntimeInfo,
S: BuildStorage,
Block: BlockT<Hash=H256>,
B: backend::LocalBackend<Block, Blake2Hasher>
@@ -1058,18 +1058,27 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
}),
}
};
let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, _, NeverNativeValue, fn() -> _>(
transaction_state,
&mut overlay,
"Core_execute_block",
&<Block as BlockT>::new(import_headers.pre().clone(), body.unwrap_or_default()).encode(),
match origin {
BlockOrigin::NetworkInitialSync => get_execution_manager(self.execution_strategies().syncing),
_ => get_execution_manager(self.execution_strategies().importing),
},
None,
NeverOffchainExt::new(),
)?;
let encoded_block = <Block as BlockT>::new(
import_headers.pre().clone(),
body.unwrap_or_default(),
).encode();
let (_, storage_update, changes_update) = self.executor
.call_at_state::<_, _, NeverNativeValue, fn() -> _>(
transaction_state,
&mut overlay,
"Core_execute_block",
&encoded_block,
match origin {
BlockOrigin::NetworkInitialSync => get_execution_manager(
self.execution_strategies().syncing,
),
_ => get_execution_manager(self.execution_strategies().importing),
},
None,
None,
)?;
overlay.commit_prospective();
@@ -1460,12 +1469,13 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
};
let capabilities = context.capabilities();
let mut offchain_extensions = match context {
ExecutionContext::OffchainCall(ext) => ext.map(|x| x.0),
_ => None,
}.map(|ext| offchain::LimitedExternalities::new(capabilities, ext));
let offchain_extensions = if let ExecutionContext::OffchainCall(Some(ext)) = context {
Some(OffchainExt::new(offchain::LimitedExternalities::new(capabilities, ext.0)))
} else {
None
};
self.executor.contextual_call::<_, _, fn(_,_) -> _,_,_>(
self.executor.contextual_call::<_, fn(_,_) -> _,_,_>(
|| core_api.initialize_block(at, &self.prepare_environment_block(at)?),
at,
function,
@@ -1474,7 +1484,7 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
initialize_block,
manager,
native_call,
offchain_extensions.as_mut(),
offchain_extensions,
recorder,
capabilities.has(offchain::Capability::Keystore),
)
+7 -7
View File
@@ -53,7 +53,7 @@ mod tests {
runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest},
AccountKeyring, Sr25519Keyring,
};
use primitives::{Blake2Hasher, map, offchain::NeverOffchainExt};
use primitives::{Blake2Hasher, map};
use hex_literal::*;
native_executor_instance!(
@@ -93,7 +93,7 @@ mod tests {
StateMachine::new(
backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"Core_initialize_block",
@@ -107,7 +107,7 @@ mod tests {
StateMachine::new(
backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"BlockBuilder_apply_extrinsic",
@@ -121,7 +121,7 @@ mod tests {
let (ret_data, _, _) = StateMachine::new(
backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"BlockBuilder_finalize_block",
@@ -169,7 +169,7 @@ mod tests {
let _ = StateMachine::new(
&backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"Core_execute_block",
@@ -199,7 +199,7 @@ mod tests {
let _ = StateMachine::new(
&backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"Core_execute_block",
@@ -229,7 +229,7 @@ mod tests {
let r = StateMachine::new(
&backend,
Some(&InMemoryChangesTrieStorage::<_, u64>::new()),
NeverOffchainExt::new(),
None,
&mut overlay,
&executor(),
"Core_execute_block",
@@ -23,11 +23,12 @@ use std::{
use codec::{Encode, Decode};
use primitives::{
offchain, H256, Blake2Hasher, convert_hash, NativeOrEncoded,
offchain::OffchainExt, H256, Blake2Hasher, convert_hash, NativeOrEncoded,
traits::CodeExecutor,
};
use sr_primitives::generic::BlockId;
use sr_primitives::traits::{One, Block as BlockT, Header as HeaderT, NumberFor};
use sr_primitives::{
generic::BlockId, traits::{One, Block as BlockT, Header as HeaderT, NumberFor},
};
use state_machine::{
self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend,
execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction,
@@ -74,15 +75,13 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
{
type Error = ClientError;
fn call<
O: offchain::Externalities,
>(
fn call(
&self,
id: &BlockId<Block>,
method: &str,
call_data: &[u8],
strategy: ExecutionStrategy,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
) -> ClientResult<Vec<u8>> {
match self.backend.is_local_state_available(id) {
true => self.local.call(id, method, call_data, strategy, side_effects_handler),
@@ -92,7 +91,6 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
fn contextual_call<
'a,
O: offchain::Externalities,
IB: Fn() -> ClientResult<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -110,7 +108,7 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
initialize_block: InitializeBlock<'a, Block>,
_manager: ExecutionManager<EM>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
side_effects_handler: Option<OffchainExt>,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
enable_keystore: bool,
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
@@ -119,7 +117,6 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
match self.backend.is_local_state_available(at) {
true => CallExecutor::contextual_call::<
_,
_,
fn(
Result<NativeOrEncoded<R>, Local::Error>,
@@ -153,7 +150,6 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
}
fn call_at_state<
O: offchain::Externalities,
S: StateBackend<Blake2Hasher>,
FF: FnOnce(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -168,7 +164,7 @@ impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for
_call_data: &[u8],
_manager: ExecutionManager<FF>,
_native_call: Option<NC>,
_side_effects_handler: Option<&mut O>,
_side_effects_handler: Option<OffchainExt>,
) -> ClientResult<(
NativeOrEncoded<R>,
(S::Transaction, <Blake2Hasher as Hasher>::Out),
@@ -242,11 +238,10 @@ pub fn check_execution_proof<Header, E, H>(
) -> ClientResult<Vec<u8>>
where
Header: HeaderT,
E: CodeExecutor<H>,
H: Hasher,
H::Out: Ord + 'static,
E: CodeExecutor,
H: Hasher<Out=H256>,
{
check_execution_proof_with_make_header(
check_execution_proof_with_make_header::<Header, E, H, _>(
executor,
request,
remote_proof,
@@ -268,9 +263,8 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
) -> ClientResult<Vec<u8>>
where
Header: HeaderT,
E: CodeExecutor<H>,
H: Hasher,
H::Out: Ord + 'static,
E: CodeExecutor,
H: Hasher<Out=H256>,
{
let local_state_root = request.header.state_root();
let root: H::Out = convert_hash(&local_state_root);
@@ -301,33 +295,32 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head
#[cfg(test)]
mod tests {
use super::*;
use consensus::BlockOrigin;
use primitives::offchain::NeverOffchainExt;
use test_client::{self, runtime::{Header, Digest, Block}, ClientExt, TestClient};
use executor::{NativeExecutor, WasmExecutionMethod};
use primitives::Blake2Hasher;
use crate::backend::{Backend, NewBlockState};
use crate::in_mem::Backend as InMemBackend;
use super::*;
struct DummyCallExecutor;
impl CallExecutor<Block, Blake2Hasher> for DummyCallExecutor {
type Error = ClientError;
fn call<O: offchain::Externalities>(
fn call(
&self,
_id: &BlockId<Block>,
_method: &str,
_call_data: &[u8],
_strategy: ExecutionStrategy,
_side_effects_handler: Option<&mut O>,
_side_effects_handler: Option<OffchainExt>,
) -> Result<Vec<u8>, ClientError> {
Ok(vec![42])
}
fn contextual_call<
'a,
O: offchain::Externalities,
IB: Fn() -> ClientResult<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -345,7 +338,7 @@ mod tests {
_initialize_block: InitializeBlock<'a, Block>,
_execution_manager: ExecutionManager<EM>,
_native_call: Option<NC>,
_side_effects_handler: Option<&mut O>,
_side_effects_handler: Option<OffchainExt>,
_proof_recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
_enable_keystore: bool,
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
@@ -357,7 +350,6 @@ mod tests {
}
fn call_at_state<
O: offchain::Externalities,
S: state_machine::Backend<Blake2Hasher>,
F: FnOnce(
Result<NativeOrEncoded<R>, Self::Error>,
@@ -372,7 +364,7 @@ mod tests {
_call_data: &[u8],
_manager: ExecutionManager<F>,
_native_call: Option<NC>,
_side_effects_handler: Option<&mut O>,
_side_effects_handler: Option<OffchainExt>,
) -> Result<
(
NativeOrEncoded<R>,
@@ -417,13 +409,17 @@ mod tests {
).unwrap();
// check remote execution proof locally
let local_result = check_execution_proof(&local_executor(), &RemoteCallRequest {
block: test_client::runtime::Hash::default(),
header: remote_header,
method: method.into(),
call_data: vec![],
retry_count: None,
}, remote_execution_proof).unwrap();
let local_result = check_execution_proof::<_, _, Blake2Hasher>(
&local_executor(),
&RemoteCallRequest {
block: test_client::runtime::Hash::default(),
header: remote_header,
method: method.into(),
call_data: vec![],
retry_count: None,
},
remote_execution_proof,
).unwrap();
(remote_result, local_result)
}
@@ -440,7 +436,7 @@ mod tests {
).unwrap();
// check remote execution proof locally
let execution_result = check_execution_proof_with_make_header(
let execution_result = check_execution_proof_with_make_header::<_, _, Blake2Hasher, _>(
&local_executor(),
&RemoteCallRequest {
block: test_client::runtime::Hash::default(),
@@ -518,7 +514,7 @@ mod tests {
"test_method",
&[],
ExecutionStrategy::NativeElseWasm,
NeverOffchainExt::new(),
None,
).unwrap(),
vec![42],
);
@@ -528,7 +524,7 @@ mod tests {
"test_method",
&[],
ExecutionStrategy::NativeElseWasm,
NeverOffchainExt::new(),
None,
);
match call_on_unavailable {
+3 -4
View File
@@ -23,7 +23,7 @@ use std::future::Future;
use hash_db::{HashDB, Hasher, EMPTY_PREFIX};
use codec::{Decode, Encode};
use primitives::{ChangesTrieConfiguration, convert_hash, traits::CodeExecutor};
use primitives::{ChangesTrieConfiguration, convert_hash, traits::CodeExecutor, H256};
use sr_primitives::traits::{
Block as BlockT, Header as HeaderT, Hash, HashFor, NumberFor,
SimpleArithmetic, CheckedConversion, Zero,
@@ -370,9 +370,8 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> {
impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S>
where
Block: BlockT,
E: CodeExecutor<H>,
H: Hasher,
H::Out: Ord + 'static,
E: CodeExecutor,
H: Hasher<Out=H256>,
S: BlockchainStorage<Block>,
{
fn check_header_proof(
+2 -2
View File
@@ -63,7 +63,7 @@ pub fn new_light<B, S, GS, RA, E>(
B: BlockT<Hash=H256>,
S: BlockchainStorage<B> + 'static,
GS: BuildStorage,
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
E: CodeExecutor + RuntimeInfo,
{
let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, None);
let executor = GenesisCallExecutor::new(backend.clone(), local_executor);
@@ -76,7 +76,7 @@ pub fn new_fetch_checker<E, B: BlockT, S: BlockchainStorage<B>>(
executor: E,
) -> LightDataChecker<E, Blake2Hasher, B, S>
where
E: CodeExecutor<Blake2Hasher>,
E: CodeExecutor,
{
LightDataChecker::new(blockchain, executor)
}
+1
View File
@@ -17,6 +17,7 @@ wasmi = "0.5.1"
parity-wasm = "0.40.3"
lazy_static = "1.4.0"
wasm-interface = { package = "substrate-wasm-interface", path = "../wasm-interface" }
externalities = { package = "substrate-externalities", path = "../externalities" }
parking_lot = "0.9.0"
log = "0.4.8"
libsecp256k1 = "0.3.0"
+2 -2
View File
@@ -45,7 +45,7 @@ pub use native_executor::{with_native_environment, NativeExecutor, NativeExecuti
pub use runtime_version::{RuntimeVersion, NativeVersion};
pub use codec::Codec;
#[doc(hidden)]
pub use primitives::{Blake2Hasher, traits::Externalities};
pub use primitives::traits::Externalities;
#[doc(hidden)]
pub use wasm_interface;
pub use wasm_runtime::WasmExecutionMethod;
@@ -56,7 +56,7 @@ pub trait RuntimeInfo {
fn native_version(&self) -> &NativeVersion;
/// Extract RuntimeVersion of given :code block
fn runtime_version<E: Externalities<Blake2Hasher>> (
fn runtime_version<E: Externalities> (
&self,
ext: &mut E,
) -> Option<RuntimeVersion>;
+10 -12
View File
@@ -20,7 +20,7 @@ use crate::wasm_runtime::{RuntimesCache, WasmExecutionMethod, WasmRuntime};
use crate::RuntimeInfo;
use runtime_version::{NativeVersion, RuntimeVersion};
use codec::{Decode, Encode};
use primitives::{Blake2Hasher, NativeOrEncoded, traits::{CodeExecutor, Externalities}};
use primitives::{NativeOrEncoded, traits::{CodeExecutor, Externalities}};
use log::{trace, warn};
thread_local! {
@@ -41,10 +41,10 @@ fn safe_call<F, U>(f: F) -> Result<U>
/// Set up the externalities and safe calling environment to execute calls to a native runtime.
///
/// If the inner closure panics, it will be caught and return an error.
pub fn with_native_environment<F, U>(ext: &mut dyn Externalities<Blake2Hasher>, f: F) -> Result<U>
pub fn with_native_environment<F, U>(ext: &mut dyn Externalities, f: F) -> Result<U>
where F: UnwindSafe + FnOnce() -> U
{
runtime_io::with_externalities(ext, move || safe_call(f))
externalities::set_and_run_with_externalities(ext, move || safe_call(f))
}
/// Delegate for dispatching a CodeExecutor call.
@@ -54,7 +54,7 @@ pub trait NativeExecutionDispatch: Send + Sync {
/// Dispatch a method in the runtime.
///
/// If the method with the specified name doesn't exist then `Err` is returned.
fn dispatch(ext: &mut dyn Externalities<Blake2Hasher>, method: &str, data: &[u8]) -> Result<Vec<u8>>;
fn dispatch(ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result<Vec<u8>>;
/// Provide native runtime version.
fn native_version() -> NativeVersion;
@@ -95,10 +95,8 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
fn with_runtime<E, R>(
&self,
ext: &mut E,
f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result<R>
) -> Result<R>
where E: Externalities<Blake2Hasher>
{
f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result<R>,
) -> Result<R> where E: Externalities {
RUNTIMES_CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
let runtime = cache.fetch_runtime(ext, self.fallback_method, self.default_heap_pages)?;
@@ -123,7 +121,7 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
&self.native_version
}
fn runtime_version<E: Externalities<Blake2Hasher>>(
fn runtime_version<E: Externalities>(
&self,
ext: &mut E,
) -> Option<RuntimeVersion> {
@@ -137,12 +135,12 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
}
}
impl<D: NativeExecutionDispatch> CodeExecutor<Blake2Hasher> for NativeExecutor<D> {
impl<D: NativeExecutionDispatch> CodeExecutor for NativeExecutor<D> {
type Error = Error;
fn call
<
E: Externalities<Blake2Hasher>,
E: Externalities,
R:Decode + Encode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe
>(
@@ -220,7 +218,7 @@ macro_rules! native_executor_instance {
(IMPL $name:ident, $dispatcher:path, $version:path) => {
impl $crate::NativeExecutionDispatch for $name {
fn dispatch(
ext: &mut $crate::Externalities<$crate::Blake2Hasher>,
ext: &mut $crate::Externalities,
method: &str,
data: &[u8]
) -> $crate::error::Result<Vec<u8>> {
+12 -12
View File
@@ -593,9 +593,9 @@ mod tests {
use wabt;
use runtime_test::WASM_BINARY;
type TestExternalities<H> = CoreTestExternalities<H, u64>;
type TestExternalities = CoreTestExternalities<Blake2Hasher, u64>;
fn call_wasm<E: Externalities<Blake2Hasher>>(
fn call_wasm<E: Externalities>(
ext: &mut E,
heap_pages: u64,
code: &[u8],
@@ -609,7 +609,7 @@ mod tests {
#[test]
fn sandbox_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -641,7 +641,7 @@ mod tests {
#[test]
fn sandbox_trap() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -662,7 +662,7 @@ mod tests {
#[test]
fn sandbox_should_trap_when_heap_exhausted() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -690,7 +690,7 @@ mod tests {
#[test]
fn start_called() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -728,7 +728,7 @@ mod tests {
#[test]
fn invoke_args() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -762,7 +762,7 @@ mod tests {
#[test]
fn return_val() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -784,7 +784,7 @@ mod tests {
#[test]
fn unlinkable_module() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -804,7 +804,7 @@ mod tests {
#[test]
fn corrupted_module() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
// Corrupted wasm file
@@ -818,7 +818,7 @@ mod tests {
#[test]
fn start_fn_ok() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
@@ -841,7 +841,7 @@ mod tests {
#[test]
fn start_fn_traps() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let code = wabt::wat2wasm(r#"
+5 -5
View File
@@ -23,7 +23,7 @@ use crate::error::{Error, WasmError};
use crate::wasmi_execution;
use log::{trace, warn};
use codec::Decode;
use primitives::{storage::well_known_keys, Blake2Hasher, traits::Externalities};
use primitives::{storage::well_known_keys, traits::Externalities};
use runtime_version::RuntimeVersion;
use std::{collections::hash_map::{Entry, HashMap}};
@@ -36,8 +36,8 @@ pub trait WasmRuntime {
fn update_heap_pages(&mut self, heap_pages: u64) -> bool;
/// Call a method in the Substrate runtime by name. Returns the encoded result on success.
fn call(&mut self, ext: &mut dyn Externalities<Blake2Hasher>, method: &str, data: &[u8])
-> Result<Vec<u8>, Error>;
fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8])
-> Result<Vec<u8>, Error>;
/// Returns the version of this runtime.
///
@@ -109,7 +109,7 @@ impl RuntimesCache {
///
/// `Error::InvalidMemoryReference` is returned if no memory export with the
/// identifier `memory` can be found in the runtime.
pub fn fetch_runtime<E: Externalities<Blake2Hasher>>(
pub fn fetch_runtime<E: Externalities>(
&mut self,
ext: &mut E,
wasm_method: WasmExecutionMethod,
@@ -157,7 +157,7 @@ impl RuntimesCache {
}
}
fn create_wasm_runtime<E: Externalities<Blake2Hasher>>(
fn create_wasm_runtime<E: Externalities>(
ext: &mut E,
wasm_method: WasmExecutionMethod,
heap_pages: u64,
+18 -16
View File
@@ -23,7 +23,7 @@ use wasmi::{
};
use crate::error::{Error, WasmError};
use codec::{Encode, Decode};
use primitives::{sandbox as sandbox_primitives, Blake2Hasher, traits::Externalities};
use primitives::{sandbox as sandbox_primitives, traits::Externalities};
use crate::host_interface::SubstrateExternals;
use crate::sandbox;
use crate::allocator;
@@ -342,7 +342,7 @@ fn get_heap_base(module: &ModuleRef) -> Result<u32, Error> {
/// Call a given method in the given wasm-module runtime.
fn call_in_wasm_module(
ext: &mut dyn Externalities<Blake2Hasher>,
ext: &mut dyn Externalities,
module_instance: &ModuleRef,
method: &str,
data: &[u8],
@@ -373,7 +373,7 @@ fn call_in_wasm_module_with_custom_signature<
FR: FnOnce(Option<RuntimeValue>, &MemoryRef) -> Result<Option<R>, Error>,
R,
>(
ext: &mut dyn Externalities<Blake2Hasher>,
ext: &mut dyn Externalities,
module_instance: &ModuleRef,
method: &str,
create_parameters: F,
@@ -398,7 +398,7 @@ fn call_in_wasm_module_with_custom_signature<
fec.write_memory(offset, data).map(|_| offset.into()).map_err(Into::into)
})?;
let result = runtime_io::with_externalities(
let result = externalities::set_and_run_with_externalities(
ext,
|| module_instance.invoke_export(method, &parameters, &mut fec),
);
@@ -588,7 +588,7 @@ impl WasmRuntime for WasmiRuntime {
self.state_snapshot.heap_pages == heap_pages
}
fn call(&mut self, ext: &mut dyn Externalities<Blake2Hasher>, method: &str, data: &[u8])
fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8])
-> Result<Vec<u8>, Error>
{
self.with(|module| {
@@ -601,7 +601,7 @@ impl WasmRuntime for WasmiRuntime {
}
}
pub fn create_instance<E: Externalities<Blake2Hasher>>(ext: &mut E, code: &[u8], heap_pages: u64)
pub fn create_instance<E: Externalities>(ext: &mut E, code: &[u8], heap_pages: u64)
-> Result<WasmiRuntime, WasmError>
{
let module = Module::from_buffer(&code).map_err(|_| WasmError::InvalidModule)?;
@@ -656,14 +656,16 @@ mod tests {
use state_machine::TestExternalities as CoreTestExternalities;
use hex_literal::hex;
use primitives::{blake2_128, blake2_256, ed25519, sr25519, map, Pair};
use primitives::{
Blake2Hasher, blake2_128, blake2_256, ed25519, sr25519, map, Pair, offchain::OffchainExt,
};
use runtime_test::WASM_BINARY;
use substrate_offchain::testing;
use trie::{TrieConfiguration, trie_types::Layout};
type TestExternalities<H> = CoreTestExternalities<H, u64>;
type TestExternalities = CoreTestExternalities<Blake2Hasher, u64>;
fn call<E: Externalities<Blake2Hasher>>(
fn call<E: Externalities>(
ext: &mut E,
heap_pages: u64,
code: &[u8],
@@ -798,7 +800,7 @@ mod tests {
#[test]
fn ed25519_verify_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let key = ed25519::Pair::from_seed(&blake2_256(b"test"));
let sig = key.sign(b"all ok!");
@@ -824,7 +826,7 @@ mod tests {
#[test]
fn sr25519_verify_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let test_code = WASM_BINARY;
let key = sr25519::Pair::from_seed(&blake2_256(b"test"));
let sig = key.sign(b"all ok!");
@@ -850,7 +852,7 @@ mod tests {
#[test]
fn ordered_trie_root_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()];
let test_code = WASM_BINARY;
assert_eq!(
@@ -863,9 +865,9 @@ mod tests {
fn offchain_local_storage_should_work() {
use substrate_client::backend::OffchainStorage;
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let (offchain, state) = testing::TestOffchainExt::new();
ext.set_offchain_externalities(offchain);
ext.register_extension(OffchainExt::new(offchain));
let test_code = WASM_BINARY;
assert_eq!(
call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(),
@@ -876,9 +878,9 @@ mod tests {
#[test]
fn offchain_http_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let mut ext = TestExternalities::default();
let (offchain, state) = testing::TestOffchainExt::new();
ext.set_offchain_externalities(offchain);
ext.register_extension(OffchainExt::new(offchain));
state.write().expect_request(
0,
testing::PendingRequest {
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "substrate-externalities"
version = "2.0.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
primitive-types = { version = "0.5.1", features = ["codec"] }
primitives-storage = { package = "substrate-primitives-storage", path = "../primitives/storage" }
rstd = { package = "sr-std", path = "../sr-std" }
environmental = { version = "1.0.2" }
@@ -0,0 +1,127 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Externalities extensions storage.
//!
//! Externalities support to register a wide variety custom extensions. The [`Extensions`] provides
//! some convenience functionality to store and retrieve these extensions.
//!
//! It is required that each extension implements the [`Extension`] trait.
use std::{collections::HashMap, any::{Any, TypeId}, ops::DerefMut};
/// Marker trait for types that should be registered as [`Externalities`](crate::Externalities) extension.
///
/// As extensions are stored as `Box<Any>`, this trait should give more confidence that the correct
/// type is registered and requested.
pub trait Extension: Sized {}
/// Macro for declaring an extension that usable with [`Extensions`].
///
/// The extension will be an unit wrapper struct that implements [`Extension`], `Deref` and
/// `DerefMut`. The wrapped type is given by the user.
///
/// # Example
/// ```
/// # use substrate_externalities::decl_extension;
/// decl_extension! {
/// /// Some test extension
/// struct TestExt(String);
/// }
/// ```
#[macro_export]
macro_rules! decl_extension {
(
$( #[ $attr:meta ] )*
$vis:vis struct $ext_name:ident ($inner:ty);
) => {
$( #[ $attr ] )*
$vis struct $ext_name (pub $inner);
impl $crate::Extension for $ext_name {}
impl std::ops::Deref for $ext_name {
type Target = $inner;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for $ext_name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
}
/// Something that provides access to the [`Extensions`] store.
///
/// This is a super trait of the [`Externalities`](crate::Externalities).
pub trait ExtensionStore {
/// Tries to find a registered extension by the given `type_id` and returns it as a `&mut dyn Any`.
///
/// It is advised to use [`ExternalitiesExt::extension`](crate::ExternalitiesExt::extension)
/// instead of this function to get type system support and automatic type downcasting.
fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any>;
}
/// Stores extensions that should be made available through the externalities.
#[derive(Default)]
pub struct Extensions {
extensions: HashMap<TypeId, Box<dyn Any>>,
}
impl Extensions {
/// Create new instance of `Self`.
pub fn new() -> Self {
Self::default()
}
/// Register the given extension.
pub fn register<E: Any + Extension>(&mut self, ext: E) {
self.extensions.insert(ext.type_id(), Box::new(ext));
}
/// Return a mutable reference to the requested extension.
pub fn get_mut(&mut self, ext_type_id: TypeId) -> Option<&mut dyn Any> {
self.extensions.get_mut(&ext_type_id).map(DerefMut::deref_mut)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct DummyExt(u32);
impl Extension for DummyExt {}
struct DummyExt2(u32);
impl Extension for DummyExt2 {}
#[test]
fn register_and_retrieve_extension() {
let mut exts = Extensions::new();
exts.register(DummyExt(1));
exts.register(DummyExt2(2));
let ext = exts.get_mut(TypeId::of::<DummyExt>()).expect("Extension is registered");
let ext_ty = ext.downcast_mut::<DummyExt>().expect("Downcasting works");
assert_eq!(ext_ty.0, 1);
}
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Substrate externalities abstraction
//!
//! The externalities mainly provide access to storage and to registered extensions. Extensions
//! are for example the keystore or the offchain externalities. These externalities are used to
//! access the node from the runtime via the runtime interfaces.
//!
//! This crate exposes the main [`Externalities`] trait.
use primitive_types::H256;
use std::any::{Any, TypeId};
use primitives_storage::ChildStorageKey;
pub use scope_limited::{set_and_run_with_externalities, with_externalities};
pub use extensions::{Extension, Extensions, ExtensionStore};
mod extensions;
mod scope_limited;
/// The Substrate externalities.
///
/// Provides access to the storage and to other registered extensions.
pub trait Externalities: ExtensionStore {
/// Read runtime storage.
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Get storage value hash. This may be optimized for large values.
fn storage_hash(&self, key: &[u8]) -> Option<H256>;
/// Get child storage value hash. This may be optimized for large values.
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256>;
/// Read original runtime storage, ignoring any overlayed changes.
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Read original runtime child storage, ignoring any overlayed changes.
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>>;
/// Get original storage value hash, ignoring any overlayed changes.
/// This may be optimized for large values.
fn original_storage_hash(&self, key: &[u8]) -> Option<H256>;
/// Get original child storage value hash, ignoring any overlayed changes.
/// This may be optimized for large values.
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256>;
/// Read child runtime storage.
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>>;
/// Set storage entry `key` of current contract being called (effective immediately).
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.place_storage(key, Some(value));
}
/// Set child storage entry `key` of current contract being called (effective immediately).
fn set_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec<u8>, value: Vec<u8>) {
self.place_child_storage(storage_key, key, Some(value))
}
/// Clear a storage entry (`key`) of current contract being called (effective immediately).
fn clear_storage(&mut self, key: &[u8]) {
self.place_storage(key.to_vec(), None);
}
/// Clear a child storage entry (`key`) of current contract being called (effective immediately).
fn clear_child_storage(&mut self, storage_key: ChildStorageKey, key: &[u8]) {
self.place_child_storage(storage_key, key.to_vec(), None)
}
/// Whether a storage entry exists.
fn exists_storage(&self, key: &[u8]) -> bool {
self.storage(key).is_some()
}
/// Whether a child storage entry exists.
fn exists_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> bool {
self.child_storage(storage_key, key).is_some()
}
/// Clear an entire child storage.
fn kill_child_storage(&mut self, storage_key: ChildStorageKey);
/// Clear storage entries which keys are start with the given prefix.
fn clear_prefix(&mut self, prefix: &[u8]);
/// Clear child storage entries which keys are start with the given prefix.
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]);
/// Set or clear a storage entry (`key`) of current contract being called (effective immediately).
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>);
/// Set or clear a child storage entry. Return whether the operation succeeds.
fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec<u8>, value: Option<Vec<u8>>);
/// Get the identity of the chain.
fn chain_id(&self) -> u64;
/// Get the trie root of the current storage map. This will also update all child storage keys
/// in the top-level storage map.
fn storage_root(&mut self) -> H256;
/// Get the trie root of a child storage map. This will also update the value of the child
/// storage keys in the top-level storage map.
/// If the storage root equals the default hash as defined by the trie, the key in the top-level
/// storage map will be removed.
fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec<u8>;
/// Get the change trie root of the current storage overlay at a block with given parent.
fn storage_changes_root(&mut self, parent: H256) -> Result<Option<H256>, ()>;
}
/// Extension for the [`Externalities`] trait.
pub trait ExternalitiesExt {
/// Tries to find a registered extension and returns a mutable reference.
fn extension<T: Any + Extension>(&mut self) -> Option<&mut T>;
}
impl<T: ExtensionStore + ?Sized> ExternalitiesExt for T {
fn extension<A: Any + Extension>(&mut self) -> Option<&mut A> {
self.extension_by_type_id(TypeId::of::<A>()).and_then(Any::downcast_mut)
}
}
@@ -0,0 +1,37 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Stores the externalities in an `environmental` value to make it scope limited available.
use crate::Externalities;
environmental::environmental!(ext: trait Externalities);
/// Set the given externalities while executing the given closure. To get access to the externalities
/// while executing the given closure [`with_externalities`] grants access to them. The externalities
/// are only set for the same thread this function was called from.
pub fn set_and_run_with_externalities<F, R>(ext: &mut dyn Externalities, f: F) -> R
where F: FnOnce() -> R
{
ext::using(ext, f)
}
/// Execute the given closure with the currently set externalities.
///
/// Returns `None` if no externalities are set or `Some(_)` with the result of the closure.
pub fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> Option<R> {
ext::with(f)
}
@@ -48,7 +48,7 @@ use sr_primitives::{
Justification, generic::BlockId,
traits::{NumberFor, Block as BlockT, Header as HeaderT, One},
};
use primitives::{H256, Blake2Hasher, offchain::NeverOffchainExt};
use primitives::{H256, Blake2Hasher};
use substrate_telemetry::{telemetry, CONSENSUS_INFO};
use fg_primitives::AuthorityId;
@@ -78,7 +78,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> AuthoritySetForFinalityProver<Block> fo
"GrandpaApi_grandpa_authorities",
&[],
ExecutionStrategy::NativeElseWasm,
NeverOffchainExt::new(),
None,
).and_then(|call_result| Decode::decode(&mut &call_result[..])
.map_err(|err| ClientError::CallResultDecode(
"failed to decode GRANDPA authorities set proof".into(), err
+5 -1
View File
@@ -31,6 +31,8 @@ num-traits = { version = "0.2.8", default-features = false }
zeroize = "0.10.1"
lazy_static = { version = "1.4.0", optional = true }
parking_lot = { version = "0.9.0", optional = true }
externalities = { package = "substrate-externalities", path = "../externalities", optional = true }
primitives-storage = { package = "substrate-primitives-storage", path = "storage", default-features = false }
[dev-dependencies]
substrate-serializer = { path = "../serializer" }
@@ -52,7 +54,7 @@ std = [
"log",
"wasmi",
"lazy_static",
"parking_lot",
"parking_lot",
"primitive-types/std",
"primitive-types/serde",
"primitive-types/byteorder",
@@ -79,4 +81,6 @@ std = [
"schnorrkel",
"regex",
"num-traits/std",
"externalities",
"primitives-storage/std",
]
@@ -1,68 +0,0 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Provides a wrapper around a child storage key.
use crate::storage::well_known_keys::is_child_trie_key_valid;
use rstd::{borrow::Cow, vec::Vec};
/// A wrapper around a child storage key.
///
/// This wrapper ensures that the child storage key is correct and properly used. It is
/// impossible to create an instance of this struct without providing a correct `storage_key`.
pub struct ChildStorageKey<'a> {
storage_key: Cow<'a, [u8]>,
}
impl<'a> ChildStorageKey<'a> {
fn new(storage_key: Cow<'a, [u8]>) -> Option<Self> {
if is_child_trie_key_valid(&storage_key) {
Some(ChildStorageKey { storage_key })
} else {
None
}
}
/// Create a new `ChildStorageKey` from a vector.
///
/// `storage_key` need to start with `:child_storage:default:`
/// See `is_child_trie_key_valid` for more details.
pub fn from_vec(key: Vec<u8>) -> Option<Self> {
Self::new(Cow::Owned(key))
}
/// Create a new `ChildStorageKey` from a slice.
///
/// `storage_key` need to start with `:child_storage:default:`
/// See `is_child_trie_key_valid` for more details.
pub fn from_slice(key: &'a [u8]) -> Option<Self> {
Self::new(Cow::Borrowed(key))
}
/// Get access to the byte representation of the storage key.
///
/// This key is guaranteed to be correct.
pub fn as_ref(&self) -> &[u8] {
&*self.storage_key
}
/// Destruct this instance into an owned vector that represents the storage key.
///
/// This key is guaranteed to be correct.
pub fn into_owned(self) -> Vec<u8> {
self.storage_key.into_owned()
}
}
+3 -2
View File
@@ -54,16 +54,15 @@ pub mod crypto;
pub mod u32_trait;
pub mod child_storage_key;
pub mod ed25519;
pub mod sr25519;
pub mod hash;
mod hasher;
pub mod offchain;
pub mod sandbox;
pub mod storage;
pub mod uint;
mod changes_trie;
#[cfg(feature = "std")]
pub mod traits;
pub mod testing;
@@ -81,6 +80,8 @@ pub use hash_db::Hasher;
// pub use self::hasher::blake::BlakeHasher;
pub use self::hasher::blake2::Blake2Hasher;
pub use primitives_storage as storage;
/// Context for executing a call into the runtime.
pub enum ExecutionContext {
/// Context for general importing (including own blocks).
+10 -104
View File
@@ -17,8 +17,7 @@
//! Offchain workers types
use codec::{Encode, Decode};
use rstd::prelude::{Vec, Box};
use rstd::convert::TryFrom;
use rstd::{prelude::{Vec, Box}, convert::TryFrom};
pub use crate::crypto::KeyTypeId;
@@ -663,110 +662,17 @@ impl<T: Externalities> Externalities for LimitedExternalities<T> {
}
}
/// An implementation of offchain extensions that should never be triggered.
pub enum NeverOffchainExt {}
impl NeverOffchainExt {
/// Create new offchain extensions.
pub fn new<'a>() -> Option<&'a mut Self> {
None
}
#[cfg(feature = "std")]
externalities::decl_extension! {
/// The offchain extension that will be registered at the Substrate externalities.
pub struct OffchainExt(Box<dyn Externalities>);
}
impl Externalities for NeverOffchainExt {
fn is_validator(&self) -> bool {
unreachable!()
}
fn submit_transaction(&mut self, _extrinsic: Vec<u8>) -> Result<(), ()> {
unreachable!()
}
fn network_state(
&self,
) -> Result<OpaqueNetworkState, ()> {
unreachable!()
}
fn timestamp(&mut self) -> Timestamp {
unreachable!()
}
fn sleep_until(&mut self, _deadline: Timestamp) {
unreachable!()
}
fn random_seed(&mut self) -> [u8; 32] {
unreachable!()
}
fn local_storage_set(&mut self, _kind: StorageKind, _key: &[u8], _value: &[u8]) {
unreachable!()
}
fn local_storage_compare_and_set(
&mut self,
_kind: StorageKind,
_key: &[u8],
_old_value: Option<&[u8]>,
_new_value: &[u8],
) -> bool {
unreachable!()
}
fn local_storage_get(&mut self, _kind: StorageKind, _key: &[u8]) -> Option<Vec<u8>> {
unreachable!()
}
fn http_request_start(
&mut self,
_method: &str,
_uri: &str,
_meta: &[u8]
) -> Result<HttpRequestId, ()> {
unreachable!()
}
fn http_request_add_header(
&mut self,
_request_id: HttpRequestId,
_name: &str,
_value: &str
) -> Result<(), ()> {
unreachable!()
}
fn http_request_write_body(
&mut self,
_request_id: HttpRequestId,
_chunk: &[u8],
_deadline: Option<Timestamp>
) -> Result<(), HttpError> {
unreachable!()
}
fn http_response_wait(
&mut self,
_ids: &[HttpRequestId],
_deadline: Option<Timestamp>
) -> Vec<HttpRequestStatus> {
unreachable!()
}
fn http_response_headers(
&mut self,
_request_id: HttpRequestId
) -> Vec<(Vec<u8>, Vec<u8>)> {
unreachable!()
}
fn http_response_read_body(
&mut self,
_request_id: HttpRequestId,
_buffer: &mut [u8],
_deadline: Option<Timestamp>
) -> Result<usize, HttpError> {
unreachable!()
#[cfg(feature = "std")]
impl OffchainExt {
/// Create a new instance of `Self`.
pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
Self(Box::new(offchain))
}
}
+3 -4
View File
@@ -18,8 +18,7 @@
#[cfg(feature = "std")]
use crate::{ed25519, sr25519, crypto::{Public, Pair}};
use crate::crypto::KeyTypeId; // No idea why this import had to move from
// the previous line, but now the compiler is happy
use crate::crypto::KeyTypeId;
/// Key type for generic Ed25519 key.
pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
@@ -37,7 +36,7 @@ pub struct KeyStore {
#[cfg(feature = "std")]
impl KeyStore {
/// Creates a new instance of `Self`.
pub fn new() -> std::sync::Arc<parking_lot::RwLock<Self>> {
pub fn new() -> crate::traits::BareCryptoStorePtr {
std::sync::Arc::new(parking_lot::RwLock::new(Self::default()))
}
}
@@ -133,7 +132,7 @@ impl crate::traits::BareCryptoStore for KeyStore {
#[cfg(test)]
mod tests {
use super::*;
use crate::{sr25519, traits::BareCryptoStore};
use crate::sr25519;
use crate::testing::{ED25519, SR25519};
+9 -117
View File
@@ -16,15 +16,13 @@
//! Shareable Substrate traits.
#[cfg(feature = "std")]
use crate::{crypto::KeyTypeId, ed25519, sr25519, child_storage_key::ChildStorageKey};
#[cfg(feature = "std")]
use crate::{crypto::KeyTypeId, ed25519, sr25519};
use std::{fmt::{Debug, Display}, panic::UnwindSafe};
#[cfg(feature = "std")]
use hash_db::Hasher;
pub use externalities::{Externalities, ExternalitiesExt};
/// Something that generates, stores and provides access to keys.
#[cfg(feature = "std")]
pub trait BareCryptoStore: Send + Sync {
/// Returns all sr25519 public keys for the given key type.
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
@@ -70,128 +68,22 @@ pub trait BareCryptoStore: Send + Sync {
}
/// A pointer to the key store.
#[cfg(feature = "std")]
pub type BareCryptoStorePtr = std::sync::Arc<parking_lot::RwLock<dyn BareCryptoStore>>;
/// Externalities: pinned to specific active address.
#[cfg(feature = "std")]
pub trait Externalities<H: Hasher> {
/// Read runtime storage.
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Get storage value hash. This may be optimized for large values.
fn storage_hash(&self, key: &[u8]) -> Option<H::Out> {
self.storage(key).map(|v| H::hash(&v))
}
/// Get child storage value hash. This may be optimized for large values.
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H::Out> {
self.child_storage(storage_key, key).map(|v| H::hash(&v))
}
/// Read original runtime storage, ignoring any overlayed changes.
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Read original runtime child storage, ignoring any overlayed changes.
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>>;
/// Get original storage value hash, ignoring any overlayed changes.
/// This may be optimized for large values.
fn original_storage_hash(&self, key: &[u8]) -> Option<H::Out> {
self.original_storage(key).map(|v| H::hash(&v))
}
/// Get original child storage value hash, ignoring any overlayed changes.
/// This may be optimized for large values.
fn original_child_storage_hash(
&self,
storage_key: ChildStorageKey,
key: &[u8],
) -> Option<H::Out> {
self.original_child_storage(storage_key, key).map(|v| H::hash(&v))
}
/// Read child runtime storage.
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>>;
/// Set storage entry `key` of current contract being called (effective immediately).
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.place_storage(key, Some(value));
}
/// Set child storage entry `key` of current contract being called (effective immediately).
fn set_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec<u8>, value: Vec<u8>) {
self.place_child_storage(storage_key, key, Some(value))
}
/// Clear a storage entry (`key`) of current contract being called (effective immediately).
fn clear_storage(&mut self, key: &[u8]) {
self.place_storage(key.to_vec(), None);
}
/// Clear a child storage entry (`key`) of current contract being called (effective immediately).
fn clear_child_storage(&mut self, storage_key: ChildStorageKey, key: &[u8]) {
self.place_child_storage(storage_key, key.to_vec(), None)
}
/// Whether a storage entry exists.
fn exists_storage(&self, key: &[u8]) -> bool {
self.storage(key).is_some()
}
/// Whether a child storage entry exists.
fn exists_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> bool {
self.child_storage(storage_key, key).is_some()
}
/// Clear an entire child storage.
fn kill_child_storage(&mut self, storage_key: ChildStorageKey);
/// Clear storage entries which keys are start with the given prefix.
fn clear_prefix(&mut self, prefix: &[u8]);
/// Clear child storage entries which keys are start with the given prefix.
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]);
/// Set or clear a storage entry (`key`) of current contract being called (effective immediately).
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>);
/// Set or clear a child storage entry. Return whether the operation succeeds.
fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec<u8>, value: Option<Vec<u8>>);
/// Get the identity of the chain.
fn chain_id(&self) -> u64;
/// Get the trie root of the current storage map. This will also update all child storage keys
/// in the top-level storage map.
fn storage_root(&mut self) -> H::Out where H::Out: Ord;
/// Get the trie root of a child storage map. This will also update the value of the child
/// storage keys in the top-level storage map.
/// If the storage root equals the default hash as defined by the trie, the key in the top-level
/// storage map will be removed.
fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec<u8>;
/// Get the change trie root of the current storage overlay at a block with given parent.
fn storage_changes_root(&mut self, parent: H::Out) -> Result<Option<H::Out>, ()> where H::Out: Ord;
/// Returns offchain externalities extension if present.
fn offchain(&mut self) -> Option<&mut dyn crate::offchain::Externalities>;
/// Returns the keystore.
fn keystore(&self) -> Option<BareCryptoStorePtr>;
externalities::decl_extension! {
/// The keystore extension to register/retrieve from the externalities.
pub struct KeystoreExt(BareCryptoStorePtr);
}
/// Code execution engine.
#[cfg(feature = "std")]
pub trait CodeExecutor<H: Hasher>: Sized + Send + Sync {
pub trait CodeExecutor: Sized + Send + Sync {
/// Externalities error type.
type Error: Display + Debug + Send + 'static;
/// Call a given method in the runtime. Returns a tuple of the result (either the output data
/// or an execution error) together with a `bool`, which is true if native execution was used.
fn call<
E: Externalities<H>,
E: Externalities,
R: codec::Codec + PartialEq,
NC: FnOnce() -> Result<R, String> + UnwindSafe,
>(
@@ -0,0 +1,15 @@
[package]
name = "substrate-primitives-storage"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
description = "Storage related primitives"
[dependencies]
rstd = { package = "sr-std", path = "../../sr-std", default-features = false }
serde = { version = "1.0.101", optional = true, features = ["derive"] }
impl-serde = { version = "0.2.1", optional = true }
[features]
default = [ "std" ]
std = [ "rstd/std", "serde", "impl-serde" ]
@@ -14,23 +14,30 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Contract execution data.
//! Primitive types for storage related stuff.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "std")]
use crate::bytes;
use rstd::vec::Vec;
/// Contract storage key.
use rstd::{vec::Vec, borrow::Cow};
/// Storage key.
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))]
pub struct StorageKey(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
pub struct StorageKey(
#[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))]
pub Vec<u8>,
);
/// Contract storage entry data.
/// Storage data associated to a [`StorageKey`].
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))]
pub struct StorageData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
pub struct StorageData(
#[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))]
pub Vec<u8>,
);
/// Storage change set
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, PartialEq, Eq))]
@@ -39,15 +46,11 @@ pub struct StorageChangeSet<Hash> {
/// Block hash
pub block: Hash,
/// A list of changes
pub changes: Vec<(
StorageKey,
Option<StorageData>,
)>,
pub changes: Vec<(StorageKey, Option<StorageData>)>,
}
/// List of all well known keys and prefixes in storage.
pub mod well_known_keys {
/// Wasm code of the runtime.
///
/// Stored as a raw byte vector. Required by substrate.
@@ -94,3 +97,52 @@ pub mod well_known_keys {
has_right_prefix
}
}
/// A wrapper around a child storage key.
///
/// This wrapper ensures that the child storage key is correct and properly used. It is
/// impossible to create an instance of this struct without providing a correct `storage_key`.
pub struct ChildStorageKey<'a> {
storage_key: Cow<'a, [u8]>,
}
impl<'a> ChildStorageKey<'a> {
/// Create new instance of `Self`.
fn new(storage_key: Cow<'a, [u8]>) -> Option<Self> {
if well_known_keys::is_child_trie_key_valid(&storage_key) {
Some(ChildStorageKey { storage_key })
} else {
None
}
}
/// Create a new `ChildStorageKey` from a vector.
///
/// `storage_key` need to start with `:child_storage:default:`
/// See `is_child_trie_key_valid` for more details.
pub fn from_vec(key: Vec<u8>) -> Option<Self> {
Self::new(Cow::Owned(key))
}
/// Create a new `ChildStorageKey` from a slice.
///
/// `storage_key` need to start with `:child_storage:default:`
/// See `is_child_trie_key_valid` for more details.
pub fn from_slice(key: &'a [u8]) -> Option<Self> {
Self::new(Cow::Borrowed(key))
}
/// Get access to the byte representation of the storage key.
///
/// This key is guaranteed to be correct.
pub fn as_ref(&self) -> &[u8] {
&*self.storage_key
}
/// Destruct this instance into an owned vector that represents the storage key.
///
/// This key is guaranteed to be correct.
pub fn into_owned(self) -> Vec<u8> {
self.storage_key.into_owned()
}
}
+5 -3
View File
@@ -24,8 +24,8 @@ use transaction_pool::{
FullChainApi,
};
use primitives::{
H256, blake2_256, hexdisplay::HexDisplay, traits::BareCryptoStore,
testing::{ED25519, SR25519, KeyStore}, ed25519, crypto::Pair
H256, blake2_256, hexdisplay::HexDisplay, testing::{ED25519, SR25519, KeyStore}, ed25519,
crypto::Pair,
};
use test_client::{
self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys}, DefaultTestClientBuilderExt,
@@ -212,7 +212,9 @@ fn should_insert_key() {
fn should_rotate_keys() {
let runtime = runtime::Runtime::new().unwrap();
let keystore = KeyStore::new();
let client = Arc::new(test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build());
let client = Arc::new(
test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build(),
);
let p = Author {
client: client.clone(),
pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client))),
+6 -4
View File
@@ -33,8 +33,7 @@ use client::{
backend::Backend, error::Result as ClientResult,
};
use primitives::{
H256, Blake2Hasher, Bytes, offchain::NeverOffchainExt,
storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet},
H256, Blake2Hasher, Bytes, storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet},
};
use runtime_version::RuntimeVersion;
use state_machine::ExecutionStrategy;
@@ -240,13 +239,16 @@ impl<B, E, Block, RA> StateBackend<B, E, Block, RA> for FullState<B, E, Block, R
) -> FutureResult<Bytes> {
Box::new(result(
self.block_or_best(block)
.and_then(|block| self.client.executor()
.and_then(|block|
self
.client
.executor()
.call(
&BlockId::Hash(block),
&method,
&*call_data,
ExecutionStrategy::NativeElseWasm,
NeverOffchainExt::new(),
None,
)
.map(Into::into))
.map_err(client_err)))
+2 -2
View File
@@ -15,9 +15,9 @@ codec = { package = "parity-scale-codec", version = "1.0.0", default-features =
hash-db = { version = "0.15.2", default-features = false }
libsecp256k1 = { version = "0.3.0", optional = true }
tiny-keccak = { version = "1.5.0", optional = true }
environmental = { version = "1.0.2", 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 }
[features]
default = ["std"]
@@ -27,10 +27,10 @@ std = [
"rstd/std",
"hash-db/std",
"trie",
"environmental",
"substrate-state-machine",
"libsecp256k1",
"tiny-keccak",
"externalities",
]
nightly = []
strict = []
+2 -5
View File
@@ -368,13 +368,10 @@ mod imp {
}
#[cfg(feature = "std")]
pub use self::imp::{
StorageOverlay, ChildrenStorageOverlay, with_storage,
with_externalities
};
pub use self::imp::{StorageOverlay, ChildrenStorageOverlay, with_storage};
#[cfg(not(feature = "std"))]
pub use self::imp::ext::*;
/// Type alias for Externalities implementation used in tests.
#[cfg(feature = "std")]
pub type TestExternalities<H> = self::imp::TestExternalities<H, u64>;
pub type TestExternalities = self::imp::TestExternalities<primitives::Blake2Hasher, u64>;
+40 -50
View File
@@ -16,19 +16,18 @@
use primitives::{
blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher, sr25519, Pair, H256,
traits::Externalities, child_storage_key::ChildStorageKey, hexdisplay::HexDisplay, offchain,
Hasher,
traits::KeystoreExt, storage::ChildStorageKey, hexdisplay::HexDisplay, Hasher,
offchain::{self, OffchainExt},
};
// Switch to this after PoC-3
// pub use primitives::BlakeHasher;
pub use substrate_state_machine::{BasicExternalities, TestExternalities};
use environmental::environmental;
use trie::{TrieConfiguration, trie_types::Layout};
use std::{collections::HashMap, convert::TryFrom};
environmental!(ext: trait Externalities<Blake2Hasher>);
use externalities::{with_externalities, set_and_run_with_externalities, ExternalitiesExt};
/// Additional bounds for `Hasher` trait for with_std.
pub trait HasherBounds {}
@@ -48,12 +47,12 @@ fn child_storage_key_or_panic(storage_key: &[u8]) -> ChildStorageKey {
impl StorageApi for () {
fn storage(key: &[u8]) -> Option<Vec<u8>> {
ext::with(|ext| ext.storage(key).map(|s| s.to_vec()))
with_externalities(|ext| ext.storage(key).map(|s| s.to_vec()))
.expect("storage cannot be called outside of an Externalities-provided environment.")
}
fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option<usize> {
ext::with(|ext| ext.storage(key).map(|value| {
with_externalities(|ext| ext.storage(key).map(|value| {
let data = &value[value_offset.min(value.len())..];
let written = std::cmp::min(data.len(), value_out.len());
value_out[..written].copy_from_slice(&data[..written]);
@@ -62,7 +61,7 @@ impl StorageApi for () {
}
fn child_storage(storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.child_storage(storage_key, key).map(|s| s.to_vec())
})
@@ -70,7 +69,7 @@ impl StorageApi for () {
}
fn set_storage(key: &[u8], value: &[u8]) {
ext::with(|ext|
with_externalities(|ext|
ext.set_storage(key.to_vec(), value.to_vec())
);
}
@@ -81,7 +80,7 @@ impl StorageApi for () {
value_out: &mut [u8],
value_offset: usize,
) -> Option<usize> {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.child_storage(storage_key, key)
.map(|value| {
@@ -95,73 +94,71 @@ impl StorageApi for () {
}
fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.set_child_storage(storage_key, key.to_vec(), value.to_vec())
});
}
fn clear_storage(key: &[u8]) {
ext::with(|ext|
with_externalities(|ext|
ext.clear_storage(key)
);
}
fn clear_child_storage(storage_key: &[u8], key: &[u8]) {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.clear_child_storage(storage_key, key)
});
}
fn kill_child_storage(storage_key: &[u8]) {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.kill_child_storage(storage_key)
});
}
fn exists_storage(key: &[u8]) -> bool {
ext::with(|ext|
with_externalities(|ext|
ext.exists_storage(key)
).unwrap_or(false)
}
fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.exists_child_storage(storage_key, key)
}).unwrap_or(false)
}
fn clear_prefix(prefix: &[u8]) {
ext::with(|ext|
ext.clear_prefix(prefix)
);
with_externalities(|ext| ext.clear_prefix(prefix));
}
fn clear_child_prefix(storage_key: &[u8], prefix: &[u8]) {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.clear_child_prefix(storage_key, prefix)
});
}
fn storage_root() -> [u8; 32] {
ext::with(|ext|
with_externalities(|ext|
ext.storage_root()
).unwrap_or(H256::zero()).into()
}
fn child_storage_root(storage_key: &[u8]) -> Vec<u8> {
ext::with(|ext| {
with_externalities(|ext| {
let storage_key = child_storage_key_or_panic(storage_key);
ext.child_storage_root(storage_key)
}).expect("child_storage_root cannot be called outside of an Externalities-provided environment.")
}
fn storage_changes_root(parent_hash: [u8; 32]) -> Option<[u8; 32]> {
ext::with(|ext|
with_externalities(|ext|
ext.storage_changes_root(parent_hash.into()).map(|h| h.map(|h| h.into()))
).unwrap_or(Ok(None)).expect("Invalid parent hash passed to storage_changes_root")
}
@@ -177,7 +174,7 @@ impl StorageApi for () {
impl OtherApi for () {
fn chain_id() -> u64 {
ext::with(|ext|
with_externalities(|ext|
ext.chain_id()
).unwrap_or(0)
}
@@ -199,8 +196,8 @@ impl OtherApi for () {
impl CryptoApi for () {
fn ed25519_public_keys(id: KeyTypeId) -> Vec<ed25519::Public> {
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.read()
.ed25519_public_keys(id)
@@ -208,8 +205,8 @@ impl CryptoApi for () {
}
fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public {
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.write()
.ed25519_generate_new(id, seed)
@@ -224,8 +221,8 @@ impl CryptoApi for () {
) -> Option<ed25519::Signature> {
let pub_key = ed25519::Public::try_from(pubkey.as_ref()).ok()?;
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.read()
.ed25519_key_pair(id, &pub_key)
@@ -238,8 +235,8 @@ impl CryptoApi for () {
}
fn sr25519_public_keys(id: KeyTypeId) -> Vec<sr25519::Public> {
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.read()
.sr25519_public_keys(id)
@@ -247,8 +244,8 @@ impl CryptoApi for () {
}
fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public {
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.write()
.sr25519_generate_new(id, seed)
@@ -263,8 +260,8 @@ impl CryptoApi for () {
) -> Option<sr25519::Signature> {
let pub_key = sr25519::Public::try_from(pubkey.as_ref()).ok()?;
ext::with(|ext| {
ext.keystore()
with_externalities(|ext| {
ext.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!")
.read()
.sr25519_key_pair(id, &pub_key)
@@ -316,9 +313,9 @@ impl HashingApi for () {
}
fn with_offchain<R>(f: impl FnOnce(&mut dyn offchain::Externalities) -> R, msg: &'static str) -> R {
ext::with(|ext| ext
.offchain()
.map(|ext| f(ext))
with_externalities(|ext| ext
.extension::<OffchainExt>()
.map(|ext| f(&mut **ext))
.expect(msg)
).expect("offchain-worker functions cannot be called outside of an Externalities-provided environment.")
}
@@ -443,13 +440,6 @@ impl OffchainApi for () {
impl Api for () {}
/// Execute the given closure with global function available whose functionality routes into the
/// externalities `ext`. Forwards the value that the closure returns.
// NOTE: need a concrete hasher here due to limitations of the `environmental!` macro, otherwise a type param would have been fine I think.
pub fn with_externalities<R, F: FnOnce() -> R>(ext: &mut dyn Externalities<Blake2Hasher>, f: F) -> R {
ext::using(ext, f)
}
/// A set of key value pairs for storage.
pub type StorageOverlay = HashMap<Vec<u8>, Vec<u8>>;
@@ -467,7 +457,7 @@ pub fn with_storage<R, F: FnOnce() -> R>(
rstd::mem::swap(&mut alt_storage, storage);
let mut ext = BasicExternalities::new(alt_storage.0, alt_storage.1);
let r = ext::using(&mut ext, f);
let r = set_and_run_with_externalities(&mut ext, f);
*storage = ext.into_storages();
@@ -482,7 +472,7 @@ mod std_tests {
#[test]
fn storage_works() {
let mut t = BasicExternalities::default();
assert!(with_externalities(&mut t, || {
assert!(set_and_run_with_externalities(&mut t, || {
assert_eq!(storage(b"hello"), None);
set_storage(b"hello", b"world");
assert_eq!(storage(b"hello"), Some(b"world".to_vec()));
@@ -493,7 +483,7 @@ mod std_tests {
t = BasicExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()], map![]);
assert!(!with_externalities(&mut t, || {
assert!(!set_and_run_with_externalities(&mut t, || {
assert_eq!(storage(b"hello"), None);
assert_eq!(storage(b"foo"), Some(b"bar".to_vec()));
false
@@ -506,7 +496,7 @@ mod std_tests {
b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec()
], map![]);
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
let mut v = [0u8; 4];
assert!(read_storage(b":test", &mut v[..], 0).unwrap() >= 4);
assert_eq!(v, [11u8, 0, 0, 0]);
@@ -525,7 +515,7 @@ mod std_tests {
b":abdd".to_vec() => b"\x0b\0\0\0Hello world".to_vec()
], map![]);
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
clear_prefix(b":abc");
assert!(storage(b":a").is_some());
+2
View File
@@ -16,6 +16,7 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
log = { version = "0.4.8", optional = true }
paste = "0.1.6"
rand = { version = "0.7.2", optional = true }
externalities = { package = "substrate-externalities", path = "../externalities", optional = true }
impl-trait-for-tuples = "0.1.2"
[dev-dependencies]
@@ -36,4 +37,5 @@ std = [
"primitives/std",
"app-crypto/std",
"rand",
"externalities",
]
+3
View File
@@ -67,6 +67,9 @@ pub use sr_arithmetic::{
/// Re-export 128 bit helpers from sr_arithmetic
pub use sr_arithmetic::helpers_128bit;
#[cfg(feature = "std")]
pub use externalities::set_and_run_with_externalities;
/// An abstraction over justification for a block's validity under a consensus algorithm.
///
/// Essentially a finality proof. The exact formulation will vary between consensus
@@ -512,16 +512,18 @@ impl<'a> HeadersIterator<'a> {
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{TestExternalities, with_externalities};
use crate::set_and_run_with_externalities;
use runtime_io::TestExternalities;
use substrate_offchain::testing;
use primitives::offchain::OffchainExt;
#[test]
fn should_send_a_basic_request_and_get_response() {
let (offchain, state) = testing::TestOffchainExt::new();
let mut t = TestExternalities::default();
t.set_offchain_externalities(offchain);
t.register_extension(OffchainExt::new(offchain));
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
let request: Request = Request::get("http://localhost:1234");
let pending = request
.add_header("X-Auth", "hunter2")
@@ -560,9 +562,9 @@ mod tests {
fn should_send_a_post_request() {
let (offchain, state) = testing::TestOffchainExt::new();
let mut t = TestExternalities::default();
t.set_offchain_externalities(offchain);
t.register_extension(OffchainExt::new(offchain));
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
let pending = Request::default()
.method(Method::Post)
.url("http://localhost:1234")
+1
View File
@@ -17,6 +17,7 @@ panic-handler = { package = "substrate-panic-handler", path = "../panic-handler"
codec = { package = "parity-scale-codec", version = "1.0.0" }
num-traits = "0.2.8"
rand = "0.7.2"
externalities = { package = "substrate-externalities", path = "../externalities" }
[dev-dependencies]
hex-literal = "0.2.1"
+34 -27
View File
@@ -16,15 +16,14 @@
//! Basic implementation for Externalities.
use std::collections::HashMap;
use std::iter::FromIterator;
use std::{collections::HashMap, any::{TypeId, Any}, iter::FromIterator};
use crate::backend::{Backend, InMemory};
use hash_db::Hasher;
use trie::{TrieConfiguration, default_child_trie_root};
use trie::trie_types::Layout;
use primitives::{
storage::well_known_keys::is_child_storage_key, child_storage_key::ChildStorageKey, offchain,
traits::Externalities,
storage::{well_known_keys::is_child_storage_key, ChildStorageKey},
traits::Externalities, Blake2Hasher, hash::H256,
};
use log::warn;
@@ -88,21 +87,37 @@ impl From<HashMap<Vec<u8>, Vec<u8>>> for BasicExternalities {
}
}
impl<H: Hasher> Externalities<H> for BasicExternalities where H::Out: Ord {
impl Externalities for BasicExternalities {
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.top.get(key).cloned()
}
fn storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage(key).map(|v| Blake2Hasher::hash(&v))
}
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
Externalities::<H>::storage(self, key)
self.storage(key)
}
fn original_storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage_hash(key)
}
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
self.children.get(storage_key.as_ref()).and_then(|child| child.get(key)).cloned()
}
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage(storage_key, key).map(|v| Blake2Hasher::hash(&v))
}
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage_hash(storage_key, key)
}
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
Externalities::<H>::child_storage(self, storage_key, key)
Externalities::child_storage(self, storage_key, key)
}
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
@@ -155,16 +170,15 @@ impl<H: Hasher> Externalities<H> for BasicExternalities where H::Out: Ord {
fn chain_id(&self) -> u64 { 42 }
fn storage_root(&mut self) -> H::Out {
fn storage_root(&mut self) -> H256 {
let mut top = self.top.clone();
let keys: Vec<_> = self.children.keys().map(|k| k.to_vec()).collect();
// Single child trie implementation currently allows using the same child
// empty root for all child trie. Using null storage key until multiple
// type of child trie support.
let empty_hash = default_child_trie_root::<Layout<H>>(&[]);
let empty_hash = default_child_trie_root::<Layout<Blake2Hasher>>(&[]);
for storage_key in keys {
let child_root = Externalities::<H>::child_storage_root(
self,
let child_root = self.child_storage_root(
ChildStorageKey::from_slice(storage_key.as_slice())
.expect("Map only feed by valid keys; qed"),
);
@@ -175,30 +189,27 @@ impl<H: Hasher> Externalities<H> for BasicExternalities where H::Out: Ord {
}
}
Layout::<H>::trie_root(self.top.clone())
Layout::<Blake2Hasher>::trie_root(self.top.clone())
}
fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec<u8> {
if let Some(child) = self.children.get(storage_key.as_ref()) {
let delta = child.clone().into_iter().map(|(k, v)| (k, Some(v)));
InMemory::<H>::default().child_storage_root(storage_key.as_ref(), delta).0
InMemory::<Blake2Hasher>::default().child_storage_root(storage_key.as_ref(), delta).0
} else {
default_child_trie_root::<Layout<H>>(storage_key.as_ref())
default_child_trie_root::<Layout<Blake2Hasher>>(storage_key.as_ref())
}
}
fn storage_changes_root(&mut self, _parent: H::Out) -> Result<Option<H::Out>, ()> {
fn storage_changes_root(&mut self, _parent: H256) -> Result<Option<H256>, ()> {
Ok(None)
}
}
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> {
warn!("Call to non-existent offchain externalities set.");
None
}
fn keystore(&self) -> Option<primitives::traits::BareCryptoStorePtr> {
warn!("Call to non-existent keystore.");
impl externalities::ExtensionStore for BasicExternalities {
fn extension_by_type_id(&mut self, _: TypeId) -> Option<&mut dyn Any> {
warn!("Extensions are not supported by `BasicExternalities`.");
None
}
}
@@ -206,14 +217,13 @@ impl<H: Hasher> Externalities<H> for BasicExternalities where H::Out: Ord {
#[cfg(test)]
mod tests {
use super::*;
use primitives::{Blake2Hasher, H256, map};
use primitives::{H256, map};
use primitives::storage::well_known_keys::CODE;
use hex_literal::hex;
#[test]
fn commit_should_work() {
let mut ext = BasicExternalities::default();
let ext = &mut ext as &mut dyn Externalities<Blake2Hasher>;
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
@@ -225,7 +235,6 @@ mod tests {
#[test]
fn set_and_retrieve_code() {
let mut ext = BasicExternalities::default();
let ext = &mut ext as &mut dyn Externalities<Blake2Hasher>;
let code = vec![1, 2, 3];
ext.set_storage(CODE.to_vec(), code.clone());
@@ -246,8 +255,6 @@ mod tests {
]
);
let ext = &mut ext as &mut dyn Externalities<Blake2Hasher>;
let child = || ChildStorageKey::from_vec(child_storage.clone()).unwrap();
assert_eq!(ext.child_storage(child(), b"doe"), Some(b"reindeer".to_vec()));
+98 -71
View File
@@ -16,22 +16,24 @@
//! Concrete externalities implementation.
use std::{error, fmt, cmp::Ord};
use log::{warn, trace};
use crate::{
backend::Backend, OverlayedChanges,
changes_trie::{
Storage as ChangesTrieStorage, CacheAction as ChangesTrieCacheAction, build_changes_trie,
},
};
use hash_db::Hasher;
use primitives::{
offchain, storage::well_known_keys::is_child_storage_key,
traits::{BareCryptoStorePtr, Externalities}, child_storage_key::ChildStorageKey,
hexdisplay::HexDisplay,
storage::{ChildStorageKey, well_known_keys::is_child_storage_key},
traits::Externalities, hexdisplay::HexDisplay, hash::H256,
};
use trie::{MemoryDB, default_child_trie_root};
use trie::trie_types::Layout;
use trie::{trie_types::Layout, MemoryDB, default_child_trie_root};
use externalities::Extensions;
use std::{error, fmt, any::{Any, TypeId}};
use log::{warn, trace};
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
@@ -65,11 +67,7 @@ impl<B: error::Error, E: error::Error> error::Error for Error<B, E> {
}
/// Wraps a read-only backend, call executor, and current overlayed changes.
pub struct Ext<'a, H, N, B, T, O>
where
H: Hasher,
B: 'a + Backend<H>,
{
pub struct Ext<'a, H, N, B, T> where H: Hasher<Out=H256>, B: 'a + Backend<H> {
/// The overlayed changes to write to.
overlay: &'a mut OverlayedChanges,
/// The storage backend to read from.
@@ -86,25 +84,19 @@ where
/// `storage_changes_root` is called matters + we need to remember additional
/// data at this moment (block number).
changes_trie_transaction: Option<(MemoryDB<H>, H::Out, ChangesTrieCacheAction<H::Out, N>)>,
/// Additional externalities for offchain workers.
///
/// If None, some methods from the trait might not be supported.
offchain_externalities: Option<&'a mut O>,
/// The keystore that manages the keys of the node.
keystore: Option<BareCryptoStorePtr>,
/// Pseudo-unique id used for tracing.
pub id: u16,
/// Dummy usage of N arg.
_phantom: ::std::marker::PhantomData<N>,
_phantom: std::marker::PhantomData<N>,
/// Extensions registered with this instance.
extensions: Option<&'a mut Extensions>,
}
impl<'a, H, N, B, T, O> Ext<'a, H, N, B, T, O>
impl<'a, H, N, B, T> Ext<'a, H, N, B, T>
where
H: Hasher,
H: Hasher<Out=H256>,
B: 'a + Backend<H>,
T: 'a + ChangesTrieStorage<H, N>,
O: 'a + offchain::Externalities,
H::Out: Ord + 'static,
N: crate::changes_trie::BlockNumber,
{
/// Create a new `Ext` from overlayed changes and read-only backend
@@ -112,8 +104,7 @@ where
overlay: &'a mut OverlayedChanges,
backend: &'a B,
changes_trie_storage: Option<&'a T>,
offchain_externalities: Option<&'a mut O>,
keystore: Option<BareCryptoStorePtr>,
extensions: Option<&'a mut Extensions>,
) -> Self {
Ext {
overlay,
@@ -121,21 +112,25 @@ where
storage_transaction: None,
changes_trie_storage,
changes_trie_transaction: None,
offchain_externalities,
keystore,
id: rand::random(),
_phantom: Default::default(),
extensions,
}
}
/// Get the transaction necessary to update the backend.
pub fn transaction(mut self) -> ((B::Transaction, H::Out), Option<crate::ChangesTrieTransaction<H, N>>) {
pub fn transaction(&mut self) -> (
(B::Transaction, H256),
Option<crate::ChangesTrieTransaction<H, N>>,
) {
let _ = self.storage_root();
let (storage_transaction, changes_trie_transaction) = (
self.storage_transaction
.take()
.expect("storage_transaction always set after calling storage root; qed"),
self.changes_trie_transaction
.take()
.map(|(tx, _, cache)| (tx, cache)),
);
@@ -151,16 +146,14 @@ where
fn mark_dirty(&mut self) {
self.storage_transaction = None;
}
}
#[cfg(test)]
impl<'a, H, N, B, T, O> Ext<'a, H, N, B, T, O>
impl<'a, H, N, B, T> Ext<'a, H, N, B, T>
where
H: Hasher,
H: Hasher<Out=H256>,
B: 'a + Backend<H>,
T: 'a + ChangesTrieStorage<H, N>,
O: 'a + offchain::Externalities,
N: crate::changes_trie::BlockNumber,
{
pub fn storage_pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
@@ -177,13 +170,12 @@ where
}
}
impl<'a, B, T, H, N, O> Externalities<H> for Ext<'a, H, N, B, T, O>
where H: Hasher,
impl<'a, H, B, T, N> Externalities for Ext<'a, H, N, B, T>
where
H: Hasher<Out=H256>,
B: 'a + Backend<H>,
T: 'a + ChangesTrieStorage<H, N>,
H::Out: Ord + 'static,
N: crate::changes_trie::BlockNumber,
O: 'a + offchain::Externalities,
{
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
let _guard = panic_handler::AbortGuard::force_abort();
@@ -197,10 +189,14 @@ where H: Hasher,
result
}
fn storage_hash(&self, key: &[u8]) -> Option<H::Out> {
fn storage_hash(&self, key: &[u8]) -> Option<H256> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.overlay.storage(key).map(|x| x.map(|x| H::hash(x))).unwrap_or_else(||
self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
let result = self.overlay
.storage(key)
.map(|x| x.map(|x| H::hash(x)))
.unwrap_or_else(||
self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL)
);
trace!(target: "state-trace", "{:04x}: Hash {}={:?}",
self.id,
HexDisplay::from(&key),
@@ -220,7 +216,7 @@ where H: Hasher,
result
}
fn original_storage_hash(&self, key: &[u8]) -> Option<H::Out> {
fn original_storage_hash(&self, key: &[u8]) -> Option<H256> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
trace!(target: "state-trace", "{:04x}: GetOriginalHash {}={:?}",
@@ -233,33 +229,48 @@ where H: Hasher,
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.overlay.child_storage(storage_key.as_ref(), key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL));
let result = self.overlay
.child_storage(storage_key.as_ref(), key)
.map(|x| x.map(|x| x.to_vec()))
.unwrap_or_else(||
self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL)
);
trace!(target: "state-trace", "{:04x}: GetChild({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
HexDisplay::from(&key),
result.as_ref().map(HexDisplay::from)
);
result
}
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H::Out> {
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.overlay.child_storage(storage_key.as_ref(), key).map(|x| x.map(|x| H::hash(x))).unwrap_or_else(||
self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
let result = self.overlay
.child_storage(storage_key.as_ref(), key)
.map(|x| x.map(|x| H::hash(x)))
.unwrap_or_else(||
self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL)
);
trace!(target: "state-trace", "{:04x}: ChildHash({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
HexDisplay::from(&key),
result,
);
result
}
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL);
let result = self.backend
.child_storage(storage_key.as_ref(), key)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
trace!(target: "state-trace", "{:04x}: ChildOriginal({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
@@ -269,9 +280,12 @@ where H: Hasher,
result
}
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H::Out> {
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
let _guard = panic_handler::AbortGuard::force_abort();
let result = self.backend.child_storage_hash(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL);
let result = self.backend
.child_storage_hash(storage_key.as_ref(), key)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
trace!(target: "state-trace", "{}: ChildHashOriginal({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
@@ -287,6 +301,7 @@ where H: Hasher,
Some(x) => x.is_some(),
_ => self.backend.exists_storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL),
};
trace!(target: "state-trace", "{:04x}: Exists {}={:?}",
self.id,
HexDisplay::from(&key),
@@ -301,8 +316,11 @@ where H: Hasher,
let result = match self.overlay.child_storage(storage_key.as_ref(), key) {
Some(x) => x.is_some(),
_ => self.backend.exists_child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL),
_ => self.backend
.exists_child_storage(storage_key.as_ref(), key)
.expect(EXT_NOT_ALLOWED_TO_FAIL),
};
trace!(target: "state-trace", "{:04x}: ChildExists({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
@@ -328,7 +346,12 @@ where H: Hasher,
self.overlay.set_storage(key, value);
}
fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec<u8>, value: Option<Vec<u8>>) {
fn place_child_storage(
&mut self,
storage_key: ChildStorageKey,
key: Vec<u8>,
value: Option<Vec<u8>>,
) {
trace!(target: "state-trace", "{:04x}: PutChild({}) {}={:?}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
@@ -392,7 +415,7 @@ where H: Hasher,
42
}
fn storage_root(&mut self) -> H::Out {
fn storage_root(&mut self) -> H256 {
let _guard = panic_handler::AbortGuard::force_abort();
if let Some((_, ref root)) = self.storage_transaction {
trace!(target: "state-trace", "{:04x}: Root (cached) {}",
@@ -465,7 +488,7 @@ where H: Hasher,
}
}
fn storage_changes_root(&mut self, parent_hash: H::Out) -> Result<Option<H::Out>, ()> {
fn storage_changes_root(&mut self, parent_hash: H256) -> Result<Option<H256>, ()> {
let _guard = panic_handler::AbortGuard::force_abort();
self.changes_trie_transaction = build_changes_trie::<_, T, H, N>(
self.backend,
@@ -481,32 +504,36 @@ where H: Hasher,
);
result
}
}
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> {
self.offchain_externalities.as_mut().map(|x| &mut **x as _)
impl<'a, H, B, T, N> externalities::ExtensionStore for Ext<'a, H, N, B, T>
where
H: Hasher<Out=H256>,
B: 'a + Backend<H>,
T: 'a + ChangesTrieStorage<H, N>,
N: crate::changes_trie::BlockNumber,
{
fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
self.extensions.as_mut().and_then(|exts| exts.get_mut(type_id))
}
fn keystore(&self) -> Option<BareCryptoStorePtr> {
self.keystore.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
use codec::Encode;
use primitives::{Blake2Hasher};
use primitives::storage::well_known_keys::EXTRINSIC_INDEX;
use crate::backend::InMemory;
use crate::changes_trie::{Configuration as ChangesTrieConfiguration,
InMemoryStorage as InMemoryChangesTrieStorage};
use crate::overlayed_changes::OverlayedValue;
use super::*;
use primitives::{Blake2Hasher, storage::well_known_keys::EXTRINSIC_INDEX};
use crate::{
changes_trie::{
Configuration as ChangesTrieConfiguration,
InMemoryStorage as InMemoryChangesTrieStorage,
}, backend::InMemory, overlayed_changes::OverlayedValue,
};
type TestBackend = InMemory<Blake2Hasher>;
type TestChangesTrieStorage = InMemoryChangesTrieStorage<Blake2Hasher, u64>;
type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend, TestChangesTrieStorage, crate::NeverOffchainExt>;
type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend, TestChangesTrieStorage>;
fn prepare_overlay_with_changes() -> OverlayedChanges {
OverlayedChanges {
@@ -532,7 +559,7 @@ mod tests {
fn storage_changes_root_is_none_when_storage_is_not_provided() {
let mut overlay = prepare_overlay_with_changes();
let backend = TestBackend::default();
let mut ext = TestExt::new(&mut overlay, &backend, None, None, None);
let mut ext = TestExt::new(&mut overlay, &backend, None, None);
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None);
}
@@ -542,7 +569,7 @@ mod tests {
overlay.changes_trie_config = None;
let storage = TestChangesTrieStorage::with_blocks(vec![(100, Default::default())]);
let backend = TestBackend::default();
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None);
}
@@ -551,7 +578,7 @@ mod tests {
let mut overlay = prepare_overlay_with_changes();
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
let backend = TestBackend::default();
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
assert_eq!(
ext.storage_changes_root(Default::default()).unwrap(),
Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into()),
@@ -564,7 +591,7 @@ mod tests {
overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None;
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
let backend = TestBackend::default();
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
assert_eq!(
ext.storage_changes_root(Default::default()).unwrap(),
Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into()),
+100 -84
View File
@@ -18,18 +18,16 @@
#![warn(missing_docs)]
use std::{
fmt, result, collections::HashMap,
marker::PhantomData, panic::UnwindSafe,
};
use std::{fmt, result, collections::HashMap, panic::UnwindSafe, marker::PhantomData};
use log::{warn, trace};
use hash_db::Hasher;
use codec::{Decode, Encode};
use primitives::{
storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain::{self, NeverOffchainExt},
traits::{BareCryptoStorePtr, CodeExecutor},
hexdisplay::HexDisplay,
storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain::OffchainExt,
traits::{KeystoreExt, CodeExecutor}, hexdisplay::HexDisplay, hash::H256,
};
use overlayed_changes::OverlayedChangeSet;
use externalities::Extensions;
pub mod backend;
mod changes_trie;
@@ -42,9 +40,7 @@ mod proving_backend;
mod trie_backend;
mod trie_backend_essence;
use overlayed_changes::OverlayedChangeSet;
pub use trie::{TrieMut, DBValue, MemoryDB};
pub use trie::trie_types::{Layout, TrieDBMut};
pub use trie::{trie_types::{Layout, TrieDBMut}, TrieMut, DBValue, MemoryDB};
pub use testing::TestExternalities;
pub use basic::BasicExternalities;
pub use ext::Ext;
@@ -167,48 +163,54 @@ fn always_untrusted_wasm<E, R: Decode>() -> ExecutionManager<DefaultHandler<R, E
}
/// The substrate state machine.
pub struct StateMachine<'a, B, H, N, T, O, Exec> {
backend: B,
changes_trie_storage: Option<&'a T>,
offchain_ext: Option<&'a mut O>,
overlay: &'a mut OverlayedChanges,
pub struct StateMachine<'a, B, H, N, T, Exec> where H: Hasher<Out=H256>, B: Backend<H> {
backend: &'a B,
exec: &'a Exec,
method: &'a str,
call_data: &'a [u8],
keystore: Option<BareCryptoStorePtr>,
_hasher: PhantomData<(H, N)>,
overlay: &'a mut OverlayedChanges,
extensions: Extensions,
changes_trie_storage: Option<&'a T>,
_marker: PhantomData<(H, N)>,
}
impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
H: Hasher,
Exec: CodeExecutor<H>,
impl<'a, B, H, N, T, Exec> StateMachine<'a, B, H, N, T, Exec> where
H: Hasher<Out=H256>,
Exec: CodeExecutor,
B: Backend<H>,
T: ChangesTrieStorage<H, N>,
O: offchain::Externalities,
H::Out: Ord + 'static,
N: crate::changes_trie::BlockNumber,
{
/// Creates new substrate state machine.
pub fn new(
backend: B,
backend: &'a B,
changes_trie_storage: Option<&'a T>,
offchain_ext: Option<&'a mut O>,
offchain_ext: Option<OffchainExt>,
overlay: &'a mut OverlayedChanges,
exec: &'a Exec,
method: &'a str,
call_data: &'a [u8],
keystore: Option<BareCryptoStorePtr>,
keystore: Option<KeystoreExt>,
) -> Self {
let mut extensions = Extensions::new();
if let Some(keystore) = keystore {
extensions.register(keystore);
}
if let Some(offchain) = offchain_ext {
extensions.register(offchain);
}
Self {
backend,
changes_trie_storage,
offchain_ext,
overlay,
exec,
method,
call_data,
keystore,
_hasher: PhantomData,
extensions,
overlay,
changes_trie_storage,
_marker: PhantomData,
}
}
@@ -220,10 +222,10 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
///
/// Note: changes to code will be in place if this call is made again. For running partial
/// blocks (e.g. a transaction at a time), ensure a different method is used.
pub fn execute(
&mut self,
strategy: ExecutionStrategy,
) -> Result<(Vec<u8>, (B::Transaction, H::Out), Option<ChangesTrieTransaction<H, N>>), Box<dyn Error>> {
pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result<
(Vec<u8>, (B::Transaction, H::Out), Option<ChangesTrieTransaction<H, N>>),
Box<dyn Error>,
> {
// We are not giving a native call and thus we are sure that the result can never be a native
// value.
self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
@@ -252,38 +254,44 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
R: Decode + Encode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
{
let mut externalities = ext::Ext::new(
let mut ext = Ext::new(
self.overlay,
&self.backend,
self.changes_trie_storage,
self.offchain_ext.as_mut().map(|x| &mut **x),
self.keystore.clone(),
self.backend,
self.changes_trie_storage.clone(),
Some(&mut self.extensions),
);
let id = externalities.id;
trace!(target: "state-trace", "{:04x}: Call {} at {:?}. Input={:?}",
let id = ext.id;
trace!(
target: "state-trace", "{:04x}: Call {} at {:?}. Input={:?}",
id,
self.method,
self.backend,
HexDisplay::from(&self.call_data),
);
let (result, was_native) = self.exec.call(
&mut externalities,
&mut ext,
self.method,
self.call_data,
use_native,
native_call,
);
let (storage_delta, changes_delta) = if compute_tx {
let (storage_delta, changes_delta) = externalities.transaction();
let (storage_delta, changes_delta) = ext.transaction();
(Some(storage_delta), changes_delta)
} else {
(None, None)
};
trace!(target: "state-trace", "{:04x}: Return. Native={:?}, Result={:?}",
trace!(
target: "state-trace", "{:04x}: Return. Native={:?}, Result={:?}",
id,
was_native,
result,
);
(result, was_native, storage_delta, changes_delta)
}
@@ -293,12 +301,16 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
mut native_call: Option<NC>,
orig_prospective: OverlayedChangeSet,
on_consensus_failure: Handler,
) -> (CallResult<R, Exec::Error>, Option<(B::Transaction, H::Out)>, Option<ChangesTrieTransaction<H, N>>) where
) -> (
CallResult<R, Exec::Error>,
Option<(B::Transaction, H::Out)>,
Option<ChangesTrieTransaction<H, N>>,
) where
R: Decode + Encode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
Handler: FnOnce(
CallResult<R, Exec::Error>,
CallResult<R, Exec::Error>
CallResult<R, Exec::Error>,
) -> CallResult<R, Exec::Error>
{
let (result, was_native, storage_delta, changes_delta) = self.execute_aux(
@@ -317,7 +329,8 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
if (result.is_ok() && wasm_result.is_ok()
&& result.as_ref().ok() == wasm_result.as_ref().ok())
|| result.is_err() && wasm_result.is_err() {
|| result.is_err() && wasm_result.is_err()
{
(result, storage_delta, changes_delta)
} else {
(on_consensus_failure(wasm_result, result), wasm_storage_delta, wasm_changes_delta)
@@ -332,7 +345,11 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
compute_tx: bool,
mut native_call: Option<NC>,
orig_prospective: OverlayedChangeSet,
) -> (CallResult<R, Exec::Error>, Option<(B::Transaction, H::Out)>, Option<ChangesTrieTransaction<H, N>>) where
) -> (
CallResult<R, Exec::Error>,
Option<(B::Transaction, H::Out)>,
Option<ChangesTrieTransaction<H, N>>,
) where
R: Decode + Encode + PartialEq,
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
{
@@ -431,7 +448,7 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where
};
if result.is_ok() {
init_overlay(self.overlay, true, &self.backend)?;
init_overlay(self.overlay, true, self.backend)?;
}
result.map_err(|e| Box::new(e) as _)
@@ -445,13 +462,12 @@ pub fn prove_execution<B, H, Exec>(
exec: &Exec,
method: &str,
call_data: &[u8],
keystore: Option<BareCryptoStorePtr>,
keystore: Option<KeystoreExt>,
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
where
B: Backend<H>,
H: Hasher,
Exec: CodeExecutor<H>,
H::Out: Ord + 'static,
H: Hasher<Out=H256>,
Exec: CodeExecutor,
{
let trie_backend = backend.as_trie_backend()
.ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>)?;
@@ -473,17 +489,16 @@ pub fn prove_execution_on_trie_backend<S, H, Exec>(
exec: &Exec,
method: &str,
call_data: &[u8],
keystore: Option<BareCryptoStorePtr>,
keystore: Option<KeystoreExt>,
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
where
S: trie_backend_essence::TrieBackendStorage<H>,
H: Hasher,
Exec: CodeExecutor<H>,
H::Out: Ord + 'static,
H: Hasher<Out=H256>,
Exec: CodeExecutor,
{
let proving_backend = proving_backend::ProvingBackend::new(trie_backend);
let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage<H, u64>, _, Exec>::new(
proving_backend, None, NeverOffchainExt::new(), overlay, exec, method, call_data, keystore,
let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage<H, u64>, Exec>::new(
&proving_backend, None, None, overlay, exec, method, call_data, keystore,
);
let (result, _, _) = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
@@ -503,11 +518,11 @@ pub fn execution_proof_check<H, Exec>(
exec: &Exec,
method: &str,
call_data: &[u8],
keystore: Option<BareCryptoStorePtr>,
keystore: Option<KeystoreExt>,
) -> Result<Vec<u8>, Box<dyn Error>>
where
H: Hasher,
Exec: CodeExecutor<H>,
H: Hasher<Out=H256>,
Exec: CodeExecutor,
H::Out: Ord + 'static,
{
let trie_backend = create_proof_check_backend::<H>(root.into(), proof)?;
@@ -521,15 +536,14 @@ pub fn execution_proof_check_on_trie_backend<H, Exec>(
exec: &Exec,
method: &str,
call_data: &[u8],
keystore: Option<BareCryptoStorePtr>,
keystore: Option<KeystoreExt>,
) -> Result<Vec<u8>, Box<dyn Error>>
where
H: Hasher,
Exec: CodeExecutor<H>,
H::Out: Ord + 'static,
H: Hasher<Out=H256>,
Exec: CodeExecutor,
{
let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage<H, u64>, _, Exec>::new(
trie_backend, None, NeverOffchainExt::new(), overlay, exec, method, call_data, keystore,
let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage<H, u64>, Exec>::new(
trie_backend, None, None, overlay, exec, method, call_data, keystore,
);
sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
@@ -546,7 +560,7 @@ pub fn prove_read<B, H, I>(
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
where
B: Backend<H>,
H: Hasher,
H: Hasher<Out=H256>,
H::Out: Ord,
I: IntoIterator,
I::Item: AsRef<[u8]>,
@@ -741,7 +755,7 @@ mod tests {
InMemoryStorage as InMemoryChangesTrieStorage,
Configuration as ChangesTrieConfig,
};
use primitives::{Blake2Hasher, map, traits::Externalities, child_storage_key::ChildStorageKey};
use primitives::{Blake2Hasher, map, traits::Externalities, storage::ChildStorageKey};
struct DummyCodeExecutor {
change_changes_trie_config: bool,
@@ -750,10 +764,14 @@ mod tests {
fallback_succeeds: bool,
}
impl<H: Hasher> CodeExecutor<H> for DummyCodeExecutor {
impl CodeExecutor for DummyCodeExecutor {
type Error = u8;
fn call<E: Externalities<H>, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result<R, String>>(
fn call<
E: Externalities,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, String>,
>(
&self,
ext: &mut E,
_method: &str,
@@ -800,9 +818,9 @@ mod tests {
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
let mut state_machine = StateMachine::new(
backend,
&backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
&mut overlayed_changes,
&DummyCodeExecutor {
change_changes_trie_config: false,
@@ -829,9 +847,9 @@ mod tests {
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
let mut state_machine = StateMachine::new(
backend,
&backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
&mut overlayed_changes,
&DummyCodeExecutor {
change_changes_trie_config: false,
@@ -855,9 +873,9 @@ mod tests {
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
let mut state_machine = StateMachine::new(
backend,
&backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
&mut overlayed_changes,
&DummyCodeExecutor {
change_changes_trie_config: false,
@@ -948,7 +966,6 @@ mod tests {
&mut overlay,
backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
);
ext.clear_prefix(b"ab");
@@ -979,7 +996,6 @@ mod tests {
&mut overlay,
backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
);
@@ -1067,9 +1083,9 @@ mod tests {
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
let mut state_machine = StateMachine::new(
backend,
&backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
&mut overlayed_changes,
&DummyCodeExecutor {
change_changes_trie_config: true,
@@ -1092,9 +1108,9 @@ mod tests {
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
let mut state_machine = StateMachine::new(
backend,
&backend,
Some(&changes_trie_storage),
NeverOffchainExt::new(),
None,
&mut overlayed_changes,
&DummyCodeExecutor {
change_changes_trie_config: true,
@@ -420,7 +420,6 @@ mod tests {
&mut overlay,
&backend,
Some(&changes_trie_storage),
crate::NeverOffchainExt::new(),
None,
);
const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
@@ -432,9 +431,12 @@ mod tests {
fn changes_trie_configuration_is_saved() {
let mut overlay = OverlayedChanges::default();
assert!(overlay.changes_trie_config.is_none());
assert_eq!(overlay.set_changes_trie_config(ChangesTrieConfig {
digest_interval: 4, digest_levels: 1,
}), true);
assert_eq!(
overlay.set_changes_trie_config(
ChangesTrieConfig { digest_interval: 4, digest_levels: 1, },
),
true,
);
assert!(overlay.changes_trie_config.is_some());
}
@@ -250,7 +250,7 @@ mod tests {
use crate::backend::{InMemory};
use crate::trie_backend::tests::test_trie;
use super::*;
use primitives::{Blake2Hasher, child_storage_key::ChildStorageKey};
use primitives::{Blake2Hasher, storage::ChildStorageKey};
fn test_proving<'a>(
trie_backend: &'a TrieBackend<PrefixedMemoryDB<Blake2Hasher>,Blake2Hasher>,
+46 -38
View File
@@ -16,7 +16,7 @@
//! Test implementation for Externalities.
use std::collections::{HashMap};
use std::{collections::HashMap, any::{Any, TypeId}};
use hash_db::Hasher;
use crate::{
backend::{InMemory, Backend}, OverlayedChanges,
@@ -26,25 +26,28 @@ use crate::{
},
};
use primitives::{
storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key},
traits::{BareCryptoStorePtr, Externalities}, offchain, child_storage_key::ChildStorageKey,
storage::{
ChildStorageKey,
well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key}
},
traits::Externalities, hash::H256, Blake2Hasher,
};
use codec::Encode;
use externalities::{Extensions, Extension};
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
type StorageTuple = (HashMap<Vec<u8>, Vec<u8>>, HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>);
/// Simple HashMap-based Externalities impl.
pub struct TestExternalities<H: Hasher, N: ChangesTrieBlockNumber> {
pub struct TestExternalities<H: Hasher<Out=H256>=Blake2Hasher, N: ChangesTrieBlockNumber=u64> {
overlay: OverlayedChanges,
backend: InMemory<H>,
changes_trie_storage: ChangesTrieInMemoryStorage<H, N>,
offchain: Option<Box<dyn offchain::Externalities>>,
keystore: Option<BareCryptoStorePtr>,
extensions: Extensions,
}
impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
/// Create a new instance of `TestExternalities` with storage.
pub fn new(storage: StorageTuple) -> Self {
Self::new_with_code(&[], storage)
@@ -75,8 +78,7 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
overlay,
changes_trie_storage: ChangesTrieInMemoryStorage::new(),
backend: backend.into(),
offchain: None,
keystore: None,
extensions: Default::default(),
}
}
@@ -85,14 +87,9 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
self.backend = self.backend.update(vec![(None, k, Some(v))]);
}
/// Set offchain externaltiies.
pub fn set_offchain_externalities(&mut self, offchain: impl offchain::Externalities + 'static) {
self.offchain = Some(Box::new(offchain));
}
/// Set keystore.
pub fn set_keystore(&mut self, keystore: BareCryptoStorePtr) {
self.keystore = Some(keystore);
/// Registers the given extension for this instance.
pub fn register_extension<E: Any + Extension>(&mut self, ext: E) {
self.extensions.register(ext);
}
/// Get mutable reference to changes trie storage.
@@ -118,13 +115,13 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
}
}
impl<H: Hasher, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities<H, N> {
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities<H, N> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs())
}
}
impl<H: Hasher, N: ChangesTrieBlockNumber> PartialEq for TestExternalities<H, N> {
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> PartialEq for TestExternalities<H, N> {
/// This doesn't test if they are in the same state, only if they contains the
/// same data at this state
fn eq(&self, other: &TestExternalities<H, N>) -> bool {
@@ -132,30 +129,37 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> PartialEq for TestExternalities<H, N>
}
}
impl<H: Hasher, N: ChangesTrieBlockNumber> Default for TestExternalities<H, N> {
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> Default for TestExternalities<H, N> {
fn default() -> Self { Self::new(Default::default()) }
}
impl<H: Hasher, N: ChangesTrieBlockNumber> From<StorageTuple> for TestExternalities<H, N> {
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> From<StorageTuple> for TestExternalities<H, N> {
fn from(storage: StorageTuple) -> Self {
Self::new(storage)
}
}
impl<H, N> Externalities<H> for TestExternalities<H, N> where
H: Hasher,
impl<H, N> Externalities for TestExternalities<H, N> where
H: Hasher<Out=H256>,
N: ChangesTrieBlockNumber,
H::Out: Ord + 'static,
{
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL))
}
fn storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage(key).map(|v| H::hash(&v))
}
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)
}
fn original_storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage_hash(key)
}
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
self.overlay
.child_storage(storage_key.as_ref(), key)
@@ -166,6 +170,10 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
)
}
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage(storage_key, key).map(|v| H::hash(&v))
}
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
self.backend
.child_storage(storage_key.as_ref(), key)
@@ -173,6 +181,10 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
.expect(EXT_NOT_ALLOWED_TO_FAIL)
}
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage_hash(storage_key, key)
}
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
if is_child_storage_key(&key) {
panic!("Refuse to directly set child storage key");
@@ -185,7 +197,7 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
&mut self,
storage_key: ChildStorageKey,
key: Vec<u8>,
value: Option<Vec<u8>>
value: Option<Vec<u8>>,
) {
self.overlay.set_child_storage(storage_key.into_owned(), key, value);
}
@@ -215,7 +227,6 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
}
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) {
self.overlay.clear_child_prefix(storage_key.as_ref(), prefix);
let backend = &self.backend;
@@ -227,8 +238,7 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
fn chain_id(&self) -> u64 { 42 }
fn storage_root(&mut self) -> H::Out {
fn storage_root(&mut self) -> H256 {
let child_storage_keys =
self.overlay.prospective.children.keys()
.chain(self.overlay.committed.children.keys());
@@ -246,7 +256,6 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))
.chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone())));
self.backend.full_storage_root(delta, child_delta_iter).0
}
fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec<u8> {
@@ -270,7 +279,7 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
root
}
fn storage_changes_root(&mut self, parent: H::Out) -> Result<Option<H::Out>, ()> {
fn storage_changes_root(&mut self, parent: H256) -> Result<Option<H256>, ()> {
Ok(build_changes_trie::<_, _, H, N>(
&self.backend,
Some(&self.changes_trie_storage),
@@ -278,15 +287,14 @@ impl<H, N> Externalities<H> for TestExternalities<H, N> where
parent,
)?.map(|(_, root, _)| root))
}
}
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> {
self.offchain
.as_mut()
.map(|x| &mut **x as _)
}
fn keystore(&self) -> Option<BareCryptoStorePtr> {
self.keystore.clone()
impl<H, N> externalities::ExtensionStore for TestExternalities<H, N> where
H: Hasher<Out=H256>,
N: ChangesTrieBlockNumber,
{
fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
self.extensions.get_mut(type_id)
}
}
+16 -13
View File
@@ -319,10 +319,11 @@ fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
mod tests {
use super::*;
use runtime_io::{with_externalities, TestExternalities};
use runtime_io::TestExternalities;
use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring};
use sr_primitives::set_and_run_with_externalities;
use crate::{Header, Transfer, WASM_BINARY};
use primitives::{Blake2Hasher, NeverNativeValue, map, traits::CodeExecutor};
use primitives::{NeverNativeValue, map, traits::CodeExecutor};
use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance};
// Declare an instance of the native executor dispatch for the test runtime.
@@ -336,7 +337,7 @@ mod tests {
NativeExecutor::new(WasmExecutionMethod::Interpreted, None)
}
fn new_test_ext() -> TestExternalities<Blake2Hasher> {
fn new_test_ext() -> TestExternalities {
let authorities = vec![
Sr25519Keyring::Alice.to_raw_public(),
Sr25519Keyring::Bob.to_raw_public(),
@@ -357,7 +358,7 @@ mod tests {
)
}
fn block_import_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities<Blake2Hasher>) {
fn block_import_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities) {
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
@@ -370,7 +371,7 @@ mod tests {
extrinsics: vec![],
};
with_externalities(&mut new_test_ext(), || polish_block(&mut b));
set_and_run_with_externalities(&mut new_test_ext(), || polish_block(&mut b));
block_executor(b, &mut new_test_ext());
}
@@ -378,7 +379,7 @@ mod tests {
#[test]
fn block_import_works_native() {
block_import_works(|b, ext| {
with_externalities(ext, || {
set_and_run_with_externalities(ext, || {
execute_block(b);
});
});
@@ -397,7 +398,9 @@ mod tests {
})
}
fn block_import_with_transaction_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities<Blake2Hasher>) {
fn block_import_with_transaction_works<F>(block_executor: F)
where F: Fn(Block, &mut TestExternalities)
{
let mut b1 = Block {
header: Header {
parent_hash: [69u8; 32].into(),
@@ -417,7 +420,7 @@ mod tests {
};
let mut dummy_ext = new_test_ext();
with_externalities(&mut dummy_ext, || polish_block(&mut b1));
set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b1));
let mut b2 = Block {
header: Header {
@@ -443,26 +446,26 @@ mod tests {
],
};
with_externalities(&mut dummy_ext, || polish_block(&mut b2));
set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b2));
drop(dummy_ext);
let mut t = new_test_ext();
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 111);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 0);
});
block_executor(b1, &mut t);
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 42);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 69);
});
block_executor(b2, &mut t);
with_externalities(&mut t, || {
set_and_run_with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 0);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 42);
assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69);
@@ -472,7 +475,7 @@ mod tests {
#[test]
fn block_import_with_transaction_works_native() {
block_import_with_transaction_works(|b, ext| {
with_externalities(ext, || {
set_and_run_with_externalities(ext, || {
execute_block(b);
});
});