mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 10:01:17 +00:00
Merge branch 'master' into rh-grandpa-dynamic2
This commit is contained in:
@@ -47,8 +47,7 @@ impl NewBlockState {
|
||||
}
|
||||
|
||||
/// Block insertion operation. Keeps hold if the inserted block state and data.
|
||||
pub trait BlockImportOperation<Block, H>
|
||||
where
|
||||
pub trait BlockImportOperation<Block, H> where
|
||||
Block: BlockT,
|
||||
H: Hasher<Out=Block::Hash>,
|
||||
{
|
||||
@@ -88,11 +87,9 @@ where
|
||||
///
|
||||
/// The same applies for live `BlockImportOperation`s: while an import operation building on a parent `P`
|
||||
/// is alive, the state for `P` should not be pruned.
|
||||
pub trait Backend<Block, H>: Send + Sync
|
||||
where
|
||||
pub trait Backend<Block, H>: Send + Sync where
|
||||
Block: BlockT,
|
||||
H: Hasher<Out=Block::Hash>,
|
||||
|
||||
{
|
||||
/// Associated block insertion operation type.
|
||||
type BlockImportOperation: BlockImportOperation<Block, H>;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
//! The runtime api for building blocks.
|
||||
|
||||
use runtime_primitives::{traits::Block as BlockT, ApplyResult};
|
||||
use rstd::vec::Vec;
|
||||
|
||||
decl_runtime_apis! {
|
||||
/// The `BlockBuilder` api trait that provides required functions for building a block for a runtime.
|
||||
pub trait BlockBuilder<Block: BlockT> {
|
||||
/// The runtime api for building blocks./// Apply the given extrinsics.
|
||||
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult;
|
||||
/// Finish the current block.
|
||||
fn finalise_block() -> <Block as BlockT>::Header;
|
||||
/// Generate inherent extrinsics.
|
||||
fn inherent_extrinsics<InherentExtrinsic, UncheckedExtrinsic>(
|
||||
inherent: InherentExtrinsic
|
||||
) -> Vec<UncheckedExtrinsic>;
|
||||
/// Check that the inherents are valid.
|
||||
fn check_inherents<InherentData, Error>(
|
||||
block: Block, data: InherentData
|
||||
) -> Result<(), Error>;
|
||||
/// Generate a random seed.
|
||||
fn random_seed() -> <Block as BlockT>::Hash;
|
||||
}
|
||||
}
|
||||
+36
-48
@@ -14,60 +14,48 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Utility struct to build a block.
|
||||
|
||||
use super::api::BlockBuilder as BlockBuilderApi;
|
||||
use std::vec::Vec;
|
||||
use std::marker::PhantomData;
|
||||
use codec::Encode;
|
||||
use state_machine;
|
||||
use runtime_primitives::traits::{Header as HeaderT, Hash, Block as BlockT, One, HashFor};
|
||||
use blockchain::HeaderBackend;
|
||||
use runtime_primitives::traits::{
|
||||
Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef
|
||||
};
|
||||
use primitives::H256;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_api::BlockBuilder as BlockBuilderAPI;
|
||||
use {backend, error, Client, CallExecutor};
|
||||
use runtime_api::Core;
|
||||
use error;
|
||||
use runtime_primitives::ApplyOutcome;
|
||||
use primitives::{Blake2Hasher, H256};
|
||||
use hash_db::Hasher;
|
||||
|
||||
/// Utility for building new (valid) blocks from a stream of extrinsics.
|
||||
pub struct BlockBuilder<'a, B, E, Block, H>
|
||||
where
|
||||
B: backend::Backend<Block, H> + 'a,
|
||||
E: CallExecutor<Block, H> + Clone + 'a,
|
||||
Block: BlockT,
|
||||
H: Hasher<Out=Block::Hash>,
|
||||
H::Out: Ord,
|
||||
|
||||
{
|
||||
pub struct BlockBuilder<'a, Block, A: ProvideRuntimeApi> where Block: BlockT {
|
||||
header: <Block as BlockT>::Header,
|
||||
extrinsics: Vec<<Block as BlockT>::Extrinsic>,
|
||||
client: &'a Client<B, E, Block>,
|
||||
api: ApiRef<'a, A::Api>,
|
||||
block_id: BlockId<Block>,
|
||||
changes: state_machine::OverlayedChanges,
|
||||
_marker: PhantomData<H>,
|
||||
}
|
||||
|
||||
impl<'a, B, E, Block> BlockBuilder<'a, B, E, Block, Blake2Hasher>
|
||||
impl<'a, Block, A> BlockBuilder<'a, Block, A>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher> + 'a,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + 'a,
|
||||
Block: BlockT<Hash=H256>,
|
||||
A: ProvideRuntimeApi + HeaderBackend<Block> + 'a,
|
||||
A::Api: BlockBuilderApi<Block>,
|
||||
{
|
||||
/// Create a new instance of builder from the given client, building on the latest block.
|
||||
pub fn new(client: &'a Client<B, E, Block>) -> error::Result<Self> {
|
||||
client.info().and_then(|i| Self::at_block(&BlockId::Hash(i.chain.best_hash), client))
|
||||
pub fn new(api: &'a A) -> error::Result<Self> {
|
||||
api.info().and_then(|i| Self::at_block(&BlockId::Hash(i.best_hash), api))
|
||||
}
|
||||
|
||||
/// 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>, client: &'a Client<B, E, Block>) -> error::Result<Self> {
|
||||
let number = client.block_number_from_id(block_id)?
|
||||
pub fn at_block(block_id: &BlockId<Block>, api: &'a A) -> error::Result<Self> {
|
||||
let number = api.block_number_from_id(block_id)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", block_id)))?
|
||||
+ One::one();
|
||||
|
||||
let parent_hash = client.block_hash_from_id(block_id)?
|
||||
let parent_hash = api.block_hash_from_id(block_id)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", block_id)))?;
|
||||
|
||||
let mut changes = Default::default();
|
||||
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
||||
number,
|
||||
Default::default(),
|
||||
@@ -76,16 +64,14 @@ where
|
||||
Default::default()
|
||||
);
|
||||
|
||||
client.initialise_block(block_id, &mut changes, &header)?;
|
||||
changes.commit_prospective();
|
||||
let api = api.runtime_api();
|
||||
api.initialise_block(block_id, &header)?;
|
||||
|
||||
Ok(BlockBuilder {
|
||||
header,
|
||||
extrinsics: Vec::new(),
|
||||
client,
|
||||
api,
|
||||
block_id: *block_id,
|
||||
changes,
|
||||
_marker: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -93,30 +79,32 @@ where
|
||||
/// can be validly executed (by executing it); if it is invalid, it'll be returned along with
|
||||
/// the error. Otherwise, it will return a mutable reference to self (in order to chain).
|
||||
pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> error::Result<()> {
|
||||
match self.client.apply_extrinsic(&self.block_id, &mut self.changes, &xt) {
|
||||
Ok(result) => {
|
||||
match result {
|
||||
fn impl_push<'a, T, Block: BlockT>(
|
||||
api: &mut ApiRef<'a, T>,
|
||||
block_id: &BlockId<Block>,
|
||||
xt: Block::Extrinsic,
|
||||
extrinsics: &mut Vec<Block::Extrinsic>
|
||||
) -> error::Result<()> where T: BlockBuilderApi<Block> {
|
||||
api.map_api_result(|api| {
|
||||
match api.apply_extrinsic(block_id, &xt)? {
|
||||
Ok(ApplyOutcome::Success) | Ok(ApplyOutcome::Fail) => {
|
||||
self.extrinsics.push(xt);
|
||||
self.changes.commit_prospective();
|
||||
extrinsics.push(xt);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
self.changes.discard_prospective();
|
||||
Err(error::ErrorKind::ApplyExtinsicFailed(e).into())
|
||||
Err(error::ErrorKind::ApplyExtrinsicFailed(e).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.changes.discard_prospective();
|
||||
Err(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//FIXME: Please NLL, help me!
|
||||
impl_push(&mut self.api, &self.block_id, xt, &mut self.extrinsics)
|
||||
}
|
||||
|
||||
/// Consume the builder to return a valid `Block` containing all pushed extrinsics.
|
||||
pub fn bake(mut self) -> error::Result<Block> {
|
||||
self.header = self.client.finalise_block(&self.block_id, &mut self.changes)?;
|
||||
self.header = self.api.finalise_block(&self.block_id)?;
|
||||
|
||||
debug_assert_eq!(
|
||||
self.header.extrinsics_root().clone(),
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
//! Utility struct to build a block.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod block_builder;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::block_builder::*;
|
||||
pub mod api;
|
||||
@@ -40,6 +40,22 @@ pub trait HeaderBackend<Block: BlockT>: Send + Sync {
|
||||
fn expect_header(&self, id: BlockId<Block>) -> Result<Block::Header> {
|
||||
self.header(id)?.ok_or_else(|| ErrorKind::UnknownBlock(format!("{}", id)).into())
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
fn block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Option<Block::Hash>> {
|
||||
match *id {
|
||||
BlockId::Hash(h) => Ok(Some(h)),
|
||||
BlockId::Number(n) => self.hash(n),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
|
||||
match *id {
|
||||
BlockId::Hash(_) => Ok(self.header(*id)?.map(|h| h.number().clone())),
|
||||
BlockId::Number(n) => Ok(Some(n)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Blockchain database backend. Does not perform any validation.
|
||||
|
||||
@@ -27,7 +27,7 @@ use hash_db;
|
||||
use heapsize::HeapSizeOf;
|
||||
use trie;
|
||||
|
||||
use primitives::H256;
|
||||
use primitives::{H256, convert_hash};
|
||||
use runtime_primitives::traits::{As, Header as HeaderT, SimpleArithmetic, One};
|
||||
use state_machine::backend::InMemory as InMemoryState;
|
||||
use state_machine::{prove_read, read_proof_check};
|
||||
@@ -113,8 +113,7 @@ pub fn check_proof<Header, Hasher>(
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + HeapSizeOf,
|
||||
{
|
||||
let mut root: Hasher::Out = Default::default();
|
||||
root.as_mut().copy_from_slice(local_root.as_ref());
|
||||
let root: Hasher::Out = convert_hash(&local_root);
|
||||
let local_cht_key = encode_cht_key(local_number);
|
||||
let local_cht_value = read_proof_check::<Hasher>(root, remote_proof,
|
||||
&local_cht_key).map_err(|e| ClientError::from(e))?;
|
||||
|
||||
+219
-241
@@ -16,36 +16,40 @@
|
||||
|
||||
//! Substrate Client
|
||||
|
||||
use std::sync::Arc;
|
||||
use error::{Error, ErrorKind};
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use error::Error;
|
||||
use futures::sync::mpsc;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::{
|
||||
Justification,
|
||||
generic::{BlockId, SignedBlock, Block as RuntimeBlock},
|
||||
generic::{BlockId, SignedBlock},
|
||||
transaction_validity::{TransactionValidity, TransactionTag},
|
||||
};
|
||||
use consensus::{ImportBlock, ImportResult, BlockOrigin};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash};
|
||||
use runtime_primitives::{ApplyResult, BuildStorage};
|
||||
use runtime_api as api;
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration};
|
||||
use runtime_primitives::traits::{
|
||||
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash,
|
||||
ApiRef, ProvideRuntimeApi
|
||||
};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use runtime_api::{Core as CoreAPI, CallApiAt, TaggedTransactionQueue, ConstructRuntimeApi};
|
||||
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
use codec::{Encode, Decode};
|
||||
use codec::Decode;
|
||||
use state_machine::{
|
||||
Backend as StateBackend, CodeExecutor,
|
||||
Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
|
||||
ExecutionStrategy, ExecutionManager, prove_read,
|
||||
key_changes, key_changes_proof, OverlayedChanges
|
||||
};
|
||||
use codec::Encode;
|
||||
|
||||
use backend::{self, BlockImportOperation};
|
||||
use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend};
|
||||
use call_executor::{CallExecutor, LocalCallExecutor};
|
||||
use executor::{RuntimeVersion, RuntimeInfo};
|
||||
use notifications::{StorageNotifications, StorageEventStream};
|
||||
use {cht, error, in_mem, block_builder, genesis, consensus};
|
||||
use {cht, error, in_mem, block_builder::{self, api::BlockBuilder as BlockBuilderAPI}, genesis, consensus};
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -54,7 +58,7 @@ pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotific
|
||||
pub type FinalityNotifications<Block> = mpsc::UnboundedReceiver<FinalityNotification<Block>>;
|
||||
|
||||
/// Substrate Client
|
||||
pub struct Client<B, E, Block> where Block: BlockT {
|
||||
pub struct Client<B, E, Block, RA> where Block: BlockT {
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
storage_notifications: Mutex<StorageNotifications<Block>>,
|
||||
@@ -65,6 +69,7 @@ pub struct Client<B, E, Block> where Block: BlockT {
|
||||
block_execution_strategy: ExecutionStrategy,
|
||||
api_execution_strategy: ExecutionStrategy,
|
||||
changes_trie_config: Option<ChangesTrieConfiguration>,
|
||||
_phantom: PhantomData<RA>,
|
||||
}
|
||||
|
||||
/// A source of blockchain events.
|
||||
@@ -180,36 +185,36 @@ impl<H> PrePostHeader<H> {
|
||||
}
|
||||
|
||||
/// Create an instance of in-memory client.
|
||||
pub fn new_in_mem<E, Block, S>(
|
||||
pub fn new_in_mem<E, Block, S, RA>(
|
||||
executor: E,
|
||||
genesis_storage: S,
|
||||
) -> error::Result<Client<in_mem::Backend<Block, Blake2Hasher>, LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>, Block>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
) -> error::Result<Client<in_mem::Backend<Block, Blake2Hasher>, LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage)
|
||||
}
|
||||
|
||||
/// Create a client with the explicitely provided backend.
|
||||
/// This is useful for testing backend implementations.
|
||||
pub fn new_with_backend<B, E, Block, S>(
|
||||
pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
build_genesis_storage: S,
|
||||
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
B: backend::LocalBackend<Block, Blake2Hasher>
|
||||
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
B: backend::LocalBackend<Block, Blake2Hasher>
|
||||
{
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor);
|
||||
Client::new(backend, call_executor, build_genesis_storage, ExecutionStrategy::NativeWhenPossible, ExecutionStrategy::NativeWhenPossible)
|
||||
}
|
||||
|
||||
impl<B, E, Block> Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -255,6 +260,7 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
block_execution_strategy,
|
||||
api_execution_strategy,
|
||||
changes_trie_config,
|
||||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -323,6 +329,36 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
self.header_proof_with_cht_size(id, cht::SIZE)
|
||||
}
|
||||
|
||||
pub(crate) fn call_at_state(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
changes: &mut OverlayedChanges
|
||||
) -> error::Result<Vec<u8>> {
|
||||
let state = self.state_at(at)?;
|
||||
|
||||
let execution_manager = || match self.api_execution_strategy {
|
||||
ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
|
||||
ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm,
|
||||
ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| {
|
||||
warn!("Consensus error between wasm and native runtime execution at block {:?}", at);
|
||||
warn!(" Function {:?}", function);
|
||||
warn!(" Native result {:?}", native_result);
|
||||
warn!(" Wasm result {:?}", wasm_result);
|
||||
wasm_result
|
||||
}),
|
||||
};
|
||||
|
||||
self.executor.call_at_state(&state, changes, function, &args, execution_manager())
|
||||
.map(|res| res.0)
|
||||
}
|
||||
|
||||
/// Get block hash by number.
|
||||
pub fn block_hash(&self, block_number: <<Block as BlockT>::Header as HeaderT>::Number) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(block_number)
|
||||
}
|
||||
|
||||
/// Reads given header and generates CHT-based header proof for CHT of given size.
|
||||
pub fn header_proof_with_cht_size(&self, id: &BlockId<Block>, cht_size: u64) -> error::Result<(Block::Header, Vec<Vec<u8>>)> {
|
||||
let proof_error = || error::ErrorKind::Backend(format!("Failed to generate header proof for {:?}", id));
|
||||
@@ -355,7 +391,10 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
config,
|
||||
storage,
|
||||
self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
|
||||
self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&last),
|
||||
number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
|
||||
},
|
||||
self.backend.blockchain().info()?.best_number.as_(),
|
||||
key)
|
||||
.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
|
||||
@@ -388,7 +427,10 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
config,
|
||||
storage,
|
||||
self.require_block_number_from_id(&BlockId::Hash(first))?.as_(),
|
||||
self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&last),
|
||||
number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(),
|
||||
},
|
||||
max_number.as_(),
|
||||
key)
|
||||
.map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into())
|
||||
@@ -396,88 +438,41 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
|
||||
/// Create a new block, built on the head of the chain.
|
||||
pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
|
||||
where E: Clone
|
||||
pub fn new_block(
|
||||
&self
|
||||
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
|
||||
E: Clone + Send + Sync,
|
||||
RA: BlockBuilderAPI<Block>
|
||||
{
|
||||
block_builder::BlockBuilder::new(self)
|
||||
}
|
||||
|
||||
/// Create a new block, built on top of `parent`.
|
||||
pub fn new_block_at(&self, parent: &BlockId<Block>) -> error::Result<block_builder::BlockBuilder<B, E, Block, Blake2Hasher>>
|
||||
where E: Clone
|
||||
pub fn new_block_at(
|
||||
&self, parent: &BlockId<Block>
|
||||
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
|
||||
E: Clone + Send + Sync,
|
||||
RA: BlockBuilderAPI<Block>
|
||||
{
|
||||
block_builder::BlockBuilder::at_block(parent, &self)
|
||||
}
|
||||
|
||||
/// Set up the native execution environment to call into a native runtime code.
|
||||
pub fn call_api<A, R>(&self, function: &'static str, args: &A) -> error::Result<R>
|
||||
where A: Encode, R: Decode
|
||||
{
|
||||
self.call_api_at(&BlockId::Number(self.info()?.chain.best_number), function, args)
|
||||
}
|
||||
|
||||
/// Call a runtime function at given block.
|
||||
pub fn call_api_at<A, R>(&self, at: &BlockId<Block>, function: &'static str, args: &A) -> error::Result<R>
|
||||
where A: Encode, R: Decode
|
||||
{
|
||||
let parent = at;
|
||||
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
||||
self.block_number_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))? + As::sa(1),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
self.block_hash_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
|
||||
Default::default()
|
||||
);
|
||||
let mut overlay = Default::default();
|
||||
|
||||
self.call_at_state(at, "initialise_block", &header, &mut overlay)?;
|
||||
self.call_at_state(at, function, args, &mut overlay)
|
||||
}
|
||||
|
||||
fn call_at_state<A: Encode, R: Decode>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: &A,
|
||||
changes: &mut OverlayedChanges
|
||||
) -> error::Result<R> {
|
||||
let state = self.state_at(at)?;
|
||||
|
||||
let execution_manager = || match self.api_execution_strategy {
|
||||
ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible,
|
||||
ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm,
|
||||
ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| {
|
||||
warn!("Consensus error between wasm and native runtime execution at block {:?}", at);
|
||||
warn!(" Function {:?}", function);
|
||||
warn!(" Native result {:?}", native_result);
|
||||
warn!(" Wasm result {:?}", wasm_result);
|
||||
wasm_result
|
||||
}),
|
||||
};
|
||||
|
||||
self.executor.call_at_state(
|
||||
&state,
|
||||
changes,
|
||||
function,
|
||||
&args.encode(),
|
||||
execution_manager()
|
||||
).and_then(|res|
|
||||
R::decode(&mut &res.0[..])
|
||||
.ok_or_else(|| Error::from(ErrorKind::CallResultDecode(function)))
|
||||
)
|
||||
}
|
||||
|
||||
// TODO [ToDr] Optimize and re-use tags from the pool.
|
||||
fn transaction_tags(&self, at: Block::Hash, body: &Option<Vec<Block::Extrinsic>>) -> error::Result<Vec<TransactionTag>> {
|
||||
fn transaction_tags(
|
||||
&self,
|
||||
at: Block::Hash,
|
||||
body: &Option<Vec<Block::Extrinsic>>
|
||||
) -> error::Result<Vec<TransactionTag>> where
|
||||
RA: TaggedTransactionQueue<Block>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
||||
{
|
||||
let id = BlockId::Hash(at);
|
||||
Ok(match body {
|
||||
None => vec![],
|
||||
Some(ref extrinsics) => {
|
||||
let mut tags = vec![];
|
||||
for tx in extrinsics {
|
||||
let tx = api::TaggedTransactionQueue::validate_transaction(self, &id, &tx)?;
|
||||
let tx = self.runtime_api().validate_transaction(&id, &tx)?;
|
||||
match tx {
|
||||
TransactionValidity::Valid { mut provides, .. } => {
|
||||
tags.append(&mut provides);
|
||||
@@ -503,7 +498,10 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
authorities: Option<Vec<AuthorityId>>,
|
||||
finalized: bool,
|
||||
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
) -> error::Result<ImportResult> {
|
||||
) -> error::Result<ImportResult> where
|
||||
RA: TaggedTransactionQueue<Block>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
||||
{
|
||||
let parent_hash = import_headers.post().parent_hash().clone();
|
||||
match self.backend.blockchain().status(BlockId::Hash(hash))? {
|
||||
blockchain::BlockStatus::InChain => return Ok(ImportResult::AlreadyInChain),
|
||||
@@ -734,30 +732,9 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get block hash by number.
|
||||
pub fn block_hash(&self, block_number: <<Block as BlockT>::Header as HeaderT>::Number) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(block_number)
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
pub fn block_hash_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<Block::Hash>> {
|
||||
match *id {
|
||||
BlockId::Hash(h) => Ok(Some(h)),
|
||||
BlockId::Number(n) => self.block_hash(n),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash.
|
||||
pub fn block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<Option<NumberFor<Block>>> {
|
||||
match *id {
|
||||
BlockId::Hash(_) => Ok(self.header(id)?.map(|h| h.number().clone())),
|
||||
BlockId::Number(n) => Ok(Some(n)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an arbitrary block ID into a block hash, returning error if the block is unknown.
|
||||
fn require_block_number_from_id(&self, id: &BlockId<Block>) -> error::Result<NumberFor<Block>> {
|
||||
self.block_number_from_id(id)
|
||||
self.backend.blockchain().block_number_from_id(id)
|
||||
.and_then(|n| n.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{}", id)).into()))
|
||||
}
|
||||
|
||||
@@ -778,11 +755,11 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
|
||||
/// Get full block by id.
|
||||
pub fn block(&self, id: &BlockId<Block>)
|
||||
-> error::Result<Option<SignedBlock<Block::Header, Block::Extrinsic>>>
|
||||
-> error::Result<Option<SignedBlock<Block>>>
|
||||
{
|
||||
Ok(match (self.header(id)?, self.body(id)?, self.justification(id)?) {
|
||||
(Some(header), Some(extrinsics), Some(justification)) =>
|
||||
Some(SignedBlock { block: RuntimeBlock { header, extrinsics }, justification }),
|
||||
Some(SignedBlock { block: Block::new(header, extrinsics), justification }),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
@@ -895,11 +872,87 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> ChainHeaderBackend<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: Send + Sync
|
||||
{
|
||||
fn header(&self, id: BlockId<Block>) -> error::Result<Option<Block::Header>> {
|
||||
self.backend.blockchain().header(id)
|
||||
}
|
||||
|
||||
fn info(&self) -> error::Result<blockchain::Info<Block>> {
|
||||
self.backend.blockchain().info()
|
||||
}
|
||||
|
||||
fn status(&self, id: BlockId<Block>) -> error::Result<blockchain::BlockStatus> {
|
||||
self.backend.blockchain().status(id)
|
||||
}
|
||||
|
||||
fn number(&self, hash: Block::Hash) -> error::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
|
||||
self.backend.blockchain().number(hash)
|
||||
}
|
||||
|
||||
fn hash(&self, number: NumberFor<Block>) -> error::Result<Option<Block::Hash>> {
|
||||
self.backend.blockchain().hash(number)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: CoreAPI<Block>
|
||||
{
|
||||
type Api = RA;
|
||||
|
||||
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
|
||||
Self::Api::construct_runtime_api(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: Send + Sync,
|
||||
{
|
||||
fn call_api_at(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Vec<u8>> {
|
||||
//TODO: Find a better way to prevent double block initialization
|
||||
if function != "initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) {
|
||||
let parent = at;
|
||||
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
||||
self.block_number_from_id(parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?
|
||||
+ As::sa(1),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
self.block_hash_from_id(&parent)?
|
||||
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
|
||||
Default::default()
|
||||
);
|
||||
self.call_at_state(at, "initialise_block", header.encode(), changes)?;
|
||||
*initialised_block = Some(*at);
|
||||
}
|
||||
|
||||
self.call_at_state(at, function, args, changes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
|
||||
Block: BlockT<Hash=H256>,
|
||||
RA: TaggedTransactionQueue<Block>
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
@@ -914,8 +967,8 @@ impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
let ImportBlock {
|
||||
origin,
|
||||
header,
|
||||
external_justification,
|
||||
post_runtime_digests,
|
||||
justification,
|
||||
post_digests,
|
||||
body,
|
||||
finalized,
|
||||
auxiliary,
|
||||
@@ -927,11 +980,11 @@ impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
|
||||
}
|
||||
|
||||
let import_headers = if post_runtime_digests.is_empty() {
|
||||
let import_headers = if post_digests.is_empty() {
|
||||
PrePostHeader::Same(header)
|
||||
} else {
|
||||
let mut post_header = header.clone();
|
||||
for item in post_runtime_digests {
|
||||
for item in post_digests {
|
||||
post_header.digest_mut().push(item);
|
||||
}
|
||||
PrePostHeader::Different(header, post_header)
|
||||
@@ -946,7 +999,7 @@ impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
origin,
|
||||
hash,
|
||||
import_headers,
|
||||
external_justification,
|
||||
justification,
|
||||
body,
|
||||
new_authorities,
|
||||
finalized,
|
||||
@@ -963,7 +1016,7 @@ impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> consensus::Authorities<Block> for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> consensus::Authorities<Block> for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -974,7 +1027,7 @@ impl<B, E, Block> consensus::Authorities<Block> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> CurrentHeight for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -985,7 +1038,7 @@ impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
|
||||
impl<B, E, Block, RA> BlockNumberToHash for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -998,7 +1051,7 @@ impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>
|
||||
impl<B, E, Block, RA> BlockchainEvents<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
@@ -1022,7 +1075,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> ChainHead<Block> for Client<B, E, Block>
|
||||
impl<B, E, Block, RA> ChainHead<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
@@ -1033,116 +1086,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> BlockBody<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
impl<B, E, Block, RA> BlockBody<Block> for Client<B, E, Block, RA>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
fn block_body(&self, id: &BlockId<Block>) -> error::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
||||
self.body(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Core<Block, AuthorityId> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, Self::Error> {
|
||||
self.call_api_at(at, "version", &())
|
||||
}
|
||||
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, Self::Error> {
|
||||
self.authorities_at(at)
|
||||
}
|
||||
|
||||
fn execute_block(&self, at: &BlockId<Block>, block: &Block) -> Result<(), Self::Error> {
|
||||
self.call_api_at(at, "execute_block", &(block))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Metadata<Block, Vec<u8>> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn metadata(&self, at: &BlockId<Block>) -> Result<Vec<u8>, Self::Error> {
|
||||
self.executor.call(at, "metadata",&[]).map(|v| v.return_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::BlockBuilder<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
type OverlayedChanges = OverlayedChanges;
|
||||
|
||||
fn initialise_block(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
changes: &mut OverlayedChanges,
|
||||
header: &<Block as BlockT>::Header
|
||||
) -> Result<(), Self::Error> {
|
||||
self.call_at_state(at, "initialise_block", header, changes)
|
||||
}
|
||||
|
||||
fn apply_extrinsic(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
changes: &mut OverlayedChanges,
|
||||
extrinsic: &<Block as BlockT>::Extrinsic
|
||||
) -> Result<ApplyResult, Self::Error> {
|
||||
self.call_at_state(at, "apply_extrinsic", extrinsic, changes)
|
||||
}
|
||||
|
||||
fn finalise_block(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
changes: &mut OverlayedChanges
|
||||
) -> Result<<Block as BlockT>::Header, Self::Error> {
|
||||
self.call_at_state(at, "finalise_block", &(), changes)
|
||||
}
|
||||
|
||||
fn inherent_extrinsics<InherentExtrinsic: Encode + Decode, UncheckedExtrinsic: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>, inherent: &InherentExtrinsic
|
||||
) -> Result<Vec<UncheckedExtrinsic>, Self::Error> {
|
||||
self.call_api_at(at, "inherent_extrinsics", &(inherent))
|
||||
}
|
||||
|
||||
fn check_inherents<InherentData: Encode + Decode, InherentError: Encode + Decode>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
block: &Block,
|
||||
data: &InherentData
|
||||
) -> Result<Result<(), InherentError>, Self::Error> {
|
||||
self.call_api_at(at, "check_inherents", &(block, data))
|
||||
}
|
||||
|
||||
fn random_seed(&self, at: &BlockId<Block>) -> Result<<Block as BlockT>::Hash, Self::Error> {
|
||||
self.call_api_at(at, "random_seed", &())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::TaggedTransactionQueue<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn validate_transaction<TransactionValidity: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>, tx: &<Block as BlockT>::Extrinsic
|
||||
) -> Result<TransactionValidity, Self::Error> {
|
||||
self.call_api_at(at, "validate_transaction", &(tx))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::collections::HashMap;
|
||||
@@ -1155,14 +1109,14 @@ pub(crate) mod tests {
|
||||
use consensus::BlockOrigin;
|
||||
use test_client::client::backend::Backend as TestBackend;
|
||||
use test_client::BlockBuilderExt;
|
||||
use test_client::runtime::{self, Block, Transfer};
|
||||
use test_client::runtime::{self, Block, Transfer, ClientWithApi, test_api::TestAPI};
|
||||
|
||||
/// Returns tuple, consisting of:
|
||||
/// 1) test client pre-filled with blocks changing balances;
|
||||
/// 2) roots of changes tries for these blocks
|
||||
/// 3) test cases in form (begin, end, key, vec![(block, extrinsic)]) that are required to pass
|
||||
pub fn prepare_client_with_key_changes() -> (
|
||||
test_client::client::Client<test_client::Backend, test_client::Executor, Block>,
|
||||
test_client::client::Client<test_client::Backend, test_client::Executor, Block, ClientWithApi>,
|
||||
Vec<H256>,
|
||||
Vec<(u64, u64, Vec<u8>, Vec<(u64, u32)>)>,
|
||||
) {
|
||||
@@ -1234,8 +1188,20 @@ pub(crate) mod tests {
|
||||
fn client_initialises_from_genesis_ok() {
|
||||
let client = test_client::new();
|
||||
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Alice.to_raw_public()).unwrap(), 1000);
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Ferdie.to_raw_public()).unwrap(), 0);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Alice.to_raw_public()
|
||||
).unwrap(),
|
||||
1000
|
||||
);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Ferdie.to_raw_public()
|
||||
).unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1278,8 +1244,20 @@ pub(crate) mod tests {
|
||||
|
||||
assert_eq!(client.info().unwrap().chain.best_number, 1);
|
||||
assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap());
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Alice.to_raw_public()).unwrap(), 958);
|
||||
assert_eq!(client.call_api::<_, u64>("balance_of", &Keyring::Ferdie.to_raw_public()).unwrap(), 42);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Alice.to_raw_public()
|
||||
).unwrap(),
|
||||
958
|
||||
);
|
||||
assert_eq!(
|
||||
client.runtime_api().balance_of(
|
||||
&BlockId::Number(client.info().unwrap().chain.best_number),
|
||||
&Keyring::Ferdie.to_raw_public()
|
||||
).unwrap(),
|
||||
42
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -41,7 +41,7 @@ error_chain! {
|
||||
}
|
||||
|
||||
/// Applying extrinsic error.
|
||||
ApplyExtinsicFailed(e: ApplyError) {
|
||||
ApplyExtrinsicFailed(e: ApplyError) {
|
||||
description("Extrinsic error"),
|
||||
display("Extrinsic error: {:?}", e),
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ mod tests {
|
||||
use trie::ordered_trie_root;
|
||||
|
||||
let transactions = txs.into_iter().map(|tx| {
|
||||
let signature = Pair::from(Keyring::from_public(Public::from_raw(tx.from.0)).unwrap())
|
||||
let signature = Pair::from(Keyring::from_public(Public::from_raw(tx.from.to_fixed_bytes())).unwrap())
|
||||
.sign(&tx.encode()).into();
|
||||
|
||||
Extrinsic { transfer: tx, signature }
|
||||
|
||||
@@ -14,64 +14,103 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Substrate Client and associated logic.
|
||||
// end::description[]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![warn(missing_docs)]
|
||||
#![recursion_limit="128"]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate substrate_trie as trie;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate substrate_state_machine as state_machine;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate substrate_consensus_common as consensus;
|
||||
#[cfg(test)] extern crate substrate_keyring as keyring;
|
||||
#[cfg(test)] extern crate substrate_test_client as test_client;
|
||||
#[macro_use] extern crate substrate_telemetry;
|
||||
#[macro_use] extern crate slog; // needed until we can reexport `slog_info` from `substrate_telemetry`
|
||||
extern crate sr_version as runtime_version;
|
||||
extern crate sr_std as rstd;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_keyring as keyring;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_test_client as test_client;
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate substrate_telemetry;
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate slog; // needed until we can reexport `slog_info` from `substrate_telemetry`
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate fnv;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate futures;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate parking_lot;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate hash_db;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate heapsize;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate kvdb;
|
||||
extern crate sr_api;
|
||||
|
||||
#[macro_use] extern crate error_chain;
|
||||
#[macro_use] extern crate log;
|
||||
#[cfg_attr(test, macro_use)] extern crate substrate_executor as executor;
|
||||
#[cfg(test)] #[macro_use] extern crate hex_literal;
|
||||
#[cfg(test)] extern crate kvdb_memorydb;
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(test, macro_use)]
|
||||
extern crate substrate_executor as executor;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_memorydb;
|
||||
|
||||
#[macro_use]
|
||||
pub mod runtime_api;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod error;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod blockchain;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod backend;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod cht;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod in_mem;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod genesis;
|
||||
pub mod block_builder;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod light;
|
||||
#[cfg(feature = "std")]
|
||||
mod leaves;
|
||||
#[cfg(feature = "std")]
|
||||
mod call_executor;
|
||||
#[cfg(feature = "std")]
|
||||
mod client;
|
||||
#[cfg(feature = "std")]
|
||||
mod notifications;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use blockchain::Info as ChainInfo;
|
||||
#[cfg(feature = "std")]
|
||||
pub use call_executor::{CallResult, CallExecutor, LocalCallExecutor};
|
||||
#[cfg(feature = "std")]
|
||||
pub use client::{
|
||||
new_with_backend,
|
||||
new_in_mem,
|
||||
BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents,
|
||||
Client, ClientInfo, ChainHead,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
pub use notifications::{StorageEventStream, StorageChangeSet};
|
||||
#[cfg(feature = "std")]
|
||||
pub use state_machine::ExecutionStrategy;
|
||||
#[cfg(feature = "std")]
|
||||
pub use leaves::LeafSet;
|
||||
|
||||
/// Traits for interfacing with the runtime from the client.
|
||||
pub mod runtime_api {
|
||||
pub use sr_api::*;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use futures::{IntoFuture, Future};
|
||||
|
||||
use primitives::convert_hash;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
|
||||
use state_machine::{Backend as StateBackend, CodeExecutor, OverlayedChanges,
|
||||
@@ -136,8 +137,7 @@ pub fn check_execution_proof<Header, E, H>(
|
||||
|
||||
{
|
||||
let local_state_root = request.header.state_root();
|
||||
let mut root: H::Out = Default::default();
|
||||
root.as_mut().copy_from_slice(local_state_root.as_ref());
|
||||
let root: H::Out = convert_hash(&local_state_root);
|
||||
|
||||
let mut changes = OverlayedChanges::default();
|
||||
let local_result = execution_proof_check::<H, _>(
|
||||
|
||||
@@ -21,10 +21,10 @@ use futures::IntoFuture;
|
||||
|
||||
use hash_db::Hasher;
|
||||
use heapsize::HeapSizeOf;
|
||||
use primitives::ChangesTrieConfiguration;
|
||||
use primitives::{ChangesTrieConfiguration, convert_hash};
|
||||
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberFor};
|
||||
use state_machine::{CodeExecutor, ChangesTrieRootsStorage, read_proof_check,
|
||||
key_changes_proof_check};
|
||||
use state_machine::{CodeExecutor, ChangesTrieRootsStorage, ChangesTrieAnchorBlockId,
|
||||
read_proof_check, key_changes_proof_check};
|
||||
|
||||
use call_executor::CallResult;
|
||||
use cht;
|
||||
@@ -192,9 +192,8 @@ impl<E, Block, H> FetchChecker<Block> for LightDataChecker<E, H>
|
||||
request: &RemoteReadRequest<Block::Header>,
|
||||
remote_proof: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
let mut root: H::Out = Default::default();
|
||||
root.as_mut().copy_from_slice(request.header.state_root().as_ref());
|
||||
read_proof_check::<H>(root, remote_proof, &request.key).map_err(Into::into)
|
||||
read_proof_check::<H>(convert_hash(request.header.state_root()), remote_proof, &request.key)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn check_execution_proof(
|
||||
@@ -229,7 +228,10 @@ impl<E, Block, H> FetchChecker<Block> for LightDataChecker<E, H>
|
||||
},
|
||||
remote_proof,
|
||||
first_number,
|
||||
request.last_block.0.as_(),
|
||||
&ChangesTrieAnchorBlockId {
|
||||
hash: convert_hash(&request.last_block.1),
|
||||
number: request.last_block.0.as_(),
|
||||
},
|
||||
remote_max.as_(),
|
||||
&request.key)
|
||||
.map(|pairs| pairs.into_iter().map(|(b, x)| (As::sa(b), x)).collect())
|
||||
@@ -248,15 +250,12 @@ impl<'a, H, Hash> ChangesTrieRootsStorage<H> for RootsStorage<'a, Hash>
|
||||
H: Hasher,
|
||||
Hash: 'a + Send + Sync + Clone + AsRef<[u8]>,
|
||||
{
|
||||
fn root(&self, block: u64) -> Result<Option<H::Out>, String> {
|
||||
fn root(&self, _anchor: &ChangesTrieAnchorBlockId<H::Out>, block: u64) -> Result<Option<H::Out>, String> {
|
||||
// we can't ask for roots from parallel forks here => ignore anchor
|
||||
Ok(block.checked_sub(self.first)
|
||||
.and_then(|index| self.roots.get(index as usize))
|
||||
.cloned()
|
||||
.map(|root| {
|
||||
let mut hasher_root: H::Out = Default::default();
|
||||
hasher_root.as_mut().copy_from_slice(root.as_ref());
|
||||
hasher_root
|
||||
}))
|
||||
.map(|root| convert_hash(&root)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +477,7 @@ pub mod tests {
|
||||
assert!(local_checker.check_changes_proof(&request, remote_max + 1, remote_proof.clone()).is_err());
|
||||
|
||||
// check proof on local client using broken proof
|
||||
remote_proof = local_roots_range.into_iter().map(|v| v.to_vec()).collect();
|
||||
remote_proof = local_roots_range.into_iter().map(|v| v.as_bytes().to_vec()).collect();
|
||||
assert!(local_checker.check_changes_proof(&request, remote_max, remote_proof).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ pub fn new_light_backend<B: BlockT, S: BlockchainStorage<B>, F: Fetcher<B>>(bloc
|
||||
}
|
||||
|
||||
/// Create an instance of light client.
|
||||
pub fn new_light<B, S, F, GS>(
|
||||
pub fn new_light<B, S, F, GS, RA>(
|
||||
backend: Arc<Backend<S, F>>,
|
||||
fetcher: Arc<F>,
|
||||
genesis_storage: GS,
|
||||
) -> ClientResult<Client<Backend<S, F>, RemoteCallExecutor<Blockchain<S, F>, F, Blake2Hasher>, B>>
|
||||
) -> ClientResult<Client<Backend<S, F>, RemoteCallExecutor<Blockchain<S, F>, F, Blake2Hasher>, B, RA>>
|
||||
where
|
||||
B: BlockT<Hash=H256>,
|
||||
S: BlockchainStorage<B>,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use super::{ConstructRuntimeApi, ApiExt};
|
||||
use runtime_version::RuntimeVersion;
|
||||
use runtime_primitives::traits::Block as BlockT;
|
||||
#[cfg(feature = "std")]
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use primitives::AuthorityId;
|
||||
#[cfg(feature = "std")]
|
||||
use error::Result;
|
||||
use rstd::vec::Vec;
|
||||
|
||||
/// The `Core` api trait that is mandantory for each runtime.
|
||||
/// This is the side that should be implemented for the `RuntimeApi` that is used by the `Client`.
|
||||
/// Any modifications at one of these two traits, needs to be done on the other one as well.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait Core<Block: BlockT>: 'static + Send + Sync + ConstructRuntimeApi<Block> + ApiExt {
|
||||
/// Returns the version of the runtime.
|
||||
fn version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion>;
|
||||
/// Returns the authorities.
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>>;
|
||||
/// Execute the given block.
|
||||
fn execute_block(&self, at: &BlockId<Block>, block: &Block) -> Result<()>;
|
||||
/// Initialise a block with the given header.
|
||||
fn initialise_block(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
header: &<Block as BlockT>::Header
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
pub mod runtime {
|
||||
use super::*;
|
||||
|
||||
/// The `Core` api trait that is mandantory for each runtime.
|
||||
/// This is the side that should be implemented for the `Runtime`.
|
||||
pub trait Core<Block: BlockT> {
|
||||
/// Returns the version of the runtime.
|
||||
fn version() -> RuntimeVersion;
|
||||
/// Returns the authorities.
|
||||
fn authorities() -> Vec<AuthorityId>;
|
||||
/// Execute the given block.
|
||||
fn execute_block(block: Block);
|
||||
/// Initialise a block with the given header.
|
||||
fn initialise_block(header: <Block as BlockT>::Header);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
//! Macros for declaring and implementing the runtime APIs.
|
||||
|
||||
// these are part of the public API, so need to be re-exported
|
||||
pub use runtime_version::{ApiId, RuntimeVersion};
|
||||
|
||||
/// Declare the given API traits.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// decl_runtime_apis!{
|
||||
/// pub trait Test<Event> ExtraClientSide<ClientArg> {
|
||||
/// fn test<AccountId>(event: Event) -> AccountId;
|
||||
///
|
||||
/// /// A function that will have the extra parameter `param` on the client side,
|
||||
/// /// the runtime does not have any parameter.
|
||||
/// fn testWithExtraParams() ExtraClientSide(param: &Self::ClientArg);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Will result in the following declaration:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// mod runtime {
|
||||
/// pub trait Test<Event, AccountId> {
|
||||
/// fn test(event: Event) -> AccountId;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// pub trait Test<Block: BlockT, Event> {
|
||||
/// type Error;
|
||||
/// type ClientArg;
|
||||
/// fn test<AccountId: Encode + Decode>(&self, at: &BlockId<Block>, event: Event) -> Result<Event, Self::Error>;
|
||||
/// fn testWithExtraParams(&self, at: &BlockId<Block>, param: &Client) -> Result<Event, Self::Error>;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The declarations generated in the `runtime` module will be used by `impl_runtime_apis!` for implementing
|
||||
/// the traits for a runtime. The other declarations should be used for implementing the interface
|
||||
/// in the client.
|
||||
#[macro_export]
|
||||
macro_rules! decl_runtime_apis {
|
||||
(
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param:ident $( : $generic_bound:ident )* ),* >)*
|
||||
$( ExtraClientSide < $( $client_generic_param:ident $( : $client_generic_bound:ident )* ),+ > )*
|
||||
{
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty ),*
|
||||
)
|
||||
$( ExtraClientSide ( $( $client_param_name:ident : $client_param_type:ty ),+ ) )*
|
||||
$( -> $return_ty:ty)*;
|
||||
)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
decl_runtime_apis!(
|
||||
@ADD_BLOCK_GENERIC
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param $( : $generic_bound )* ),* >)* {
|
||||
$( $( type $client_generic_param $( : $client_generic_bound )*; )* )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $( $client_param_name: $client_param_type, )* )*
|
||||
$( $param_name : &$param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
;
|
||||
;
|
||||
$( $( $generic_param $( : $generic_bound )* ),* )*
|
||||
);
|
||||
)*
|
||||
decl_runtime_apis! {
|
||||
@GENERATE_RUNTIME_TRAITS
|
||||
$(
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param $( : $generic_bound )* ),* >)* {
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* ($( $param_name : $param_type )* ) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
)*
|
||||
}
|
||||
};
|
||||
(@ADD_BLOCK_GENERIC
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
;
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:ident )* ),*;
|
||||
Block: BlockT
|
||||
$(, $generic_param_rest:ident $( : $generic_bound_rest:ident )* )*
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@ADD_BLOCK_GENERIC
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
Found;
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* , )* Block: $crate::runtime_api::BlockT;
|
||||
$( $generic_param_rest $( : $generic_bound_rest )* ),*
|
||||
);
|
||||
};
|
||||
(@ADD_BLOCK_GENERIC
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty )*;
|
||||
)*
|
||||
};
|
||||
$( $block_found:ident )*;
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
$generic_param:ident $( : $generic_bound:ident )*
|
||||
$(, $generic_param_rest:ident $( : $generic_bound_rest:ident )* )*
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@ADD_BLOCK_GENERIC
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
$( $block_found )*;
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* , )* $generic_param $( : $generic_bound )*;
|
||||
$( $generic_param_rest $( : $generic_bound_rest )* ),*
|
||||
);
|
||||
};
|
||||
(@ADD_BLOCK_GENERIC
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty )*;
|
||||
)*
|
||||
};
|
||||
Found;
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@GENERATE_RETURN_TYPES
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* ),*;
|
||||
{};
|
||||
$( $( $return_ty )*; )*
|
||||
);
|
||||
};
|
||||
(@ADD_BLOCK_GENERIC
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty )*;
|
||||
)*
|
||||
};
|
||||
;
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:ident )* ),*;
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@GENERATE_RETURN_TYPES
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
// We need to add the required generic Block parameter
|
||||
Block: $crate::runtime_api::BlockT $(, $generic_param_parsed $( : $generic_bound_parsed )* )*;
|
||||
{};
|
||||
$( $( $return_ty )*; )*
|
||||
);
|
||||
};
|
||||
(@GENERATE_RETURN_TYPES
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
{ $( $result_return_ty:ty; )* };
|
||||
$return_ty_current:ty;
|
||||
$( $( $return_ty_rest:ty )*; )*
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@GENERATE_RETURN_TYPES
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* ),*;
|
||||
{ $( $result_return_ty; )* $crate::error::Result<$return_ty_current>; };
|
||||
$( $( $return_ty_rest )*; )*
|
||||
);
|
||||
};
|
||||
(@GENERATE_RETURN_TYPES
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
{ $( $result_return_ty:ty; )* };
|
||||
;
|
||||
$( $( $return_ty_rest:ty )*; )*
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@GENERATE_RETURN_TYPES
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* ),*;
|
||||
{ $( $result_return_ty; )* $crate::error::Result<()>; };
|
||||
$( $( $return_ty_rest )*; )*
|
||||
);
|
||||
};
|
||||
(@GENERATE_RETURN_TYPES
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
{ $( $result_return_ty:ty; )* };
|
||||
) => {
|
||||
decl_runtime_apis!(
|
||||
@GENERATE_CLIENT_TRAITS
|
||||
$( #[$attr] )*
|
||||
pub trait $name $(< $( $generic_param_orig $( : $generic_bound_orig )* ),* >)* {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic ),* > )* (
|
||||
$( $param_name : $param_type, )*
|
||||
) $( -> $return_ty )*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed $( : $generic_bound_parsed )* ),*;
|
||||
{ $( $result_return_ty; )* };
|
||||
);
|
||||
};
|
||||
(@GENERATE_CLIENT_TRAITS
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param_orig:ident $( : $generic_bound_orig:ident )* ),* >)* {
|
||||
$( type $client_generic_param:ident $( : $client_generic_bound:ident )*; )*
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty, )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
$( $generic_param_parsed:ident $( : $generic_bound_parsed:path )* ),*;
|
||||
{ $( $result_return_ty:ty; )* };
|
||||
) => {
|
||||
$( #[$attr] )*
|
||||
#[cfg(feature = "std")]
|
||||
pub trait $name < $( $generic_param_parsed $( : $generic_bound_parsed )* ),* > : $crate::runtime_api::Core<Block> {
|
||||
$( type $client_generic_param $( : $client_generic_bound )*; )*
|
||||
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name $( < $( $fn_generic: $crate::runtime_api::Encode + $crate::runtime_api::Decode ),* > )* (
|
||||
&self, at: &$crate::runtime_api::BlockId<Block> $(, $param_name: $param_type )*
|
||||
) -> $result_return_ty;
|
||||
)*
|
||||
}
|
||||
};
|
||||
(@GENERATE_RUNTIME_TRAITS
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident $(< $( $generic_param:ident $( : $generic_bound:ident )* ),* >)* {
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident $( < $( $fn_generic:ident ),* > )* (
|
||||
$( $param_name:ident : $param_type:ty )*
|
||||
) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
};
|
||||
)*
|
||||
) => {
|
||||
decl_runtime_apis! {
|
||||
@GENERATE_RUNTIME_TRAITS_WITH_JOINED_GENERICS
|
||||
$(
|
||||
$( #[$attr] )*
|
||||
pub trait $name < $( $( $generic_param $( : $generic_bound )*, )* )* $( $( $( $fn_generic, )* )* )* > {
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name ($( $param_name: $param_type ),*) $( -> $return_ty )*;
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
(@GENERATE_RUNTIME_TRAITS_WITH_JOINED_GENERICS
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
pub trait $name:ident < $( $generic_param:ident $( : $generic_bound:ident )*, )* > {
|
||||
$(
|
||||
$( #[$fn_attr:meta] )*
|
||||
fn $fn_name:ident($( $param_name:ident : $param_type:ty ),*) $( -> $return_ty:ty)*;
|
||||
)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
/// The API traits to implement on the runtime side.
|
||||
pub mod runtime {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
$( #[$attr] )*
|
||||
pub trait $name < $( $generic_param $( : $generic_bound )* ),* > {
|
||||
$(
|
||||
$( #[$fn_attr] )*
|
||||
fn $fn_name ($( $param_name: $param_type ),*) $( -> $return_ty )*;
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement the given API's for the given runtime.
|
||||
/// All desired API's need to be implemented in one `impl_runtime_apis!` call.
|
||||
/// Besides generating the implementation for the runtime, there will be also generated an
|
||||
/// auxiliary module named `api` that contains function for inferring with the API in native/wasm.
|
||||
/// It is important to use the traits from the `runtime` module with this macro.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// #[macro_use]
|
||||
/// extern crate substrate_client as client;
|
||||
///
|
||||
/// use client::runtime_api::runtime::{Core, TaggedTransactionQueue};
|
||||
///
|
||||
/// impl_runtime_apis! {
|
||||
/// impl Core<Block> for Runtime {
|
||||
/// fn version() -> RuntimeVersion { unimplemented!() }
|
||||
/// fn authorities() -> Vec<AuthorityId> { unimplemented!() }
|
||||
/// fn execute_block(block: Block) {
|
||||
/// //comment
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl TaggedTransactionQueue<Block> for Runtime {
|
||||
/// fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! impl_runtime_apis {
|
||||
(
|
||||
impl $trait_name:ident $( < $( $generic:ident ),* > )* for $runtime:ident {
|
||||
$(
|
||||
fn $fn_name:ident ( $( $arg_name:ident : $arg_ty:ty ),* ) $( -> $return_ty:ty )* {
|
||||
$( $impl:tt )*
|
||||
}
|
||||
)*
|
||||
}
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
impl $trait_name $( < $( $generic ),* > )* for $runtime {
|
||||
$(
|
||||
fn $fn_name ( $( $arg_name : $arg_ty ),* ) $( -> $return_ty )* {
|
||||
$( $impl )*
|
||||
}
|
||||
)*
|
||||
}
|
||||
impl_runtime_apis! {
|
||||
$runtime;
|
||||
$( $fn_name ( $( $arg_name: $arg_ty ),* ); )*;
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
(
|
||||
$runtime:ident;
|
||||
$( $fn_name_parsed:ident ( $( $arg_name_parsed:ident : $arg_ty_parsed:ty ),* ); )*;
|
||||
impl $trait_name:ident $( < $( $generic:ident ),* > )* for $runtime_ignore:ident {
|
||||
$(
|
||||
fn $fn_name:ident ( $( $arg_name:ident : $arg_ty:ty ),* ) $( -> $return_ty:ty )* {
|
||||
$( $impl:tt )*
|
||||
}
|
||||
)*
|
||||
}
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
impl $trait_name $( < $( $generic ),* > )* for $runtime {
|
||||
$(
|
||||
fn $fn_name ( $( $arg_name : $arg_ty ),* ) $( -> $return_ty )* {
|
||||
$( $impl )*
|
||||
}
|
||||
)*
|
||||
}
|
||||
impl_runtime_apis! {
|
||||
$runtime;
|
||||
$( $fn_name_parsed ( $( $arg_name_parsed: $arg_ty_parsed ),* ); )*
|
||||
$( $fn_name ( $( $arg_name: $arg_ty ),* ); )*;
|
||||
$( $rest )*
|
||||
}
|
||||
};
|
||||
(
|
||||
$runtime:ident;
|
||||
$( $fn_name:ident ( $( $arg_name:ident : $arg_ty:ty ),* ); )*;
|
||||
) => {
|
||||
pub mod api {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn dispatch(method: &str, mut data: &[u8]) -> Option<Vec<u8>> {
|
||||
match method {
|
||||
$(
|
||||
stringify!($fn_name) => {
|
||||
Some({impl_runtime_apis! {
|
||||
@GENERATE_IMPL_CALL
|
||||
$runtime;
|
||||
$fn_name;
|
||||
$( $arg_name : $arg_ty ),*;
|
||||
data;
|
||||
}})
|
||||
}
|
||||
)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[no_mangle]
|
||||
pub fn $fn_name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
let mut input = if input_len == 0 {
|
||||
&[0u8; 0]
|
||||
} else {
|
||||
unsafe {
|
||||
$crate::runtime_api::slice::from_raw_parts(input_data, input_len)
|
||||
}
|
||||
};
|
||||
|
||||
let output = { impl_runtime_apis! {
|
||||
@GENERATE_IMPL_CALL
|
||||
$runtime;
|
||||
$fn_name;
|
||||
$( $arg_name : $arg_ty ),*;
|
||||
input;
|
||||
} };
|
||||
let res = output.as_ptr() as u64 + ((output.len() as u64) << 32);
|
||||
|
||||
// Leak the output vector to avoid it being freed.
|
||||
// This is fine in a WASM context since the heap
|
||||
// will be discarded after the call.
|
||||
::core::mem::forget(output);
|
||||
res
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
(@GENERATE_IMPL_CALL
|
||||
$runtime:ident;
|
||||
$fn_name:ident;
|
||||
$arg_name:ident : $arg_ty:ty;
|
||||
$input:ident;
|
||||
) => {
|
||||
let $arg_name : $arg_ty = match $crate::runtime_api::Decode::decode(&mut $input) {
|
||||
Some(input) => input,
|
||||
None => panic!("Bad input data provided to {}", stringify!($fn_name)),
|
||||
};
|
||||
|
||||
let output = $runtime::$fn_name($arg_name);
|
||||
$crate::runtime_api::Encode::encode(&output)
|
||||
};
|
||||
(@GENERATE_IMPL_CALL
|
||||
$runtime:ident;
|
||||
$fn_name:ident;
|
||||
$( $arg_name:ident : $arg_ty:ty ),*;
|
||||
$input:ident;
|
||||
) => {
|
||||
let ( $( $arg_name ),* ) : ($( $arg_ty ),*) = match $crate::runtime_api::Decode::decode(&mut $input) {
|
||||
Some(input) => input,
|
||||
None => panic!("Bad input data provided to {}", stringify!($fn_name)),
|
||||
};
|
||||
|
||||
let output = $runtime::$fn_name($( $arg_name ),*);
|
||||
$crate::runtime_api::Encode::encode(&output)
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
//! All the functionality required for declaring and implementing runtime api's.
|
||||
//! Core api's are also declared here.
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use state_machine::OverlayedChanges;
|
||||
#[doc(hidden)]
|
||||
pub use runtime_primitives::{traits::Block as BlockT, generic::BlockId};
|
||||
#[cfg(feature = "std")]
|
||||
use runtime_primitives::traits::ApiRef;
|
||||
pub use runtime_version::ApiId;
|
||||
#[doc(hidden)]
|
||||
pub use rstd::slice;
|
||||
#[cfg(feature = "std")]
|
||||
use rstd::result;
|
||||
pub use codec::{Encode, Decode};
|
||||
#[cfg(feature = "std")]
|
||||
use error;
|
||||
|
||||
mod core;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod traits;
|
||||
|
||||
/// Something that can be constructed to a runtime api.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait ConstructRuntimeApi<Block: BlockT>: Sized {
|
||||
/// Construct an instance of the runtime api.
|
||||
fn construct_runtime_api<'a, T: CallApiAt<Block>>(call: &'a T) -> ApiRef<'a, Self>;
|
||||
}
|
||||
|
||||
/// An extension for the `RuntimeApi`.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait ApiExt {
|
||||
/// The given closure will be called with api instance. Inside the closure any api call is
|
||||
/// allowed. After doing the api call, the closure is allowed to map the `Result` to a
|
||||
/// different `Result` type. This can be important, as the internal data structure that keeps
|
||||
/// track of modifications to the storage, discards changes when the `Result` is an `Err`.
|
||||
/// On `Ok`, the structure commits the changes to an internal buffer.
|
||||
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
|
||||
&self,
|
||||
map_call: F
|
||||
) -> result::Result<R, E>;
|
||||
}
|
||||
|
||||
/// Something that can call the runtime api at a given block.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait CallApiAt<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(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Vec<u8>>;
|
||||
|
||||
/// Call the given api function with strong arguments at the given block
|
||||
/// and returns the decoded result.
|
||||
fn call_api_at_strong<In: Encode, Out: Decode>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
function: &'static str,
|
||||
args: &In,
|
||||
changes: &mut OverlayedChanges,
|
||||
initialised_block: &mut Option<BlockId<Block>>,
|
||||
) -> error::Result<Out> where Self: Sized {
|
||||
let raw = self.call_api_at(
|
||||
at,
|
||||
function,
|
||||
args.encode(),
|
||||
changes,
|
||||
initialised_block,
|
||||
)?;
|
||||
|
||||
match Out::decode(&mut &raw[..]) {
|
||||
Some(out) => Ok(out),
|
||||
None => bail!(error::ErrorKind::CallResultDecode(function)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ApiIds for the various standard runtime APIs.
|
||||
pub mod id {
|
||||
use super::ApiId;
|
||||
|
||||
/// ApiId for the BlockBuilder trait.
|
||||
pub const BLOCK_BUILDER: ApiId = *b"blkbuild";
|
||||
|
||||
/// ApiId for the TaggedTransactionQueue trait.
|
||||
pub const TAGGED_TRANSACTION_QUEUE: ApiId = *b"validatx";
|
||||
|
||||
/// ApiId for the Metadata trait.
|
||||
pub const METADATA: ApiId = *b"metadata";
|
||||
}
|
||||
|
||||
pub use self::core::*;
|
||||
pub use self::traits::*;
|
||||
|
||||
/// The runtime apis that should be implemented for the `Runtime`.
|
||||
pub mod runtime {
|
||||
pub use super::core::runtime::Core;
|
||||
pub use super::traits::runtime::*;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2018 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/>.
|
||||
|
||||
use primitives::OpaqueMetadata;
|
||||
use runtime_primitives::{
|
||||
traits::{Block as BlockT},
|
||||
transaction_validity::TransactionValidity
|
||||
};
|
||||
|
||||
decl_runtime_apis! {
|
||||
/// The `Metadata` api trait that returns metadata for the runtime.
|
||||
pub trait Metadata {
|
||||
/// Returns the metadata of a runtime.
|
||||
fn metadata() -> OpaqueMetadata;
|
||||
}
|
||||
|
||||
/// The `TaggedTransactionQueue` api trait for interfering with the new transaction queue.
|
||||
pub trait TaggedTransactionQueue<Block: BlockT> {
|
||||
/// Validate the given transaction.
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user