Cumulus changes version 2 (#2313)

* ensure imbalances are properly accounted for (#2183)

* ensure imbalances are properly accounted for

* bump runtime version

* Update node/runtime/src/lib.rs

* implement contract events (#2161)

* implement contract events

* update runtime

* renaming

* update test code hash

* improve complexity details

* add deposit event base cost

* add test

* Revert "add deposit event base cost"

This reverts commit 58ec010c0f4f4f0e16935ad41da32aedd17a8c57.

* update test

* Revert "update test"

This reverts commit 6fe61a593ccf0d41f09a0b97472b28ed8751a999.

* Revert "Revert "add deposit event base cost""

This reverts commit 145e8a9bac15313a4c380aa66b94fd4d36fa3f6d.

* Fix format a bit

*  Replace Vec<u8> with [u8; 32] for contract storage key (#2184)

* Replace Vec<u8> with [u8; 32] for contract storage key

* Read storage keys from sandbox memory into fixed size buffer

* Increment `impl_version`

* Remove redundant Ok(()) and explicitly specify StorageKey buffer type (#2188)

* Switch to `derive(Encode, Decode)` for `Call` (#2178)

* Add some tests

* More tests

* Switch to `derive(Encode, Decode)` for `Call`

* Update lock files

* Simplify the macro cases

* Cache changes trie config in db storage (#2170)

* cache changes trie config in db storage

* Update core/client/db/src/lib.rs

Co-Authored-By: svyatonik <svyatonik@gmail.com>

* Update core/client/db/src/lib.rs

Co-Authored-By: svyatonik <svyatonik@gmail.com>

* Fix version check for renamed runtime api methods (#2190)

* Add feature to disable including the test-runtime wasm blob

* Enable `std` feature for `consensus_authorities`

* Implement `skip_initialize_block` and `initialize_block` for runtime api

* Add test and fixes bug

* Begin to implement support for passing the `ProofRecorder`

* Make sure proof generation works as intended

* Fixes tests

* Make `BlockBuilder` generate proofs on request.

* Adds `TestClientBuilder` to simplify creating a test client

* Add `include-wasm-blob` to `test-client` as well

* Make `test-client` compile without including the wasm file

* Disable more stuff in test-client without wasm

* Reorganize the re-exports

* Use correct bounds

* Update docs

* Update core/client/src/block_builder/block_builder.rs

Co-Authored-By: bkchr <bkchr@users.noreply.github.com>

* Extend test to actually generated proof

* Switch to enum for `skip_initialize_block`

* Some wasm files updates
This commit is contained in:
Bastian Köcher
2019-04-29 16:55:20 +02:00
committed by GitHub
parent bb9746c798
commit bad3ce4e17
27 changed files with 800 additions and 267 deletions
@@ -24,10 +24,9 @@ use runtime_primitives::traits::{
};
use primitives::{H256, ExecutionContext};
use crate::blockchain::HeaderBackend;
use crate::runtime_api::Core;
use crate::runtime_api::{Core, ApiExt};
use crate::error;
/// Utility for building new (valid) blocks from a stream of extrinsics.
pub struct BlockBuilder<'a, Block, A: ProvideRuntimeApi> where Block: BlockT {
header: <Block as BlockT>::Header,
@@ -44,12 +43,22 @@ where
{
/// Create a new instance of builder from the given client, building on the latest block.
pub fn new(api: &'a A) -> error::Result<Self> {
api.info().and_then(|i| Self::at_block(&BlockId::Hash(i.best_hash), api))
api.info().and_then(|i|
Self::at_block(&BlockId::Hash(i.best_hash), api, false)
)
}
/// Create a new instance of builder from the given client using a particular block's ID to
/// build upon.
pub fn at_block(block_id: &BlockId<Block>, api: &'a A) -> error::Result<Self> {
/// Create a new instance of builder from the given client using a
/// particular block's ID to build upon with optional proof recording enabled.
///
/// While proof recording is enabled, all accessed trie nodes are saved.
/// These recorded trie nodes can be used by a third party to proof the
/// output of this block builder without having access to the full storage.
pub fn at_block(
block_id: &BlockId<Block>,
api: &'a A,
proof_recording: bool
) -> error::Result<Self> {
let number = api.block_number_from_id(block_id)?
.ok_or_else(|| error::Error::UnknownBlock(format!("{}", block_id)))?
+ One::one();
@@ -63,8 +72,17 @@ where
parent_hash,
Default::default()
);
let api = api.runtime_api();
api.initialize_block_with_context(block_id, ExecutionContext::BlockConstruction, &header)?;
let mut api = api.runtime_api();
if proof_recording {
api.record_proof();
}
api.initialize_block_with_context(
block_id, ExecutionContext::BlockConstruction, &header
)?;
Ok(BlockBuilder {
header,
extrinsics: Vec::new(),
@@ -77,13 +95,15 @@ where
///
/// This will ensure the extrinsic can be validly executed (by executing it);
pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> error::Result<()> {
use crate::runtime_api::ApiExt;
let block_id = &self.block_id;
let extrinsics = &mut self.extrinsics;
self.api.map_api_result(|api| {
match api.apply_extrinsic_with_context(block_id, ExecutionContext::BlockConstruction, xt.clone())? {
match api.apply_extrinsic_with_context(
block_id,
ExecutionContext::BlockConstruction,
xt.clone()
)? {
Ok(ApplyOutcome::Success) | Ok(ApplyOutcome::Fail) => {
extrinsics.push(xt);
Ok(())
@@ -97,13 +117,34 @@ where
/// Consume the builder to return a valid `Block` containing all pushed extrinsics.
pub fn bake(mut self) -> error::Result<Block> {
self.header = self.api.finalize_block_with_context(&self.block_id, ExecutionContext::BlockConstruction)?;
self.bake_impl()?;
Ok(<Block as BlockT>::new(self.header, self.extrinsics))
}
fn bake_impl(&mut self) -> error::Result<()> {
self.header = self.api.finalize_block_with_context(
&self.block_id, ExecutionContext::BlockConstruction
)?;
debug_assert_eq!(
self.header.extrinsics_root().clone(),
HashFor::<Block>::ordered_trie_root(self.extrinsics.iter().map(Encode::encode)),
HashFor::<Block>::ordered_trie_root(
self.extrinsics.iter().map(Encode::encode)
),
);
Ok(<Block as BlockT>::new(self.header, self.extrinsics))
Ok(())
}
/// Consume the builder to return a valid `Block` containing all pushed extrinsics
/// and the generated proof.
///
/// The proof will be `Some(_)`, if proof recording was enabled while creating
/// the block builder.
pub fn bake_and_extract_proof(mut self) -> error::Result<(Block, Option<Vec<Vec<u8>>>)> {
self.bake_impl()?;
let proof = self.api.extract_proof();
Ok((<Block as BlockT>::new(self.header, self.extrinsics), proof))
}
}
+79 -57
View File
@@ -14,21 +14,25 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::{sync::Arc, cmp::Ord, panic::UnwindSafe, result};
use std::{sync::Arc, cmp::Ord, panic::UnwindSafe, result, cell::RefCell, rc::Rc};
use parity_codec::{Encode, Decode};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, RuntimeApiInfo};
use runtime_primitives::{
generic::BlockId, traits::Block as BlockT,
};
use state_machine::{
self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, ExecutionStrategy, NeverOffchainExt,
self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager,
ExecutionStrategy, NeverOffchainExt, backend::Backend as _,
};
use executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
use hash_db::Hasher;
use trie::MemoryDB;
use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, OffchainExt};
use primitives::{
H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, OffchainExt
};
use crate::runtime_api::{ProofRecorder, InitializeBlock};
use crate::backend;
use crate::error;
use crate::runtime_api::Core as CoreApi;
/// Method call executor.
pub trait CallExecutor<B, H>
@@ -60,8 +64,9 @@ where
/// Before executing the method, passed header is installed as the current header
/// of the execution context.
fn contextual_call<
'a,
O: OffchainExt,
PB: Fn() -> error::Result<B::Header>,
IB: Fn() -> error::Result<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
@@ -70,15 +75,16 @@ where
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
>(
&self,
initialize_block_fn: IB,
at: &BlockId<B>,
method: &str,
call_data: &[u8],
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<B>>,
prepare_environment_block: PB,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, B>,
execution_manager: ExecutionManager<EM>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
proof_recorder: &Option<Rc<RefCell<ProofRecorder<B>>>>,
) -> error::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
/// Extract RuntimeVersion of given block
@@ -119,7 +125,10 @@ where
call_data: &[u8]
) -> Result<(Vec<u8>, Vec<Vec<u8>>), error::Error> {
let trie_state = state.try_into_trie_backend()
.ok_or_else(|| Box::new(state_machine::ExecutionError::UnableToGenerateProof) as Box<state_machine::Error>)?;
.ok_or_else(||
Box::new(state_machine::ExecutionError::UnableToGenerateProof)
as Box<state_machine::Error>
)?;
self.prove_at_trie_state(&trie_state, overlay, method, call_data)
}
@@ -172,7 +181,8 @@ where
{
type Error = E::Error;
fn call<O: OffchainExt>(&self,
fn call<O: OffchainExt>(
&self,
id: &BlockId<Block>,
method: &str,
call_data: &[u8],
@@ -200,8 +210,9 @@ where
}
fn contextual_call<
'a,
O: OffchainExt,
PB: Fn() -> error::Result<Block::Header>,
IB: Fn() -> error::Result<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
@@ -210,64 +221,75 @@ where
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
>(
&self,
initialize_block_fn: IB,
at: &BlockId<Block>,
method: &str,
call_data: &[u8],
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<Block>>,
prepare_environment_block: PB,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
execution_manager: ExecutionManager<EM>,
native_call: Option<NC>,
mut side_effects_handler: Option<&mut O>,
side_effects_handler: Option<&mut O>,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
) -> Result<NativeOrEncoded<R>, error::Error> where ExecutionManager<EM>: Clone {
match initialize_block {
InitializeBlock::Do(ref init_block)
if init_block.borrow().as_ref().map(|id| id != at).unwrap_or(true) => {
initialize_block_fn()?;
},
// We don't need to initialize the runtime at a block.
_ => {},
}
let state = self.backend.state_at(*at)?;
let core_version = self.runtime_version(at)?.apis.iter().find(|a| a.0 == CoreApi::<Block>::ID).map(|a| a.1);
let init_block_function = if core_version < Some(2) {
"Core_initialise_block"
} else {
"Core_initialize_block"
};
match recorder {
Some(recorder) => {
let trie_state = state.try_into_trie_backend()
.ok_or_else(||
Box::new(state_machine::ExecutionError::UnableToGenerateProof)
as Box<state_machine::Error>
)?;
if method != init_block_function && initialized_block.map(|id| id != *at).unwrap_or(true) {
let header = prepare_environment_block()?;
state_machine::new(
let backend = state_machine::ProvingBackend::new_with_recorder(
&trie_state,
recorder.clone()
);
state_machine::new(
&backend,
self.backend.changes_trie_storage(),
side_effects_handler,
&mut *changes.borrow_mut(),
&self.executor,
method,
call_data,
)
.execute_using_consensus_failure_handler(
execution_manager,
false,
native_call,
)
.map(|(result, _, _)| result)
.map_err(Into::into)
}
None => state_machine::new(
&state,
self.backend.changes_trie_storage(),
side_effects_handler.as_mut().map(|x| &mut **x),
changes,
side_effects_handler,
&mut *changes.borrow_mut(),
&self.executor,
init_block_function,
&header.encode(),
).execute_using_consensus_failure_handler::<_, R, fn() -> _>(
execution_manager.clone(),
method,
call_data,
)
.execute_using_consensus_failure_handler(
execution_manager,
false,
None,
)?;
*initialized_block = Some(*at);
native_call,
)
.map(|(result, _, _)| result)
.map_err(Into::into)
}
let result = state_machine::new(
&state,
self.backend.changes_trie_storage(),
side_effects_handler,
changes,
&self.executor,
method,
call_data,
).execute_using_consensus_failure_handler(
execution_manager,
false,
native_call,
).map(|(result, _, _)| result)?;
// If the method is `initialize_block` we need to set the `initialized_block`
if method == init_block_function {
*initialized_block = Some(*at);
}
self.backend.destroy_state(state)?;
Ok(result)
}
fn runtime_version(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> {
+56 -20
View File
@@ -16,7 +16,10 @@
//! Substrate Client
use std::{marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc, panic::UnwindSafe, result};
use std::{
marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc,
panic::UnwindSafe, result, cell::RefCell, rc::Rc,
};
use crate::error::Error;
use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock};
@@ -26,16 +29,23 @@ use runtime_primitives::{
generic::{BlockId, SignedBlock},
};
use consensus::{
Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock, ImportResult,
BlockOrigin, ForkChoiceStrategy, well_known_cache_keys::Id as CacheKeyId,
Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock,
ImportResult, BlockOrigin, ForkChoiceStrategy,
well_known_cache_keys::Id as CacheKeyId,
};
use runtime_primitives::traits::{
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash,
ApiRef, ProvideRuntimeApi, Digest, DigestItem
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight,
BlockNumberToHash, ApiRef, ProvideRuntimeApi, Digest, DigestItem
};
use runtime_primitives::BuildStorage;
use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi};
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue, ExecutionContext};
use crate::runtime_api::{
CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder,
InitializeBlock,
};
use primitives::{
Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash,
NeverNativeValue, ExecutionContext
};
use primitives::storage::{StorageKey, StorageData};
use primitives::storage::well_known_keys;
use parity_codec::{Encode, Decode};
@@ -49,8 +59,8 @@ use hash_db::Hasher;
use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage};
use crate::blockchain::{
self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend,
ProvideCache, Cache,
self, Info as ChainInfo, Backend as ChainBackend,
HeaderBackend as ChainHeaderBackend, ProvideCache, Cache,
};
use crate::call_executor::{CallExecutor, LocalCallExecutor};
use executor::{RuntimeVersion, RuntimeInfo};
@@ -610,7 +620,23 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
Self: ProvideRuntimeApi,
<Self as ProvideRuntimeApi>::Api: BlockBuilderAPI<Block>
{
block_builder::BlockBuilder::at_block(parent, &self)
block_builder::BlockBuilder::at_block(parent, &self, false)
}
/// Create a new block, built on top of `parent` with proof recording enabled.
///
/// While proof recording is enabled, all accessed trie nodes are saved.
/// These recorded trie nodes can be used by a third party to proof the
/// output of this block builder without having access to the full storage.
pub fn new_block_at_with_proof_recording(
&self, parent: &BlockId<Block>
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
E: Clone + Send + Sync,
RA: Send + Sync,
Self: ProvideRuntimeApi,
<Self as ProvideRuntimeApi>::Api: BlockBuilderAPI<Block>
{
block_builder::BlockBuilder::at_block(parent, &self, true)
}
/// Lock the import lock, and run operations inside.
@@ -1340,27 +1366,36 @@ impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
Block: BlockT<Hash=H256>
Block: BlockT<Hash=H256>,
{
fn call_api_at<
'a,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
C: CoreApi<Block>,
>(
&self,
core_api: &C,
at: &BlockId<Block>,
function: &'static str,
args: Vec<u8>,
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<Block>>,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
native_call: Option<NC>,
context: ExecutionContext,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
) -> error::Result<NativeOrEncoded<R>> {
let manager = match context {
ExecutionContext::BlockConstruction => self.execution_strategies.block_construction.get_manager(),
ExecutionContext::Syncing => self.execution_strategies.syncing.get_manager(),
ExecutionContext::Importing => self.execution_strategies.importing.get_manager(),
ExecutionContext::OffchainWorker(_) => self.execution_strategies.offchain_worker.get_manager(),
ExecutionContext::Other => self.execution_strategies.other.get_manager(),
ExecutionContext::BlockConstruction =>
self.execution_strategies.block_construction.get_manager(),
ExecutionContext::Syncing =>
self.execution_strategies.syncing.get_manager(),
ExecutionContext::Importing =>
self.execution_strategies.importing.get_manager(),
ExecutionContext::OffchainWorker(_) =>
self.execution_strategies.offchain_worker.get_manager(),
ExecutionContext::Other =>
self.execution_strategies.other.get_manager(),
};
let mut offchain_extensions = match context {
@@ -1369,15 +1404,16 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
};
self.executor.contextual_call::<_, _, fn(_,_) -> _,_,_>(
|| core_api.initialize_block(at, &self.prepare_environment_block(at)?),
at,
function,
&args,
changes,
initialized_block,
|| self.prepare_environment_block(at),
initialize_block,
manager,
native_call,
offchain_extensions.as_mut(),
recorder,
)
}
@@ -17,17 +17,24 @@
//! Light client call executor. Executes methods on remote full nodes, fetching
//! execution proof and checking it locally.
use std::{collections::HashSet, sync::Arc, panic::UnwindSafe, result, marker::PhantomData};
use std::{
collections::HashSet, sync::Arc, panic::UnwindSafe, result,
marker::PhantomData, cell::RefCell, rc::Rc,
};
use futures::{IntoFuture, Future};
use parity_codec::{Encode, Decode};
use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded, OffchainExt};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT};
use state_machine::{self, Backend as StateBackend, CodeExecutor, OverlayedChanges, ExecutionStrategy,
create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, NeverOffchainExt};
use state_machine::{
self, Backend as StateBackend, CodeExecutor, OverlayedChanges,
ExecutionStrategy, create_proof_check_backend,
execution_proof_check_on_trie_backend, ExecutionManager, NeverOffchainExt
};
use hash_db::Hasher;
use crate::runtime_api::{ProofRecorder, InitializeBlock};
use crate::backend::RemoteBackend;
use crate::blockchain::Backend as ChainBackend;
use crate::call_executor::CallExecutor;
@@ -104,8 +111,9 @@ where
}
fn contextual_call<
'a,
O: OffchainExt,
PB: Fn() -> ClientResult<Block::Header>,
IB: Fn() -> ClientResult<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
@@ -114,18 +122,26 @@ where
NC,
>(
&self,
_initialize_block_fn: IB,
at: &BlockId<Block>,
method: &str,
call_data: &[u8],
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<Block>>,
_prepare_environment_block: PB,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
execution_manager: ExecutionManager<EM>,
_native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
_recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
let block_initialized = match initialize_block {
InitializeBlock::Do(ref init_block) => {
init_block.borrow().is_some()
},
InitializeBlock::Skip => false,
};
// it is only possible to execute contextual call if changes are empty
if !changes.is_empty() || initialized_block.is_some() {
if !changes.borrow().is_empty() || block_initialized {
return Err(ClientError::NotAvailableOnLightClient.into());
}
@@ -231,8 +247,9 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
}
fn contextual_call<
'a,
O: OffchainExt,
PB: Fn() -> ClientResult<Block::Header>,
IB: Fn() -> ClientResult<()>,
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
@@ -241,15 +258,16 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
>(
&self,
initialize_block_fn: IB,
at: &BlockId<Block>,
method: &str,
call_data: &[u8],
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<Block>>,
prepare_environment_block: PB,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
_manager: ExecutionManager<EM>,
native_call: Option<NC>,
side_effects_handler: Option<&mut O>,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
// there's no actual way/need to specify native/wasm execution strategy on light node
// => we can safely ignore passed values
@@ -266,15 +284,16 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
NC
>(
&self.local,
initialize_block_fn,
at,
method,
call_data,
changes,
initialized_block,
prepare_environment_block,
initialize_block,
ExecutionManager::NativeWhenPossible,
native_call,
side_effects_handler,
recorder,
).map_err(|e| ClientError::Execution(Box::new(e.to_string()))),
false => CallExecutor::contextual_call::<
_,
@@ -287,15 +306,16 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
NC
>(
&self.remote,
initialize_block_fn,
at,
method,
call_data,
changes,
initialized_block,
prepare_environment_block,
initialize_block,
ExecutionManager::NativeWhenPossible,
native_call,
side_effects_handler,
recorder,
).map_err(|e| ClientError::Execution(Box::new(e.to_string()))),
}
}
+51 -4
View File
@@ -24,7 +24,10 @@ pub use state_machine::OverlayedChanges;
pub use primitives::NativeOrEncoded;
#[doc(hidden)]
pub use runtime_primitives::{
traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, Header as HeaderT, ApiRef, RuntimeApiInfo},
traits::{
AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType,
Header as HeaderT, ApiRef, RuntimeApiInfo, Hash as HashT,
},
generic::BlockId, transaction_validity::TransactionValidity,
};
#[doc(hidden)]
@@ -42,8 +45,16 @@ use crate::error;
use sr_api_macros::decl_runtime_apis;
use primitives::OpaqueMetadata;
#[cfg(feature = "std")]
use std::panic::UnwindSafe;
use std::{panic::UnwindSafe, cell::RefCell, rc::Rc};
use rstd::vec::Vec;
#[cfg(feature = "std")]
use primitives::Hasher as HasherT;
#[cfg(feature = "std")]
/// A type that records all accessed trie nodes and generates a proof out of it.
pub type ProofRecorder<B> = state_machine::ProofRecorder<
<<<<B as BlockT>::Header as HeaderT>::Hashing as HashT>::Hasher as HasherT>::Out
>;
/// Something that can be constructed to a runtime api.
#[cfg(feature = "std")]
@@ -87,6 +98,35 @@ pub trait ApiExt<Block: BlockT> {
/// Returns the runtime version at the given block id.
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion>;
/// Start recording all accessed trie nodes for generating proofs.
fn record_proof(&mut self);
/// Extract the recorded proof.
/// This stops the proof recording.
fn extract_proof(&mut self) -> Option<Vec<Vec<u8>>>;
}
/// Before calling any runtime api function, the runtime need to be initialized
/// at the requested block. However, some functions like `execute_block` or
/// `initialize_block` itself don't require to have the runtime initialized
/// at the requested block.
///
/// `call_api_at` is instructed by this enum to do the initialization or to skip
/// it.
#[cfg(feature = "std")]
#[derive(Clone, Copy)]
pub enum InitializeBlock<'a, Block: BlockT> {
/// Skip initializing the runtime for a given block.
///
/// This is used by functions who do the initialization by themself or don't
/// require it.
Skip,
/// Initialize the runtime for a given block.
///
/// If the stored `BlockId` is `Some(_)`, the runtime is currently initialized
/// at this block.
Do(&'a RefCell<Option<BlockId<Block>>>),
}
/// Something that can call into the runtime at a given block.
@@ -95,17 +135,21 @@ pub trait CallRuntimeAt<Block: BlockT> {
/// Calls the given api function with the given encoded arguments at the given block
/// and returns the encoded result.
fn call_api_at<
'a,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe,
C: Core<Block>,
>(
&self,
core_api: &C,
at: &BlockId<Block>,
function: &'static str,
args: Vec<u8>,
changes: &mut OverlayedChanges,
initialized_block: &mut Option<BlockId<Block>>,
changes: &RefCell<OverlayedChanges>,
initialize_block: InitializeBlock<'a, Block>,
native_call: Option<NC>,
context: ExecutionContext,
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
) -> error::Result<NativeOrEncoded<R>>;
/// Returns the runtime version at the given block.
@@ -120,9 +164,12 @@ decl_runtime_apis! {
/// Returns the version of the runtime.
fn version() -> RuntimeVersion;
/// Execute the given block.
#[skip_initialize_block]
fn execute_block(block: Block);
/// Initialize a block with the given header.
#[renamed("initialise_block", 2)]
#[skip_initialize_block]
#[initialize_block]
fn initialize_block(header: &<Block as BlockT>::Header);
/// Returns the authorities.
#[deprecated(since = "1.0", note = "Please switch to `AuthoritiesApi`.")]