Rewrite impl_runtime_apis! and decl_runtime_apis! as proc-macro (#1174)

* Rewrites `impl_runtime_apis!` macro as `proc-macro`

* Adds some documentation

* Require the `impl_runtime_apis` to use a path for accessing the trait

* Make the runtime implement `GetNodeBlockType`

* Moves first chunk of runtime api code into the `impl_runtime_apis` macro

This also renames `ClientWithApi` into `RuntimeApi`.

* Make `impl_runtime_apis` use `runtime` api version automatically

* `decl_runtime_apis` automatically adds `Block: BlockT` as generic parameter

* Remove function generic arguments in block builder api

* Remove some unnused stuff from the `decl_runtime_apis` macro

* Make `InherentData` working again

* Make `impl_runtime_apis!` implement the `RuntimeApi` side as well

* Make it compile again after rebasing with master

* Split `sr-api-macros` into multiple files

* Reimplement `decl_runtime_apis!` as proc_macro

* Use `decl_runtime_apis!` for `Core` as well and improve error reporting

* Adds documentation for `decl_runtime_apis!` and `impl_runtime_apis!`

* Move some code

* Adds compile fail tests

* Adds a test and fixes some bugs

* Make `impl_runtime_apis!` support `_` as parameter name

* Fixes build errors with wasm

* Wasm rebuild after master rebase

* Apply suggestions from code review

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

* Addresses some grumbles

* Adds test to ensure that method signatures need to match

* New wasm files
This commit is contained in:
Bastian Köcher
2018-11-30 11:42:46 +01:00
committed by Gav Wood
parent 309f627d5c
commit ed421c56ee
40 changed files with 1863 additions and 1269 deletions
@@ -16,24 +16,20 @@
//! The runtime api for building blocks.
use runtime_primitives::{traits::Block as BlockT, ApplyResult};
use runtime_primitives::{traits::Block as BlockT, ApplyResult, InherentData, CheckInherentError};
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> {
pub trait BlockBuilder {
/// 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>;
fn inherent_extrinsics(inherent: InherentData) -> Vec<<Block as BlockT>::Extrinsic>;
/// Check that the inherents are valid.
fn check_inherents<InherentData, Error>(
block: Block, data: InherentData
) -> Result<(), Error>;
fn check_inherents(block: Block, data: InherentData) -> Result<(), CheckInherentError>;
/// Generate a random seed.
fn random_seed() -> <Block as BlockT>::Hash;
}
+6 -6
View File
@@ -1221,14 +1221,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, ClientWithApi, test_api::TestAPI};
use test_client::runtime::{self, Block, Transfer, RuntimeApi, 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, ClientWithApi>,
test_client::client::Client<test_client::Backend, test_client::Executor, Block, RuntimeApi>,
Vec<H256>,
Vec<(u64, u64, Vec<u8>, Vec<(u64, u32)>)>,
) {
@@ -1303,14 +1303,14 @@ pub(crate) mod tests {
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
&Keyring::Alice.to_raw_public()
&Keyring::Alice.to_raw_public().into()
).unwrap(),
1000
);
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
&Keyring::Ferdie.to_raw_public()
&Keyring::Ferdie.to_raw_public().into()
).unwrap(),
0
);
@@ -1359,14 +1359,14 @@ pub(crate) mod tests {
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
&Keyring::Alice.to_raw_public()
&Keyring::Alice.to_raw_public().into()
).unwrap(),
958
);
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
&Keyring::Ferdie.to_raw_public()
&Keyring::Ferdie.to_raw_public().into()
).unwrap(),
42
);
+5
View File
@@ -31,6 +31,8 @@ extern crate substrate_state_machine as state_machine;
extern crate substrate_consensus_common as consensus;
extern crate sr_version as runtime_version;
extern crate sr_std as rstd;
#[macro_use]
extern crate sr_api_macros;
#[cfg(test)]
extern crate substrate_keyring as keyring;
#[cfg(test)]
@@ -114,3 +116,6 @@ pub use notifications::{StorageEventStream, StorageChangeSet};
pub use state_machine::ExecutionStrategy;
#[cfg(feature = "std")]
pub use leaves::LeafSet;
#[doc(inline)]
pub use sr_api_macros::{decl_runtime_apis, impl_runtime_apis};
@@ -14,17 +14,17 @@
// 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.
//! All the functionality required for declaring and implementing runtime apis.
#[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;
pub use runtime_primitives::{
traits::{Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef}, generic::BlockId,
transaction_validity::TransactionValidity
};
pub use runtime_version::{ApiId, RuntimeVersion};
#[doc(hidden)]
pub use rstd::slice;
#[cfg(feature = "std")]
@@ -32,12 +32,9 @@ use rstd::result;
pub use codec::{Encode, Decode};
#[cfg(feature = "std")]
use error;
pub use runtime_version::RuntimeVersion;
use rstd::vec::Vec;
use primitives::{AuthorityId, OpaqueMetadata};
mod core;
#[macro_use]
mod macros;
mod traits;
/// Something that can be constructed to a runtime api.
#[cfg(feature = "std")]
@@ -113,11 +110,29 @@ pub mod id {
pub const METADATA: ApiId = *b"metadata";
}
pub use self::core::*;
pub use self::traits::*;
decl_runtime_apis! {
/// The `Core` api trait that is mandantory for each runtime.
#[core_trait]
pub trait Core {
/// 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);
}
/// The runtime apis that should be implemented for the `Runtime`.
pub mod runtime {
pub use super::core::runtime::Core;
pub use super::traits::runtime::*;
/// 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 {
/// Validate the given transaction.
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
}
}
@@ -1,62 +0,0 @@
// 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);
}
}
@@ -1,650 +0,0 @@
// 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! {
@EXTEND_FUNCTIONS
$runtime;
;
$trait_name;
$( $( $generic ),* )*;
{ $( $fn_name ( $( $arg_name: $arg_ty ),* ); )* }
$( $rest )*
}
};
(
$runtime:ident;
$( $trait_name_parsed:ident $( < $( $parsed_generic: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! {
@EXTEND_FUNCTIONS
$runtime;
$(
$trait_name_parsed $( < $( $parsed_generic ),* > )*
::$fn_name_parsed ( $( $arg_name_parsed: $arg_ty_parsed ),* );
)*;
$trait_name;
$( $( $generic ),* )*;
{ $( $fn_name ( $( $arg_name: $arg_ty ),* ); )* }
$( $rest )*
}
};
(@EXTEND_FUNCTIONS
$runtime:ident;
$( $trait_name_parsed:ident $( < $( $parsed_generic:ident ),* > )*::$fn_name_parsed:ident (
$( $arg_name_parsed:ident : $arg_ty_parsed:ty ),* );
)*;
$trait_name:ident;
$( $generic:ident ),*;
{
$fn_name_extend:ident ( $( $arg_name_extend:ident : $arg_ty_extend:ty ),* );
$( $extend_rest:tt )*
}
$( $rest:tt )*
) => {
impl_runtime_apis! {
@EXTEND_FUNCTIONS
$runtime;
$(
$trait_name_parsed $( < $( $parsed_generic ),* > )*
::$fn_name_parsed ( $( $arg_name_parsed: $arg_ty_parsed ),* );
)*
$trait_name < $( $generic ),* >
::$fn_name_extend ( $( $arg_name_extend: $arg_ty_extend ),* );;
$trait_name;
$( $generic ),*;
{
$( $extend_rest )*
}
$( $rest )*
}
};
(@EXTEND_FUNCTIONS
$runtime:ident;
$( $trait_name_parsed:ident $( < $( $parsed_generic:ident ),* > )*::$fn_name_parsed:ident (
$( $arg_name_parsed:ident : $arg_ty_parsed:ty ),* );
)*;
$trait_name:ident;
$( $generic:ident ),*;
{}
$( $rest:tt )*
) => {
impl_runtime_apis! {
$runtime;
$(
$trait_name_parsed $( < $( $parsed_generic ),* > )*
::$fn_name_parsed ( $( $arg_name_parsed: $arg_ty_parsed ),* );
)*;
$( $rest )*
}
};
(
$runtime:ident;
$(
$trait_name:ident $( < $( $generic: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;
$trait_name $( < $( $generic ),* > )*;
$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;
$trait_name $( < $( $generic ),* > )*;
$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;
$trait_name:ident $( < $( $generic: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 as $trait_name $( < $( $generic ),* > )*>::$fn_name($arg_name);
$crate::runtime_api::Encode::encode(&output)
};
(@GENERATE_IMPL_CALL
$runtime:ident;
$trait_name:ident $( < $( $generic: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 as $trait_name $( < $( $generic ),* > )*>::$fn_name($( $arg_name ),*);
$crate::runtime_api::Encode::encode(&output)
};
}
@@ -1,35 +0,0 @@
// 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;
}
}