// 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 .
//! API's for interfacing with the runtime via native/wasm.
#![cfg_attr(not(feature = "std"), no_std)]
extern crate sr_std as rstd;
extern crate sr_primitives as primitives;
#[doc(hidden)]
pub extern crate parity_codec as codec;
#[macro_use]
extern crate parity_codec_derive;
extern crate sr_version as runtime_version;
#[doc(hidden)]
pub use primitives::{traits::Block as BlockT, generic::BlockId, transaction_validity::TransactionValidity, ApplyResult};
use runtime_version::RuntimeVersion;
use rstd::vec::Vec;
#[doc(hidden)]
pub use rstd::slice;
#[doc(hidden)]
pub use codec::{Encode, Decode};
/// Declare the given API traits.
///
/// # Example:
///
/// ```nocompile
/// decl_apis!{
/// pub trait Test ExtraClientSide {
/// fn test(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 {
/// fn test(event: Event) -> AccountId;
/// }
/// }
///
/// pub trait Test {
/// type Error;
/// type ClientArg;
/// fn test(&self, at: &BlockId, event: Event) -> Result;
/// fn testWithExtraParams(&self, at: &BlockId, param: &Client) -> Result;
/// }
/// ```
///
/// The declarations generated in the `runtime` module will be used by `impl_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_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_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_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_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::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_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_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_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::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_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; )* Result<$return_ty_current, Self::Error>; };
$( $( $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_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; )* Result<(), Self::Error>; };
$( $( $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_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] )*
pub trait $name < $( $generic_param_parsed $( : $generic_bound_parsed )* ),* > {
/// The Error type returned by this API.
type Error;
$( type $client_generic_param $( : $client_generic_bound )*; )*
$(
$( #[$fn_attr] )*
fn $fn_name $( < $( $fn_generic: $crate::Encode + $crate::Decode ),* > )* (
&self, at: &$crate::BlockId $(, $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_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 )*;
)*
}
)*
}
};
}
//TODO: Move into runtime!
#[derive(Encode)]
#[cfg_attr(feature = "std", derive(Debug, Decode))]
pub enum BlockBuilderError {
#[cfg(not(feature = "std"))]
Generic(&'static str),
#[cfg(feature = "std")]
Generic(String),
TimestampInFuture(u64),
}
decl_apis! {
/// The `Core` api trait that is mandantory for each runtime.
pub trait Core {
fn version() -> RuntimeVersion;
fn authorities() -> Vec;
fn execute_block(block: Block);
}
/// The `Metadata` api trait that returns metadata for the runtime.
pub trait Metadata {
fn metadata() -> Vec;
}
/// The `OldTxQueue` api trait for interfering with the old transaction queue.
pub trait OldTxQueue {
fn account_nonce(account: AccountId) -> Index;
fn lookup_address(address: Address) -> Option;
}
/// The `TaggedTransactionQueue` api trait for interfering with the new transaction queue.
pub trait TaggedTransactionQueue {
fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity;
}
/// The `Miscellaneous` api trait for getting miscellaneous information from the runtime.
pub trait Miscellaneous {
fn validator_count() -> u32;
fn validators() -> Vec;
fn timestamp() -> Moment;
}
/// The `BlockBuilder` api trait that provides required functions for building a block for a runtime.
pub trait BlockBuilder ExtraClientSide {
/// Initialise a block with the given header.
fn initialise_block(header: ::Header) ExtraClientSide(changes: &mut Self::OverlayedChanges);
/// Apply the given extrinsics.
fn apply_extrinsic(extrinsic: ::Extrinsic) ExtraClientSide(changes: &mut Self::OverlayedChanges) -> ApplyResult;
/// Finish the current block.
fn finalise_block() ExtraClientSide(changes: &mut Self::OverlayedChanges) -> ::Header;
/// Generate inherent extrinsics.
fn inherent_extrinsics(inherent: InherentExtrinsic) -> Vec;
/// Check that the inherents are valid.
fn check_inherents(block: Block, data: InherentData) -> Result<(), BlockBuilderError>;
/// Generate a random seed.
fn random_seed() -> ::Hash;
}
}
/// Implement the given API's for the given runtime.
/// All desired API's need to be implemented in one `impl_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 sr_api as runtime_api;
///
/// use runtime_api::runtime::{Core, TaggedTransactionQueue};
///
/// impl_apis! {
/// impl Core for Runtime {
/// fn version() -> RuntimeVersion { 1 }
/// fn authorities() -> Vec { vec![1] }
/// fn execute_block(block: Block) {
/// //comment
/// let block = call_arbitrary_code(block);
/// execute(block);
/// }
/// }
///
/// impl TaggedTransactionQueue for Runtime {
/// fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity {
/// unimplemented!()
/// }
/// }
/// }
///
/// fn main() {}
/// ```
#[macro_export]
macro_rules! impl_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_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_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> {
match method {
$(
stringify!($fn_name) => {
Some({impl_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::slice::from_raw_parts(input_data, input_len)
}
};
let output = { impl_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::codec::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::codec::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::codec::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::codec::Encode::encode(&output)
};
}