mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 09:51:10 +00:00
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:
@@ -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}},
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
@@ -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#"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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, ¶meters, &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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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).
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
|
||||
@@ -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" ]
|
||||
+65
-13
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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))),
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user