Implement runtime api client side directly in the runtime (#1094)

* Move `initialise_block` into `Core` trait as it is crucial calling the API functions

* Switch to first version of new runtime API implementation

* Fixes bug in tests

* Reenable asserts

* Directly use the `TestAPI` in the tests

* Start improving the api traits

:100644 100644 898aadc7 49217199 M	Cargo.lock
:100644 100644 61570436 465ed664 M	core/client/src/backend.rs
:100644 100644 5d0c886b 64d710fd M	core/client/src/block_builder.rs
:100644 100644 c447855e 5ecbe474 M	core/client/src/client.rs
:100644 100644 139cef13 f90dbf3d M	core/client/src/error.rs
:100644 100644 2800c503 3298e66a M	core/client/src/runtime_api.rs
:100644 100644 affa1c5c 809b08bc M	core/primitives/src/lib.rs
:100644 100644 2877dfa9 d5547413 M	core/sr-api/Cargo.toml
:100644 100644 9a49784d 6a625a03 M	core/sr-api/src/lib.rs
:100644 100644 7c28e1c7 a1a444a9 M	core/sr-primitives/src/traits.rs
:100644 100644 2e113ab6 dcc01a6d M	srml/metadata/Cargo.toml
:100644 100644 ea722a70 0809531a M	srml/metadata/src/lib.rs

* Refactoring

* Move `sr-api` into client and more refactoring

* Fixes tests

* Some documentation and cleanup

* Fixes compilation after rebase

* More refactoring and more documentation

* Makes `substrate-client` compilable on `wasm`

On `wasm` it basically just exports the runtime api stuff.

* Fixes grumbles

* Updates wasm files after rebasing the master

* Remove TODO comment

* Remove whitespaces

* Fixes after rebasing master

* Another rebase, another fix commit
This commit is contained in:
Bastian Köcher
2018-11-13 13:33:28 +01:00
committed by Gav Wood
parent 6e3c56c135
commit 9063d1acae
51 changed files with 2993 additions and 777 deletions
+2 -5
View File
@@ -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>,
{
@@ -85,11 +84,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;
}
}
@@ -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::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;
+16
View File
@@ -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.
+204 -232
View File
@@ -16,8 +16,8 @@
//! 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;
@@ -27,25 +27,29 @@ use runtime_primitives::{
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 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,
ExecutionStrategy, ExecutionManager, ChangesTrieAnchorBlockId,
prove_read, key_changes, key_changes_proof, OverlayedChanges
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));
@@ -402,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);
@@ -508,7 +497,10 @@ impl<B, E, Block> Client<B, E, Block> where
body: Option<Vec<Block::Extrinsic>>,
authorities: Option<Vec<AuthorityId>>,
finalized: bool,
) -> 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),
@@ -737,30 +729,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()))
}
@@ -896,11 +867,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: CoreAPI<Block>
{
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;
@@ -963,7 +1010,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 +1021,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 +1032,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 +1045,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 +1069,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 +1080,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 +1103,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 +1182,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 +1238,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]
+56 -15
View File
@@ -16,60 +16,101 @@
//! Substrate Client and associated logic.
#![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::*;
}
+2 -2
View File
@@ -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,579 @@
// 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.
/// 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,99 @@
// 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;
use runtime_version::ApiId;
#[doc(hidden)]
pub use rstd::slice;
#[cfg(feature = "std")]
use rstd::result;
#[doc(hidden)]
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>>;
}
/// 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;
}
}