From ed421c56ee6b2abb639283b5dd74f202ac815ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 30 Nov 2018 11:42:46 +0100 Subject: [PATCH] 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 * Addresses some grumbles * Adds test to ensure that method signatures need to match * New wasm files --- substrate/Cargo.lock | 32 +- substrate/Cargo.toml | 2 +- substrate/core/client/Cargo.toml | 1 + .../core/client/src/block_builder/api.rs | 12 +- substrate/core/client/src/client.rs | 12 +- substrate/core/client/src/lib.rs | 5 + .../{runtime_api/mod.rs => runtime_api.rs} | 49 +- substrate/core/client/src/runtime_api/core.rs | 62 -- .../core/client/src/runtime_api/macros.rs | 650 ------------------ .../core/client/src/runtime_api/traits.rs | 35 - substrate/core/consensus/aura/src/lib.rs | 2 +- substrate/core/consensus/common/src/lib.rs | 19 - .../finality-grandpa/primitives/src/lib.rs | 4 +- substrate/core/finality-grandpa/src/tests.rs | 2 +- substrate/core/network/src/import_queue.rs | 2 +- substrate/core/network/src/test/mod.rs | 2 +- substrate/core/service/src/consensus.rs | 8 +- substrate/core/sr-api-macros/Cargo.toml | 20 + .../sr-api-macros/src/compile_fail_tests.rs | 408 +++++++++++ .../sr-api-macros/src/decl_runtime_apis.rs | 278 ++++++++ .../sr-api-macros/src/impl_runtime_apis.rs | 528 ++++++++++++++ substrate/core/sr-api-macros/src/lib.rs | 164 +++++ substrate/core/sr-api-macros/src/utils.rs | 97 +++ .../core/sr-api-macros/tests/decl_and_impl.rs | 93 +++ .../core/sr-primitives/src/generic/era.rs | 8 +- substrate/core/sr-primitives/src/lib.rs | 29 + substrate/core/sr-primitives/src/traits.rs | 16 +- substrate/core/test-client/src/lib.rs | 6 +- substrate/core/test-runtime/src/lib.rs | 195 +----- substrate/core/test-runtime/wasm/Cargo.lock | 16 +- .../substrate_test_runtime.compact.wasm | Bin 45227 -> 46150 bytes substrate/node/cli/src/service.rs | 10 +- substrate/node/runtime/src/lib.rs | 218 +----- substrate/node/runtime/wasm/Cargo.lock | 16 +- .../release/node_runtime.compact.wasm | Bin 636432 -> 635745 bytes substrate/srml/consensus/src/lib.rs | 7 +- substrate/srml/support/src/inherent.rs | 62 +- substrate/srml/support/src/lib.rs | 1 + substrate/srml/support/src/runtime.rs | 43 +- substrate/srml/timestamp/src/lib.rs | 18 +- 40 files changed, 1863 insertions(+), 1269 deletions(-) rename substrate/core/client/src/{runtime_api/mod.rs => runtime_api.rs} (74%) delete mode 100644 substrate/core/client/src/runtime_api/core.rs delete mode 100644 substrate/core/client/src/runtime_api/macros.rs delete mode 100644 substrate/core/client/src/runtime_api/traits.rs create mode 100644 substrate/core/sr-api-macros/Cargo.toml create mode 100644 substrate/core/sr-api-macros/src/compile_fail_tests.rs create mode 100644 substrate/core/sr-api-macros/src/decl_runtime_apis.rs create mode 100644 substrate/core/sr-api-macros/src/impl_runtime_apis.rs create mode 100644 substrate/core/sr-api-macros/src/lib.rs create mode 100644 substrate/core/sr-api-macros/src/utils.rs create mode 100644 substrate/core/sr-api-macros/tests/decl_and_impl.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index f400554404..38e527abea 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -651,7 +651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2520,7 +2520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2641,6 +2641,21 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sr-api-macros" +version = "0.1.0" +dependencies = [ + "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "substrate-client 0.1.0", + "substrate-primitives 0.1.0", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sr-io" version = "0.1.0" @@ -3038,7 +3053,7 @@ dependencies = [ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3053,7 +3068,7 @@ dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3096,7 +3111,7 @@ dependencies = [ "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3166,6 +3181,7 @@ dependencies = [ "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-api-macros 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", @@ -3686,7 +3702,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.20" +version = "0.15.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3701,7 +3717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4714,7 +4730,7 @@ dependencies = [ "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.20 (registry+https://github.com/rust-lang/crates.io-index)" = "8886c8d2774e853fcd7d9d2131f6e40ba46c9c0e358e4d57178452abd6859bb0" +"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum sysinfo 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "11c5f6e8a7a7146f26ffed9a5ff8bab2706f1ac8a413a415e1d211b819d5c24d" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 98c433f605..30a3e92325 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -60,7 +60,7 @@ members = [ "core/serializer", "core/service", "core/service/test", - "core/state-db", + "core/sr-api-macros", "core/state-machine", "core/test-runtime", "core/telemetry", diff --git a/substrate/core/client/Cargo.toml b/substrate/core/client/Cargo.toml index 1ecf284dc1..9d960cb1a3 100644 --- a/substrate/core/client/Cargo.toml +++ b/substrate/core/client/Cargo.toml @@ -26,6 +26,7 @@ substrate-primitives = { path = "../primitives", default-features = false } sr-primitives = { path = "../sr-primitives", default-features = false } sr-version = { path = "../sr-version", default-features = false } sr-std = { path = "../sr-std", default-features = false } +sr-api-macros = { path = "../sr-api-macros" } [dev-dependencies] substrate-test-client = { path = "../test-client" } diff --git a/substrate/core/client/src/block_builder/api.rs b/substrate/core/client/src/block_builder/api.rs index 67a66373aa..3b8ceb6305 100644 --- a/substrate/core/client/src/block_builder/api.rs +++ b/substrate/core/client/src/block_builder/api.rs @@ -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 { + pub trait BlockBuilder { /// Apply the given extrinsics. fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult; /// Finish the current block. fn finalise_block() -> ::Header; /// Generate inherent extrinsics. - fn inherent_extrinsics( - inherent: InherentExtrinsic - ) -> Vec; + fn inherent_extrinsics(inherent: InherentData) -> Vec<::Extrinsic>; /// Check that the inherents are valid. - fn check_inherents( - block: Block, data: InherentData - ) -> Result<(), Error>; + fn check_inherents(block: Block, data: InherentData) -> Result<(), CheckInherentError>; /// Generate a random seed. fn random_seed() -> ::Hash; } diff --git a/substrate/core/client/src/client.rs b/substrate/core/client/src/client.rs index 92a4688845..205827b6d4 100644 --- a/substrate/core/client/src/client.rs +++ b/substrate/core/client/src/client.rs @@ -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::client::Client, Vec, Vec<(u64, u64, Vec, 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 ); diff --git a/substrate/core/client/src/lib.rs b/substrate/core/client/src/lib.rs index a73671ca47..fb07c130b2 100644 --- a/substrate/core/client/src/lib.rs +++ b/substrate/core/client/src/lib.rs @@ -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}; diff --git a/substrate/core/client/src/runtime_api/mod.rs b/substrate/core/client/src/runtime_api.rs similarity index 74% rename from substrate/core/client/src/runtime_api/mod.rs rename to substrate/core/client/src/runtime_api.rs index acf4db705c..2e5c5e38ca 100644 --- a/substrate/core/client/src/runtime_api/mod.rs +++ b/substrate/core/client/src/runtime_api.rs @@ -14,17 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! 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; + /// Execute the given block. + fn execute_block(block: Block); + /// Initialise a block with the given header. + fn initialise_block(header: ::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: ::Extrinsic) -> TransactionValidity; + } } diff --git a/substrate/core/client/src/runtime_api/core.rs b/substrate/core/client/src/runtime_api/core.rs deleted file mode 100644 index 20798422b7..0000000000 --- a/substrate/core/client/src/runtime_api/core.rs +++ /dev/null @@ -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 . - -#[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: 'static + Send + Sync + ConstructRuntimeApi + ApiExt { - /// Returns the version of the runtime. - fn version(&self, at: &BlockId) -> Result; - /// Returns the authorities. - fn authorities(&self, at: &BlockId) -> Result>; - /// Execute the given block. - fn execute_block(&self, at: &BlockId, block: &Block) -> Result<()>; - /// Initialise a block with the given header. - fn initialise_block( - &self, - at: &BlockId, - header: &::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 { - /// Returns the version of the runtime. - fn version() -> RuntimeVersion; - /// Returns the authorities. - fn authorities() -> Vec; - /// Execute the given block. - fn execute_block(block: Block); - /// Initialise a block with the given header. - fn initialise_block(header: ::Header); - } -} diff --git a/substrate/core/client/src/runtime_api/macros.rs b/substrate/core/client/src/runtime_api/macros.rs deleted file mode 100644 index 1721fbd416..0000000000 --- a/substrate/core/client/src/runtime_api/macros.rs +++ /dev/null @@ -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 . - -//! 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 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_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 { - $( 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 $(, $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 for Runtime { -/// fn version() -> RuntimeVersion { unimplemented!() } -/// fn authorities() -> Vec { unimplemented!() } -/// fn execute_block(block: Block) { -/// //comment -/// unimplemented!() -/// } -/// } -/// -/// impl TaggedTransactionQueue for Runtime { -/// fn validate_transaction(tx: ::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> { - 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) - }; -} diff --git a/substrate/core/client/src/runtime_api/traits.rs b/substrate/core/client/src/runtime_api/traits.rs deleted file mode 100644 index 4d237a09ef..0000000000 --- a/substrate/core/client/src/runtime_api/traits.rs +++ /dev/null @@ -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 . - -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 { - /// Validate the given transaction. - fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity; - } -} diff --git a/substrate/core/consensus/aura/src/lib.rs b/substrate/core/consensus/aura/src/lib.rs index 0313f7af3c..a871861d18 100644 --- a/substrate/core/consensus/aura/src/lib.rs +++ b/substrate/core/consensus/aura/src/lib.rs @@ -440,7 +440,7 @@ mod tests { type Error = client::error::Error; - type TestClient = client::Client; + type TestClient = client::Client; struct DummyFactory(Arc); struct DummyProposer(u64, Arc); diff --git a/substrate/core/consensus/common/src/lib.rs b/substrate/core/consensus/common/src/lib.rs index 4758a4abfe..227131914c 100644 --- a/substrate/core/consensus/common/src/lib.rs +++ b/substrate/core/consensus/common/src/lib.rs @@ -86,25 +86,6 @@ pub trait Proposer { fn propose(&self) -> Self::Create; } -/// Inherent data to include in a block. -#[derive(Encode, Decode)] -pub struct InherentData { - /// Current timestamp. - pub timestamp: u64, - /// Indices of offline validators. - pub offline_indices: Vec, -} - -impl InherentData { - /// Create a new `InherentData` instance. - pub fn new(timestamp: u64, offline_indices: Vec) -> Self { - Self { - timestamp, - offline_indices - } - } -} - /// An oracle for when major synchronization work is being undertaken. /// /// Generally, consensus authoring work isn't undertaken while well behind diff --git a/substrate/core/finality-grandpa/primitives/src/lib.rs b/substrate/core/finality-grandpa/primitives/src/lib.rs index 4940574533..df224fa9d4 100644 --- a/substrate/core/finality-grandpa/primitives/src/lib.rs +++ b/substrate/core/finality-grandpa/primitives/src/lib.rs @@ -35,7 +35,7 @@ extern crate substrate_client as client; extern crate sr_std as rstd; use substrate_primitives::AuthorityId; -use sr_primitives::traits::{Block as BlockT, DigestFor, NumberFor}; +use sr_primitives::traits::{DigestFor, NumberFor}; use rstd::vec::Vec; /// A scheduled change of authority set. @@ -79,7 +79,7 @@ decl_runtime_apis! { /// applied in the runtime after those N blocks have passed. /// /// The consensus protocol will coordinate the handoff externally. - pub trait GrandpaApi { + pub trait GrandpaApi { /// Check a digest for pending changes. /// Return `None` if there are no pending changes. /// diff --git a/substrate/core/finality-grandpa/src/tests.rs b/substrate/core/finality-grandpa/src/tests.rs index c8ba80098d..1dfe8d69e8 100644 --- a/substrate/core/finality-grandpa/src/tests.rs +++ b/substrate/core/finality-grandpa/src/tests.rs @@ -43,7 +43,7 @@ type PeerData = test_client::Backend, test_client::Executor, Block, - test_client::runtime::ClientWithApi, + test_client::runtime::RuntimeApi, > > >; diff --git a/substrate/core/network/src/import_queue.rs b/substrate/core/network/src/import_queue.rs index cb7bf86e69..c6bb0c51bc 100644 --- a/substrate/core/network/src/import_queue.rs +++ b/substrate/core/network/src/import_queue.rs @@ -699,7 +699,7 @@ pub mod tests { } } - fn prepare_good_block() -> (client::Client, Hash, u64, BlockData) { + fn prepare_good_block() -> (client::Client, Hash, u64, BlockData) { let client = test_client::new(); let block = client.new_block().unwrap().bake().unwrap(); client.justify_and_import(BlockOrigin::File, block).unwrap(); diff --git a/substrate/core/network/src/test/mod.rs b/substrate/core/network/src/test/mod.rs index 374e825bc8..603aaa9572 100644 --- a/substrate/core/network/src/test/mod.rs +++ b/substrate/core/network/src/test/mod.rs @@ -129,7 +129,7 @@ pub struct TestPacket { recipient: NodeIndex, } -pub type PeersClient = client::Client; +pub type PeersClient = client::Client; pub struct Peer, D> { client: Arc, diff --git a/substrate/core/service/src/consensus.rs b/substrate/core/service/src/consensus.rs index 338c1680cf..240ba7dc49 100644 --- a/substrate/core/service/src/consensus.rs +++ b/substrate/core/service/src/consensus.rs @@ -25,10 +25,11 @@ use std; use client::{self, error, Client as SubstrateClient, CallExecutor}; use client::{block_builder::api::BlockBuilder as BlockBuilderApi, runtime_api::{id::BLOCK_BUILDER, Core}}; use codec::{Decode, Encode}; -use consensus_common::{self, InherentData, evaluation, offline_tracker::OfflineTracker}; +use consensus_common::{self, evaluation, offline_tracker::OfflineTracker}; use primitives::{H256, AuthorityId, ed25519, Blake2Hasher}; use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, ProvideRuntimeApi}; use runtime_primitives::generic::BlockId; +use runtime_primitives::InherentData; use transaction_pool::txpool::{self, Pool as TransactionPool}; use parking_lot::RwLock; @@ -200,10 +201,7 @@ impl consensus_common::Proposer<::Block> for Pro ) } - let inherent_data = InherentData { - timestamp, - offline_indices, - }; + let inherent_data = InherentData::new(timestamp, offline_indices); let block = self.client.build_block( &self.parent_id, diff --git a/substrate/core/sr-api-macros/Cargo.toml b/substrate/core/sr-api-macros/Cargo.toml new file mode 100644 index 0000000000..05172e5bf8 --- /dev/null +++ b/substrate/core/sr-api-macros/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "sr-api-macros" +version = "0.1.0" +authors = ["Parity Technologies "] + +[lib] +proc-macro = true + +[dependencies] +quote = "0.6" +syn = { version = "0.15", features = [ "full", "fold", "extra-traits", "visit" ] } +proc-macro2 = "0.4" + +[dev-dependencies] +substrate-client = { path = "../client" } +sr-primitives = { path = "../sr-primitives" } +substrate-primitives = { path = "../primitives" } +parity-codec = "2.1" +parity-codec-derive = "2.1" +serde = "1.0" diff --git a/substrate/core/sr-api-macros/src/compile_fail_tests.rs b/substrate/core/sr-api-macros/src/compile_fail_tests.rs new file mode 100644 index 0000000000..14d77d003c --- /dev/null +++ b/substrate/core/sr-api-macros/src/compile_fail_tests.rs @@ -0,0 +1,408 @@ +// 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 . + +//! Compile fail tests. + +mod declaring_own_block { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + + use runtime_primitives::traits::Block as BlockT; + + decl_runtime_apis! { + pub trait Api { + fn test(); + } + } + + fn main() {} + ``` + */ +} + +mod declaring_own_block_with_different_name { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + + use runtime_primitives::traits::Block as BlockT; + + decl_runtime_apis! { + pub trait Api { + fn test(); + } + } + + fn main() {} + ``` + */ +} + +mod adding_self_parameter { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + + decl_runtime_apis! { + pub trait Api { + fn test(&self); + } + } + + fn main() {} + ``` + */ +} + +mod adding_at_parameter { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + + decl_runtime_apis! { + pub trait Api { + fn test(at: u64); + } + } + + fn main() {} + ``` + */ +} + +mod adding_parameter_with_type_reference { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + + decl_runtime_apis! { + pub trait Api { + fn test(data: &u64); + } + } + + fn main() {} + ``` + */ +} + +mod missing_block_generic_parameter { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + extern crate substrate_primitives as primitives; + #[macro_use] + extern crate parity_codec_derive; + extern crate serde; + extern crate core; + + use primitives::hash::H256; + use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; + + // All the stuff we need to declare our `Block` + pub type BlockNumber = u64; + pub type DigestItem = runtime_primitives::generic::DigestItem; + pub type Digest = runtime_primitives::generic::Digest; + #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] + pub struct Extrinsic {} + + impl serde::Serialize for Extrinsic { + fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { + unimplemented!() + } + } + impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } + } + pub type Header = runtime_primitives::generic::Header; + pub type Block = runtime_primitives::generic::Block; + + /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` + /// trait are done by the `construct_runtime!` macro in a real runtime. + struct Runtime {} + impl GetNodeBlockType for Runtime { + type NodeBlock = Block; + } + + decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + } + } + + impl_runtime_apis! { + impl self::Api for Runtime { + fn test(data: u64) { + unimplemented!() + } + } + } + + fn main() {} + ``` + */ +} + +mod missing_path_for_trait { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + extern crate substrate_primitives as primitives; + #[macro_use] + extern crate parity_codec_derive; + extern crate serde; + extern crate core; + + use primitives::hash::H256; + use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; + + // All the stuff we need to declare our `Block` + pub type BlockNumber = u64; + pub type DigestItem = runtime_primitives::generic::DigestItem; + pub type Digest = runtime_primitives::generic::Digest; + #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] + pub struct Extrinsic {} + impl serde::Serialize for Extrinsic + { + fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { + unimplemented!() + } + } + impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } + } + pub type Header = runtime_primitives::generic::Header; + pub type Block = runtime_primitives::generic::Block; + + /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` + /// trait are done by the `construct_runtime!` macro in a real runtime. + struct Runtime {} + impl GetNodeBlockType for Runtime { + type NodeBlock = Block; + } + + decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + } + } + + impl_runtime_apis! { + impl Api for Runtime { + fn test(data: u64) { + unimplemented!() + } + } + } + + fn main() {} + ``` + */ +} + +mod empty_impl_runtime_apis_call { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + extern crate substrate_primitives as primitives; + #[macro_use] + extern crate parity_codec_derive; + extern crate serde; + extern crate core; + + use primitives::hash::H256; + use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; + + // All the stuff we need to declare our `Block` + pub type BlockNumber = u64; + pub type DigestItem = runtime_primitives::generic::DigestItem; + pub type Digest = runtime_primitives::generic::Digest; + #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] + pub struct Extrinsic {} + impl serde::Serialize for Extrinsic + { + fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { + unimplemented!() + } + } + impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } + } + pub type Header = runtime_primitives::generic::Header; + pub type Block = runtime_primitives::generic::Block; + + /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` + /// trait are done by the `construct_runtime!` macro in a real runtime. + struct Runtime {} + impl GetNodeBlockType for Runtime { + type NodeBlock = Block; + } + + decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + } + } + + impl_runtime_apis! {} + + fn main() {} + ``` + */ +} + +mod type_reference_in_impl_runtime_apis_call { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + extern crate substrate_primitives as primitives; + #[macro_use] + extern crate parity_codec_derive; + extern crate serde; + extern crate core; + + use primitives::hash::H256; + use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; + + // All the stuff we need to declare our `Block` + pub type BlockNumber = u64; + pub type DigestItem = runtime_primitives::generic::DigestItem; + pub type Digest = runtime_primitives::generic::Digest; + #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] + pub struct Extrinsic {} + impl serde::Serialize for Extrinsic + { + fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { + unimplemented!() + } + } + impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } + } + pub type Header = runtime_primitives::generic::Header; + pub type Block = runtime_primitives::generic::Block; + + /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` + /// trait are done by the `construct_runtime!` macro in a real runtime. + struct Runtime {} + impl GetNodeBlockType for Runtime { + type NodeBlock = Block; + } + + decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + } + } + + impl_runtime_apis! { + impl self::Api for Runtime { + fn test(data: &u64) { + unimplemented!() + } + } + } + + fn main() {} + ``` + */ +} + +mod impl_incorrect_method_signature { + /*! + ```compile_fail + #[macro_use] + extern crate substrate_client; + extern crate sr_primitives as runtime_primitives; + extern crate substrate_primitives as primitives; + #[macro_use] + extern crate parity_codec_derive; + extern crate serde; + extern crate core; + + use primitives::hash::H256; + use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; + + // All the stuff we need to declare our `Block` + pub type BlockNumber = u64; + pub type DigestItem = runtime_primitives::generic::DigestItem; + pub type Digest = runtime_primitives::generic::Digest; + #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] + pub struct Extrinsic {} + impl serde::Serialize for Extrinsic + { + fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { + unimplemented!() + } + } + impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } + } + pub type Header = runtime_primitives::generic::Header; + pub type Block = runtime_primitives::generic::Block; + + /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` + /// trait are done by the `construct_runtime!` macro in a real runtime. + struct Runtime {} + impl GetNodeBlockType for Runtime { + type NodeBlock = Block; + } + + decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + } + } + + impl_runtime_apis! { + impl self::Api for Runtime { + fn test(data: String) {} + } + } + + fn main() {} + ``` + */ +} diff --git a/substrate/core/sr-api-macros/src/decl_runtime_apis.rs b/substrate/core/sr-api-macros/src/decl_runtime_apis.rs new file mode 100644 index 0000000000..1f723519e1 --- /dev/null +++ b/substrate/core/sr-api-macros/src/decl_runtime_apis.rs @@ -0,0 +1,278 @@ +// 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 . + +use utils::{ + generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait, + fold_fn_decl_for_client_side +}; + +use proc_macro; +use proc_macro2::TokenStream; + +use quote::quote; + +use syn::{ + spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, + fold::{self, Fold}, FnDecl, parse_quote, ItemTrait, Generics, GenericParam, Attribute, + visit::{Visit, self}, FnArg, Pat, TraitBound, Type +}; + +/// Unique identifier used to make the hidden includes unique for this macro. +const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS"; + +/// The structure used for parsing the runtime api declarations. +struct RuntimeApiDecls { + decls: Vec, +} + +impl Parse for RuntimeApiDecls { + fn parse(input: ParseStream) -> Result { + let mut decls = Vec::new(); + + while !input.is_empty() { + decls.push(ItemTrait::parse(input)?); + } + + Ok(Self { decls }) + } +} + +/// Extend the given generics with `Block: BlockT` as first generic parameter. +fn extend_generics_with_block(generics: &mut Generics) { + let c = generate_crate_access(HIDDEN_INCLUDES_ID); + + generics.lt_token = Some(parse_quote!(<)); + generics.params.insert(0, parse_quote!( Block: #c::runtime_api::BlockT )); + generics.gt_token = Some(parse_quote!(>)); +} + +// Check if `core_trait` attribute is present and remove it. Returns if the attribute was found. +fn remove_core_trait_attribute(attrs: &mut Vec) -> bool { + let mut found = false; + attrs.retain(|v| { + let res = v.path.is_ident("core_trait"); + found |= res; + !res + }); + found +} + +/// Generate the decleration of the trait for the runtime. +fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream { + let mut result = Vec::new(); + + for decl in decls { + let mut decl = decl.clone(); + extend_generics_with_block(&mut decl.generics); + let mod_name = generate_runtime_mod_name_for_trait(&decl.ident); + remove_core_trait_attribute(&mut decl.attrs); + + result.push(quote!( + #[doc(hidden)] + pub mod #mod_name { + use super::*; + + #decl + } + )); + } + + quote!( #( #result )* ) +} + +/// Modify the given runtime api declaration to be usable on the client side. +struct ToClientSideDecl<'a> { + block_id: &'a TokenStream, + crate_: &'a TokenStream, +} + +impl<'a> Fold for ToClientSideDecl<'a> { + fn fold_fn_decl(&mut self, input: FnDecl) -> FnDecl { + let input = fold_fn_decl_for_client_side( + input, + &self.block_id, + &self.crate_ + ); + + fold::fold_fn_decl(self, input) + } + + fn fold_item_trait(&mut self, mut input: ItemTrait) -> ItemTrait { + extend_generics_with_block(&mut input.generics); + + // Check if this is the `Core` runtime api trait. + let is_core_trait = remove_core_trait_attribute(&mut input.attrs); + + if is_core_trait { + // Add all the supertraits we want to have for `Core`. + let crate_ = &self.crate_; + input.supertraits = parse_quote!( + 'static + + Send + + Sync + + #crate_::runtime_api::ConstructRuntimeApi + + #crate_::runtime_api::ApiExt + ); + } else { + // Add the `Core` runtime api as super trait. + let crate_ = &self.crate_; + input.supertraits.push(parse_quote!( #crate_::runtime_api::Core )); + } + + // The client side trait is only required when compiling with the feature `std` or `test`. + input.attrs.push(parse_quote!( #[cfg(any(feature = "std", test))] )); + + fold::fold_item_trait(self, input) + } +} + +/// Generate the decleration of the trait for the client side. +fn generate_client_side_decls(decls: &[ItemTrait]) -> TokenStream { + let mut result = Vec::new(); + + for decl in decls { + let mut decl = decl.clone(); + + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let block_id = quote!( #crate_::runtime_api::BlockId ); + let mut to_client_side = ToClientSideDecl { crate_: &crate_, block_id: &block_id }; + + result.push(to_client_side.fold_item_trait(decl)); + } + + quote!( #( #result )* ) +} + +/// Checks that a trait declaration is in the format we expect. +struct CheckTraitDecl { + errors: Vec, +} + +impl<'ast> Visit<'ast> for CheckTraitDecl { + fn visit_fn_arg(&mut self, input: &'ast FnArg) { + match input { + FnArg::Captured(ref arg) => { + match arg.pat { + Pat::Ident(ref pat) if pat.ident == "at" => { + self.errors.push( + Error::new( + pat.span(), + "`decl_runtime_apis!` adds automatically a parameter \ + `at: &BlockId`. Please rename/remove your parameter." + ) + ) + }, + _ => {} + } + + match arg.ty { + Type::Reference(ref reference) => { + self.errors.push( + Error::new( + reference.span(), + "Do not use type references as arguments. The client side \ + declaration will take all arguments as reference automatically." + ) + ) + }, + _ => {}, + } + }, + FnArg::SelfRef(_) | FnArg::SelfValue(_) => { + self.errors.push(Error::new(input.span(), "Self values are not supported.")) + } + _ => { + self.errors.push( + Error::new( + input.span(), + "Only function arguments in the form `pat: type` are supported." + ) + ) + } + } + + visit::visit_fn_arg(self, input); + } + + fn visit_generic_param(&mut self, input: &'ast GenericParam) { + match input { + GenericParam::Type(ty) if &ty.ident == "Block" => { + self.errors.push( + Error::new( + input.span(), + "`Block: BlockT` generic parameter will be added automatically by the \ + `decl_runtime_apis!` macro!" + ) + ) + }, + _ => {} + } + + visit::visit_generic_param(self, input); + } + + fn visit_trait_bound(&mut self, input: &'ast TraitBound) { + if let Some(last_ident) = input.path.segments.last().map(|v| &v.value().ident) { + if last_ident == "BlockT" || last_ident == "Block" { + self.errors.push( + Error::new( + input.span(), + "`Block: BlockT` generic parameter will be added automatically by the \ + `decl_runtime_apis!` macro! If you try to use a different trait than the \ + substrate `Block` trait, please rename it locally." + ) + ) + } + } + + visit::visit_trait_bound(self, input) + } +} + +/// Check that the trait declarations are in the format we expect. +fn check_trait_decls(decls: &[ItemTrait]) -> Option { + let mut checker = CheckTraitDecl { errors: Vec::new() }; + decls.iter().for_each(|decl| visit::visit_item_trait(&mut checker, &decl)); + + if checker.errors.is_empty() { + None + } else { + let errors = checker.errors.into_iter().map(|e| e.to_compile_error()); + Some(quote!( #( #errors )* )) + } +} + +/// The implementation of the `decl_runtime_apis!` macro. +pub fn decl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Parse all trait declarations + let RuntimeApiDecls { decls: api_decls } = parse_macro_input!(input as RuntimeApiDecls); + + if let Some(errors) = check_trait_decls(&api_decls) { + return errors.into(); + } + + let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); + let runtime_decls = generate_runtime_decls(&api_decls); + let client_side_decls = generate_client_side_decls(&api_decls); + + quote!( + #hidden_includes + + #runtime_decls + + #client_side_decls + ).into() +} diff --git a/substrate/core/sr-api-macros/src/impl_runtime_apis.rs b/substrate/core/sr-api-macros/src/impl_runtime_apis.rs new file mode 100644 index 0000000000..6817366def --- /dev/null +++ b/substrate/core/sr-api-macros/src/impl_runtime_apis.rs @@ -0,0 +1,528 @@ +// 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 . + +use utils::{ + unwrap_or_error, generate_crate_access, generate_hidden_includes, + generate_runtime_mod_name_for_trait, fold_fn_decl_for_client_side +}; + +use proc_macro; +use proc_macro2::{Span, TokenStream}; + +use quote::quote; + +use syn::{ + spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, MethodSig, FnArg, Path, + ImplItem, parse::{Parse, ParseStream, Result, Error}, PathArguments, GenericArgument, TypePath, + fold::{self, Fold}, FnDecl, parse_quote, Pat +}; + +use std::iter; + +/// Unique identifier used to make the hidden includes unique for this macro. +const HIDDEN_INCLUDES_ID: &str = "IMPL_RUNTIME_APIS"; + +/// The structure used for parsing the runtime api implementations. +struct RuntimeApiImpls { + impls: Vec, +} + +impl Parse for RuntimeApiImpls { + fn parse(input: ParseStream) -> Result { + let mut impls = Vec::new(); + + while !input.is_empty() { + impls.push(ItemImpl::parse(input)?); + } + + Ok(Self { impls }) + } +} + +/// Generates the call to the implementation of the requested function. +/// The generated code includes decoding of the input arguments and encoding of the output. +fn generate_impl_call( + signature: &MethodSig, + runtime: &Type, + input: &Ident, + impl_trait: &Path +) -> Result { + let mut pnames = Vec::new(); + let mut ptypes = Vec::new(); + let mut generated_pattern_counter = 0; + for input in signature.decl.inputs.iter() { + match input { + FnArg::Captured(arg) => { + match &arg.ty { + Type::Reference(_) => { + return Err( + Error::new( + arg.ty.span(), + "No type references are allowed in the api traits!" + ) + ) + }, + _ => {}, + } + + pnames.push( + generate_unique_pattern(arg.pat.clone(), &mut generated_pattern_counter) + ); + ptypes.push(&arg.ty); + }, + _ => { + return Err( + Error::new( + input.span(), + "Only function arguments with the following \ + pattern are accepted: `name: type`!" + ) + ) + } + } + } + + let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let c_iter = iter::repeat(&c); + let fn_name = &signature.ident; + let fn_name_str = iter::repeat(fn_name.to_string()); + let input = iter::repeat(input); + let pnames2 = pnames.clone(); + + Ok( + quote!( + #( + let #pnames : #ptypes = match #c_iter::runtime_api::Decode::decode(&mut #input) { + Some(input) => input, + None => panic!("Bad input data provided to {}", #fn_name_str), + }; + )* + + let output = <#runtime as #impl_trait>::#fn_name(#( #pnames2 ),*); + #c::runtime_api::Encode::encode(&output) + ).into() + ) +} + +/// Extract the trait that is implemented in the given `ItemImpl`. +fn extract_impl_trait<'a>(impl_: &'a ItemImpl) -> Result<&'a Path> { + impl_.trait_.as_ref().map(|v| &v.1).ok_or_else( + || Error::new(impl_.span(), "Only implementation of traits are supported!") + ).and_then(|p| { + if p.segments.len() > 1 { + Ok(p) + } else { + Err( + Error::new( + p.span(), + "The implemented trait has to be referenced with a path, \ + e.g. `impl client::Core for Runtime`." + ) + ) + } + }) +} + +/// Extracts the runtime block identifier. +fn extract_runtime_block_ident(trait_: &Path) -> Result<&TypePath> { + let span = trait_.span(); + let segment = trait_ + .segments + .last() + .ok_or_else( + || Error::new(span, "Empty path not supported") + )?; + let generics = segment.value(); + + match &generics.arguments { + PathArguments::AngleBracketed(ref args) => { + args.args.first().and_then(|v| match v.value() { + GenericArgument::Type(Type::Path(block)) => Some(block), + _ => None + }).ok_or_else(|| Error::new(args.span(), "Missing `Block` generic parameter.")) + }, + PathArguments::None => { + let span = trait_.segments.last().as_ref().unwrap().value().span(); + Err(Error::new(span, "Missing `Block` generic parameter.")) + }, + PathArguments::Parenthesized(_) => { + Err(Error::new(generics.arguments.span(), "Unexpected parentheses in path!")) + } + } +} + +/// Generate all the implementation calls for the given functions. +fn generate_impl_calls(impls: &[ItemImpl], input: &Ident) -> Result> { + let mut impl_calls = Vec::new(); + + for impl_ in impls { + let impl_trait = extend_with_runtime_decl_path(extract_impl_trait(impl_)?.clone()); + + for item in &impl_.items { + match item { + ImplItem::Method(method) => { + let impl_call = generate_impl_call( + &method.sig, + &impl_.self_ty, + input, + &impl_trait + )?; + + impl_calls.push((method.sig.ident.clone(), impl_call)); + }, + _ => {}, + } + } + } + + Ok(impl_calls) +} + +/// Generate the dispatch function that is used in native to call into the runtime. +fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { + let data = Ident::new("data", Span::call_site()); + let impl_calls = generate_impl_calls(impls, &data)?.into_iter().map(|(fn_name, impl_)| { + let fn_name = fn_name.to_string(); + quote!( #fn_name => Some({ #impl_ }), ) + }); + + Ok(quote!( + #[cfg(feature = "std")] + pub fn dispatch(method: &str, mut #data: &[u8]) -> Option> { + match method { + #( #impl_calls )* + _ => None, + } + } + ).into()) +} + +/// Generate the interface functions that are used to call into the runtime in wasm. +fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { + let input = Ident::new("input", Span::call_site()); + let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let impl_calls = generate_impl_calls(impls, &input)?.into_iter().map(|(fn_name, impl_)| { + quote!( + #[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 { + #c::runtime_api::slice::from_raw_parts(input_data, input_len) + } + }; + + let output = { #impl_ }; + 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 + } + ) + }); + + Ok(quote!( #( #impl_calls )* )) +} + +fn generate_block_and_block_id_ty( + runtime: &Type, + trait_: &'static str, + assoc_type: &'static str, +) -> (TokenStream, TokenStream) { + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let trait_ = Ident::new(trait_, Span::call_site()); + let assoc_type = Ident::new(assoc_type, Span::call_site()); + + let block = quote!( <#runtime as #crate_::runtime_api::#trait_>::#assoc_type ); + let block_id = quote!( #crate_::runtime_api::BlockId<#block> ); + + (block, block_id) +} + +fn generate_node_block_and_block_id_ty(runtime: &Type) -> (TokenStream, TokenStream) { + generate_block_and_block_id_ty(runtime, "GetNodeBlockType", "NodeBlock") +} + +fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result { + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let runtime = &impls.get(0).ok_or_else(|| + Error::new(Span::call_site(), "No api implementation given!") + )?.self_ty; + let (block, block_id) = generate_node_block_and_block_id_ty(runtime); + + Ok(quote!( + /// Implements all runtime apis for the client side. + #[cfg(any(feature = "std", test))] + pub struct RuntimeApi { + call: ::std::ptr::NonNull<#crate_::runtime_api::CallApiAt<#block>>, + commit_on_success: ::std::cell::RefCell, + initialised_block: ::std::cell::RefCell>, + changes: ::std::cell::RefCell<#crate_::runtime_api::OverlayedChanges>, + } + + // `RuntimeApi` itself is not threadsafe. However, an instance is only available in a + // `ApiRef` object and `ApiRef` also has an associated lifetime. This lifetimes makes it + // impossible to move `RuntimeApi` into another thread. + #[cfg(any(feature = "std", test))] + unsafe impl Send for RuntimeApi {} + #[cfg(any(feature = "std", test))] + unsafe impl Sync for RuntimeApi {} + + #[cfg(any(feature = "std", test))] + impl #crate_::runtime_api::ApiExt for RuntimeApi { + fn map_api_result ::std::result::Result, R, E>( + &self, + map_call: F + ) -> ::std::result::Result { + *self.commit_on_success.borrow_mut() = false; + let res = map_call(self); + *self.commit_on_success.borrow_mut() = true; + + self.commit_on_ok(&res); + + res + } + } + + #[cfg(any(feature = "std", test))] + impl #crate_::runtime_api::ConstructRuntimeApi<#block> for RuntimeApi { + fn construct_runtime_api<'a, T: #crate_::runtime_api::CallApiAt<#block>>( + call: &'a T + ) -> #crate_::runtime_api::ApiRef<'a, Self> { + RuntimeApi { + call: unsafe { + ::std::ptr::NonNull::new_unchecked( + call as &#crate_::runtime_api::CallApiAt<#block> as *const _ as *mut _ + ) + }, + commit_on_success: true.into(), + initialised_block: None.into(), + changes: Default::default(), + }.into() + } + } + + #[cfg(any(feature = "std", test))] + impl RuntimeApi { + fn call_api_at( + &self, + at: &#block_id, + function: &'static str, + args: &A + ) -> #crate_::error::Result { + let res = unsafe { + self.call.as_ref().call_api_at( + at, + function, + args.encode(), + &mut *self.changes.borrow_mut(), + &mut *self.initialised_block.borrow_mut() + ).and_then(|r| + R::decode(&mut &r[..]) + .ok_or_else(|| + #crate_::error::ErrorKind::CallResultDecode(function).into() + ) + ) + }; + + self.commit_on_ok(&res); + res + } + + fn commit_on_ok(&self, res: &::std::result::Result) { + if *self.commit_on_success.borrow() { + if res.is_err() { + self.changes.borrow_mut().discard_prospective(); + } else { + self.changes.borrow_mut().commit_prospective(); + } + } + } + } + )) +} + +/// Extend the given trait path with module that contains the declaration of the trait for the +/// runtime. +fn extend_with_runtime_decl_path(mut trait_: Path) -> Path { + let runtime = { + let trait_name = &trait_ + .segments + .last() + .as_ref() + .expect("Trait path should always contain at least one item; qed") + .value() + .ident; + + generate_runtime_mod_name_for_trait(trait_name) + }; + + let pos = trait_.segments.len() - 1; + trait_.segments.insert(pos, runtime.clone().into()); + trait_ +} + +/// Generates the implementations of the apis for the runtime. +fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { + let mut impls_prepared = Vec::new(); + + // We put `runtime` before each trait to get the trait that is intended for the runtime and + // we put the `RuntimeBlock` as first argument for the trait generics. + for impl_ in impls.iter() { + let mut impl_ = impl_.clone(); + let trait_ = extract_impl_trait(&impl_)?.clone(); + let trait_ = extend_with_runtime_decl_path(trait_); + + impl_.trait_.as_mut().unwrap().1 = trait_; + impls_prepared.push(impl_); + } + + Ok(quote!( #( #impls_prepared )* )) +} + +/// Generate an unique pattern based on the given counter, if the given pattern is a `_`. +fn generate_unique_pattern(pat: Pat, counter: &mut u32) -> Pat { + match pat { + Pat::Wild(_) => { + let generated_name = Ident::new( + &format!("impl_runtime_api_generated_name_{}", counter), + pat.span() + ); + *counter += 1; + + parse_quote!( #generated_name ) + }, + _ => pat, + } +} + +/// Auxilariy data structure that is used to convert `impl Api for Runtime` to +/// `impl Api for RuntimeApi`. +/// This requires us to replace the runtime `Block` with the node `Block`, +/// `impl Api for Runtime` with `impl Api for RuntimeApi` and replace the method implementations +/// with code that calls into the runtime. +struct ApiRuntimeImplToApiRuntimeApiImpl<'a> { + node_block: &'a TokenStream, + runtime_block: &'a TypePath, + node_block_id: &'a TokenStream, +} + +impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { + fn fold_type_path(&mut self, input: TypePath) -> TypePath { + let new_ty_path = if input == *self.runtime_block { + let node_block = self.node_block; + parse_quote!( #node_block ) + } else { + input + }; + + fold::fold_type_path(self, new_ty_path) + } + + fn fold_fn_decl(&mut self, input: FnDecl) -> FnDecl { + let input = fold_fn_decl_for_client_side( + input, + &self.node_block_id, + &generate_crate_access(HIDDEN_INCLUDES_ID) + ); + + fold::fold_fn_decl(self, input) + } + + fn fold_impl_item_method(&mut self, mut input: syn::ImplItemMethod) -> syn::ImplItemMethod { + { + let mut generated_name_counter = 0; + let arg_names = input.sig.decl.inputs.iter_mut().filter_map(|i| match i { + FnArg::Captured(ref mut arg) => Some(&mut arg.pat), + _ => None, + }).map(|p| { + *p = generate_unique_pattern(p.clone(), &mut generated_name_counter); + p + }); + let name = input.sig.ident.to_string(); + + // Generate the new method implementation that calls into the runime. + input.block = parse_quote!( { self.call_api_at(at, #name, &( #( #arg_names ),* )) } ); + } + + fold::fold_impl_item_method(self, input) + } + + fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl { + // Implement the trait for the `RuntimeApi` + input.self_ty = Box::new(parse_quote!( RuntimeApi )); + + // The implementation for the `RuntimeApi` is only required when compiling with the feature + // `std` or `test`. + input.attrs.push(parse_quote!( #[cfg(any(feature = "std", test))] )); + + fold::fold_item_impl(self, input) + } +} + +fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result { + let mut result = Vec::with_capacity(impls.len()); + + for impl_ in impls { + let runtime_block = extract_runtime_block_ident(extract_impl_trait(&impl_)?)?; + let (node_block, node_block_id) = generate_node_block_and_block_id_ty(&impl_.self_ty); + + let mut visitor = ApiRuntimeImplToApiRuntimeApiImpl { + runtime_block, + node_block: &node_block, + node_block_id: &node_block_id, + }; + + result.push(visitor.fold_item_impl(impl_.clone())); + } + + Ok(quote!( #( #result )* )) +} + +/// The implementation of the `impl_runtime_apis!` macro. +pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Parse all impl blocks + let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls); + let dispatch_impl = unwrap_or_error(generate_dispatch_function(&api_impls)); + let wasm_interface = unwrap_or_error(generate_wasm_interface(&api_impls)); + let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); + let base_runtime_api = unwrap_or_error(generate_runtime_api_base_structures(&api_impls)); + let api_impls_for_runtime = unwrap_or_error(generate_api_impl_for_runtime(&api_impls)); + let api_impls_for_runtime_api = unwrap_or_error(generate_api_impl_for_runtime_api(&api_impls)); + + quote!( + #hidden_includes + + #base_runtime_api + + #api_impls_for_runtime + + #api_impls_for_runtime_api + + pub mod api { + use super::*; + + #dispatch_impl + + #wasm_interface + } + ).into() +} diff --git a/substrate/core/sr-api-macros/src/lib.rs b/substrate/core/sr-api-macros/src/lib.rs new file mode 100644 index 0000000000..371cbbef6f --- /dev/null +++ b/substrate/core/sr-api-macros/src/lib.rs @@ -0,0 +1,164 @@ +// 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 . + +//! Macros for declaring and implementing runtime apis. + +#![recursion_limit = "128"] +extern crate proc_macro; +extern crate proc_macro2; +extern crate quote; +extern crate syn; + +use proc_macro::TokenStream; + +mod impl_runtime_apis; +mod decl_runtime_apis; +mod utils; +mod compile_fail_tests; + +/// Tags given trait implementations as runtime apis. +/// +/// All traits given to this macro, need to be declared with the `decl_runtime_apis!` macro. +/// The implementation of the trait should follow the declaration given to the `decl_runtime_apis!` +/// macro, besides the `Block` type that is required as first generic parameter for each runtime +/// api trait. When implementing a runtime api trait, it is required that the trait is referenced +/// by a path, e.g. `impl my_trait::MyTrait for Runtime`. The macro will use this path to access +/// the declaration of the trait for the runtime side. +/// +/// The macro also generates the implementation of the apis for the client side by generating the +/// `RuntimeApi` type. The `RuntimeApi` is hidden behind a `feature` called `std`. +/// +/// # Example +/// +/// ```rust +/// #[macro_use] +/// extern crate substrate_client; +/// # extern crate sr_primitives as runtime_primitives; +/// # extern crate substrate_primitives as primitives; +/// # #[macro_use] +/// # extern crate parity_codec_derive; +/// # extern crate serde; +/// # extern crate core; +/// # +/// # use primitives::hash::H256; +/// # use runtime_primitives::traits::{BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT}; +/// # +/// # // All the stuff we need to declare our `Block` +/// # pub type BlockNumber = u64; +/// # pub type DigestItem = runtime_primitives::generic::DigestItem; +/// # pub type Digest = runtime_primitives::generic::Digest; +/// # #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] +/// # pub struct Extrinsic {} +/// # +/// # impl serde::Serialize for Extrinsic { +/// # fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { +/// # unimplemented!() +/// # } +/// # } +/// # impl ExtrinsicT for Extrinsic { +/// # fn is_signed(&self) -> Option { +/// # unimplemented!() +/// # } +/// # } +/// # pub type Header = runtime_primitives::generic::Header; +/// # pub type Block = runtime_primitives::generic::Block; +/// # +/// # /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` +/// # /// trait are done by the `construct_runtime!` macro in a real runtime. +/// # struct Runtime {} +/// # impl GetNodeBlockType for Runtime { +/// # type NodeBlock = Block; +/// # } +/// # +/// # decl_runtime_apis! { +/// # /// Declare the api trait. +/// # pub trait Balance { +/// # /// Get the balance. +/// # fn get_balance() -> u64; +/// # /// Set the balance. +/// # fn set_balance(val: u64); +/// # } +/// # pub trait BlockBuilder { +/// # fn build_block() -> Block; +/// # } +/// # } +/// +/// /// All runtime api implementations need to be done in one call of the macro! +/// impl_runtime_apis! { +/// impl self::Balance for Runtime { +/// fn get_balance() -> u64 { +/// 1 +/// } +/// fn set_balance(_bal: u64) { +/// // Store the balance +/// } +/// } +/// +/// impl self::BlockBuilder for Runtime { +/// fn build_block() -> Block { +/// unimplemented!("Please implement me!") +/// } +/// } +/// } +/// +/// # fn main() {} +/// ``` +#[proc_macro] +pub fn impl_runtime_apis(input: TokenStream) -> TokenStream { + impl_runtime_apis::impl_runtime_apis_impl(input) +} + +/// Declares given traits as runtime apis. +/// +/// The macro will create two declarations, one for using on the client side and one for using +/// on the runtime side. The declaration for the runtime side is hidden in its own module. +/// The client side declaration gets two extra parameters per function, +/// `&self` and `at: &BlockId`. The runtime side declaration will match the given trait +/// declaration. Besides one exception, the macro adds an extra generic parameter `Block: BlockT` +/// to the client side and the runtime side. This generic parameter is usable by the user. +/// +/// For implementing these macros you should use the `impl_runtime_apis!` macro. +/// +/// # Example +/// +/// ```rust +/// #[macro_use] +/// extern crate substrate_client; +/// +/// decl_runtime_apis! { +/// /// Declare the api trait. +/// pub trait Balance { +/// /// Get the balance. +/// fn get_balance() -> u64; +/// /// Set the balance. +/// fn set_balance(val: u64); +/// } +/// +/// /// You can declare multiple api traits in one macro call. +/// /// In one module you can call the macro at maximum one time. +/// pub trait BlockBuilder { +/// /// The macro adds an explicit `Block: BlockT` generic parameter for you. +/// /// You can use this generic parameter as you would defined it manually. +/// fn build_block() -> Block; +/// } +/// } +/// +/// # fn main() {} +/// ``` +#[proc_macro] +pub fn decl_runtime_apis(input: TokenStream) -> TokenStream { + decl_runtime_apis::decl_runtime_apis_impl(input) +} diff --git a/substrate/core/sr-api-macros/src/utils.rs b/substrate/core/sr-api-macros/src/utils.rs new file mode 100644 index 0000000000..4c80adf16b --- /dev/null +++ b/substrate/core/sr-api-macros/src/utils.rs @@ -0,0 +1,97 @@ +// 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 . + +use proc_macro2::{TokenStream, Span}; +use syn::{Result, Ident, FnDecl, parse_quote, Type, FnArg}; +use quote::quote; +use std::env; + +/// Unwrap the given result, if it is an error, `compile_error!` will be generated. +pub fn unwrap_or_error(res: Result) -> TokenStream { + res.unwrap_or_else(|e| e.to_compile_error()) +} + +fn generate_hidden_includes_mod_name(unique_id: &'static str) -> Ident { + Ident::new(&format!("sr_api_hidden_includes_{}", unique_id), Span::call_site()) +} + +/// Generates the hidden includes that are required to make the macro independent from its scope. +pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream { + if env::var("CARGO_PKG_NAME").unwrap() == "substrate-client" { + TokenStream::new() + } else { + let mod_name = generate_hidden_includes_mod_name(unique_id); + quote!( + #[doc(hidden)] + mod #mod_name { + pub extern crate substrate_client as sr_api_client; + } + ) + }.into() +} + +/// Generates the access to the `subtrate_client` crate. +pub fn generate_crate_access(unique_id: &'static str) -> TokenStream { + if env::var("CARGO_PKG_NAME").unwrap() == "substrate-client" { + quote!( crate ) + } else { + let mod_name = generate_hidden_includes_mod_name(unique_id); + quote!( self::#mod_name::sr_api_client ) + }.into() +} + +/// Generates the name of the module that contains the trait declaration for the runtime. +pub fn generate_runtime_mod_name_for_trait(trait_: &Ident) -> Ident { + Ident::new(&format!("runtime_decl_for_{}", trait_.to_string()), Span::call_site()) +} + +/// Fold the given `FnDecl` to make it usable on the client side. +pub fn fold_fn_decl_for_client_side( + mut input: FnDecl, + block_id: &TokenStream, + crate_: &TokenStream +) -> FnDecl { + // Add `&` to all parameter types. + input.inputs + .iter_mut() + .filter_map(|i| match i { + FnArg::Captured(ref mut arg) => Some(&mut arg.ty), + _ => None, + }) + .filter_map(|i| match i { + Type::Reference(_) => None, + r => Some(r), + }) + .for_each(|i| *i = parse_quote!( &#i )); + + // Add `&self, at:& BlockId` as parameters to each function at the beginning. + input.inputs.insert(0, parse_quote!( at: &#block_id )); + input.inputs.insert(0, parse_quote!( &self )); + + // Wrap the output in a `Result` + input.output = { + let generate_result = |ty: &Type| { + parse_quote!( -> ::std::result::Result<#ty, #crate_::error::Error> ) + }; + + match &input.output { + syn::ReturnType::Default => generate_result(&parse_quote!( () )), + syn::ReturnType::Type(_, ref ty) => generate_result(&ty), + } + }; + + input +} diff --git a/substrate/core/sr-api-macros/tests/decl_and_impl.rs b/substrate/core/sr-api-macros/tests/decl_and_impl.rs new file mode 100644 index 0000000000..97dc2f9189 --- /dev/null +++ b/substrate/core/sr-api-macros/tests/decl_and_impl.rs @@ -0,0 +1,93 @@ +#[macro_use] +extern crate substrate_client; +extern crate sr_primitives as runtime_primitives; +extern crate substrate_primitives as primitives; +#[macro_use] +extern crate parity_codec_derive; +extern crate serde; +extern crate core; + +use primitives::hash::H256; +use runtime_primitives::traits::{ + BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT, Block as BlockT +}; +use runtime_primitives::generic::BlockId; +use substrate_client::runtime_api; +use primitives::AuthorityId; +use substrate_client::error::Result; + +// All the stuff we need to declare our `Block` +pub type BlockNumber = u64; +pub type DigestItem = runtime_primitives::generic::DigestItem; +pub type Digest = runtime_primitives::generic::Digest; +#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] +pub struct Extrinsic {} + +impl serde::Serialize for Extrinsic { + fn serialize( + &self, + _: S + ) -> ::std::result::Result where S: ::serde::Serializer { + unimplemented!() + } +} +impl ExtrinsicT for Extrinsic { + fn is_signed(&self) -> Option { + unimplemented!() + } +} +pub type Header = runtime_primitives::generic::Header; +pub type Block = runtime_primitives::generic::Block; + +/// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` +/// trait are done by the `construct_runtime!` macro in a real runtime. +pub struct Runtime {} +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; +} + +decl_runtime_apis! { + pub trait Api { + fn test(data: u64); + fn something_with_block(block: Block) -> Block; + fn function_with_two_args(data: u64, block: Block); + } +} + +impl_runtime_apis! { + impl self::Api for Runtime { + fn test(_: u64) { + unimplemented!() + } + + fn something_with_block(_: Block) -> Block { + unimplemented!() + } + + fn function_with_two_args(_: u64, _: Block) { + unimplemented!() + } + } + + impl runtime_api::Core for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn authorities() -> Vec { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialise_block(_: ::Header) { + unimplemented!() + } + } +} + +#[test] +fn test_client_side_function_signature() { + let _test: fn(&RuntimeApi, &BlockId, &u64) -> Result<()> = RuntimeApi::test; + let _something_with_block: fn(&RuntimeApi, &BlockId, &Block) -> Result = + RuntimeApi::something_with_block; +} diff --git a/substrate/core/sr-primitives/src/generic/era.rs b/substrate/core/sr-primitives/src/generic/era.rs index 71ee8fa145..bccee778be 100644 --- a/substrate/core/sr-primitives/src/generic/era.rs +++ b/substrate/core/sr-primitives/src/generic/era.rs @@ -61,7 +61,7 @@ impl Era { Era::Mortal(period, quantized_phase) } - /// Create an "immortal" transaction. + /// Create an "immortal" transaction. pub fn immortal() -> Self { Era::Immortal } @@ -75,7 +75,7 @@ impl Era { } /// Get the block number of the start of the era whose properties this object - /// describes that `current` belongs to. + /// describes that `current` belongs to. pub fn birth(self, current: u64) -> u64 { match self { Era::Immortal => 0, @@ -189,10 +189,10 @@ mod tests { assert_ne!(e.birth(10), 6); assert_ne!(e.birth(5), 6); } - + #[test] fn current_less_than_phase() { // should not panic Era::mortal(4, 3).birth(1); } -} \ No newline at end of file +} diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index 9ad97cf28c..86c93ab3d7 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -462,6 +462,35 @@ macro_rules! impl_outer_log { }; } +//TODO: https://github.com/paritytech/substrate/issues/1022 +/// Inherent data to include in a block. +#[derive(Encode, Decode)] +pub struct InherentData { + /// Current timestamp. + pub timestamp: u64, + /// Indices of offline validators. + pub consensus: Vec, +} + +impl InherentData { + /// Create a new `InherentData` instance. + pub fn new(timestamp: u64, consensus: Vec) -> Self { + Self { + timestamp, + consensus, + } + } +} + +//TODO: https://github.com/paritytech/substrate/issues/1022 +/// Error type used while checking inherents. +#[derive(Encode)] +#[cfg_attr(feature = "std", derive(Decode))] +pub enum CheckInherentError { + TimestampInFuture(u64), + Other(RuntimeString), +} + #[cfg(test)] mod tests { use substrate_primitives::hash::H256; diff --git a/substrate/core/sr-primitives/src/traits.rs b/substrate/core/sr-primitives/src/traits.rs index 85ce07ff4b..0d33d7859f 100644 --- a/substrate/core/sr-primitives/src/traits.rs +++ b/substrate/core/sr-primitives/src/traits.rs @@ -582,8 +582,6 @@ pub trait DigestItem: Codec + Member + MaybeSerializeDebugButNotDeserialize { pub trait ProvideInherent { /// The inherent that is provided. type Inherent: Encode + MaybeDecode; - /// The error used by this trait. - type Error: Encode + MaybeDecode; /// The call for setting the inherent. type Call: Encode + MaybeDecode; @@ -597,7 +595,7 @@ pub trait ProvideInherent { /// Check that the given inherent is valid. fn check_inherent Option<&Self::Call>>( block: &Block, data: Self::Inherent, extract_function: &F - ) -> Result<(), Self::Error>; + ) -> Result<(), super::CheckInherentError>; } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. @@ -629,3 +627,15 @@ pub trait ProvideRuntimeApi { /// storage, even on a `commit`. fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api>; } + +/// A marker trait for something that knows the type of the runtime block. +pub trait GetRuntimeBlockType { + /// The `RuntimeBlock` type. + type RuntimeBlock: self::Block; +} + +/// A marker trait for something that knows the type of the node block. +pub trait GetNodeBlockType { + /// The `NodeBlock` type. + type NodeBlock: self::Block; +} diff --git a/substrate/core/test-client/src/lib.rs b/substrate/core/test-client/src/lib.rs index ce504bd085..66b057350a 100644 --- a/substrate/core/test-client/src/lib.rs +++ b/substrate/core/test-client/src/lib.rs @@ -66,12 +66,12 @@ pub type Executor = client::LocalCallExecutor< >; /// Creates new client instance used for tests. -pub fn new() -> client::Client { +pub fn new() -> client::Client { new_with_backend(Arc::new(Backend::new()), false) } /// Creates new test client instance that suports changes trie creation. -pub fn new_with_changes_trie() -> client::Client { +pub fn new_with_changes_trie() -> client::Client { new_with_backend(Arc::new(Backend::new()), true) } @@ -80,7 +80,7 @@ pub fn new_with_changes_trie() -> client::Client( backend: Arc, support_changes_trie: bool -) -> client::Client>, runtime::Block, runtime::ClientWithApi> +) -> client::Client>, runtime::Block, runtime::RuntimeApi> where B: backend::LocalBackend, { diff --git a/substrate/core/test-runtime/src/lib.rs b/substrate/core/test-runtime/src/lib.rs index 65d122b498..50a0134e90 100644 --- a/substrate/core/test-runtime/src/lib.rs +++ b/substrate/core/test-runtime/src/lib.rs @@ -50,19 +50,17 @@ pub mod system; use rstd::prelude::*; use codec::{Encode, Decode}; -use client::{runtime_api::runtime::*, block_builder::api::runtime::*}; -#[cfg(feature = "std")] -use client::runtime_api::ApiExt; -use runtime_primitives::traits::{BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT}; -#[cfg(feature = "std")] -use runtime_primitives::traits::ApiRef; -use runtime_primitives::{ApplyResult, Ed25519Signature, transaction_validity::TransactionValidity}; -#[cfg(feature = "std")] -use runtime_primitives::generic::BlockId; +use client::{runtime_api as client_api, block_builder::api as block_builder_api}; +use runtime_primitives::{ + ApplyResult, Ed25519Signature, transaction_validity::TransactionValidity, + traits::{ + BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, + GetNodeBlockType, GetRuntimeBlockType + }, InherentData, CheckInherentError +}; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; use primitives::AuthorityId; -#[cfg(feature = "std")] use primitives::OpaqueMetadata; #[cfg(any(feature = "std", test))] use runtime_version::NativeVersion; @@ -172,170 +170,27 @@ pub fn changes_trie_config() -> primitives::ChangesTrieConfiguration { } pub mod test_api { + use super::AccountId; + decl_runtime_apis! { pub trait TestAPI { - fn balance_of(id: AccountId) -> u64; + fn balance_of(id: AccountId) -> u64; } } } -use test_api::runtime::TestAPI; +pub struct Runtime; -#[cfg(feature = "std")] -pub struct ClientWithApi { - call: ::std::ptr::NonNull>, - commit_on_success: ::std::cell::RefCell, - initialised_block: ::std::cell::RefCell>>, - changes: ::std::cell::RefCell, +impl GetNodeBlockType for Runtime { + type NodeBlock = Block; } -#[cfg(feature = "std")] -unsafe impl Send for ClientWithApi {} -#[cfg(feature = "std")] -unsafe impl Sync for ClientWithApi {} - -#[cfg(feature = "std")] -impl ApiExt for ClientWithApi { - fn map_api_result Result, R, E>(&self, map_call: F) -> Result { - *self.commit_on_success.borrow_mut() = false; - let res = map_call(self); - *self.commit_on_success.borrow_mut() = true; - - self.commit_on_ok(&res); - - res - } +impl GetRuntimeBlockType for Runtime { + type RuntimeBlock = Block; } -#[cfg(feature = "std")] -impl client::runtime_api::ConstructRuntimeApi for ClientWithApi { - fn construct_runtime_api<'a, T: client::runtime_api::CallApiAt>(call: &'a T) -> ApiRef<'a, Self> { - ClientWithApi { - call: unsafe { - ::std::ptr::NonNull::new_unchecked( - ::std::mem::transmute( - call as &client::runtime_api::CallApiAt - ) - ) - }, - commit_on_success: true.into(), - initialised_block: None.into(), - changes: Default::default(), - }.into() - } -} - -#[cfg(feature = "std")] -impl ClientWithApi { - fn call_api_at( - &self, - at: &BlockId, - function: &'static str, - args: &A - ) -> client::error::Result { - let res = unsafe { - self.call.as_ref().call_api_at( - at, - function, - args.encode(), - &mut *self.changes.borrow_mut(), - &mut *self.initialised_block.borrow_mut() - ).and_then(|r| - R::decode(&mut &r[..]) - .ok_or_else(|| - client::error::ErrorKind::CallResultDecode(function).into() - ) - ) - }; - - self.commit_on_ok(&res); - res - } - - fn commit_on_ok(&self, res: &Result) { - if *self.commit_on_success.borrow() { - if res.is_err() { - self.changes.borrow_mut().discard_prospective(); - } else { - self.changes.borrow_mut().commit_prospective(); - } - } - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::Core for ClientWithApi { - fn version(&self, at: &BlockId) -> Result { - self.call_api_at(at, "version", &()) - } - - fn authorities(&self, at: &BlockId) -> Result, client::error::Error> { - self.call_api_at(at, "authorities", &()) - } - - fn execute_block(&self, at: &BlockId, block: &Block) -> Result<(), client::error::Error> { - self.call_api_at(at, "execute_block", block) - } - - fn initialise_block(&self, at: &BlockId, header: &::Header) -> Result<(), client::error::Error> { - self.call_api_at(at, "initialise_block", header) - } -} - -#[cfg(feature = "std")] -impl client::block_builder::api::BlockBuilder for ClientWithApi { - fn apply_extrinsic(&self, at: &BlockId, extrinsic: &::Extrinsic) -> Result { - self.call_api_at(at, "apply_extrinsic", extrinsic) - } - - fn finalise_block(&self, at: &BlockId) -> Result<::Header, client::error::Error> { - self.call_api_at(at, "finalise_block", &()) - } - - fn inherent_extrinsics( - &self, at: &BlockId, inherent: &Inherent - ) -> Result, client::error::Error> { - self.call_api_at(at, "inherent_extrinsics", inherent) - } - - fn check_inherents(&self, at: &BlockId, block: &Block, inherent: &Inherent) -> Result, client::error::Error> { - self.call_api_at(at, "check_inherents", &(block, inherent)) - } - - fn random_seed(&self, at: &BlockId) -> Result<::Hash, client::error::Error> { - self.call_api_at(at, "random_seed", &()) - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::TaggedTransactionQueue for ClientWithApi { - fn validate_transaction( - &self, - at: &BlockId, - utx: &::Extrinsic - ) -> Result { - self.call_api_at(at, "validate_transaction", utx) - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::Metadata for ClientWithApi { - fn metadata(&self, at: &BlockId) -> Result { - self.call_api_at(at, "metadata", &()) - } -} - -#[cfg(feature = "std")] -impl test_api::TestAPI for ClientWithApi { - fn balance_of(&self, at: &BlockId, id: &AccountId) -> Result { - self.call_api_at(at, "balance_of", id) - } -} - -struct Runtime; - impl_runtime_apis! { - impl Core for Runtime { + impl client_api::Core for Runtime { fn version() -> RuntimeVersion { version() } @@ -353,13 +208,19 @@ impl_runtime_apis! { } } - impl TaggedTransactionQueue for Runtime { + impl client_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + } + + impl client_api::TaggedTransactionQueue for Runtime { fn validate_transaction(utx: ::Extrinsic) -> TransactionValidity { system::validate_transaction(utx) } } - impl BlockBuilder for Runtime { + impl block_builder_api::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { system::execute_transaction(extrinsic) } @@ -368,11 +229,11 @@ impl_runtime_apis! { system::finalise_block() } - fn inherent_extrinsics(_data: u32) -> Vec { + fn inherent_extrinsics(_data: InherentData) -> Vec<::Extrinsic> { unimplemented!() } - fn check_inherents(_block: Block, _data: u32) -> Result<(), u32> { + fn check_inherents(_block: Block, _data: InherentData) -> Result<(), CheckInherentError> { unimplemented!() } @@ -381,7 +242,7 @@ impl_runtime_apis! { } } - impl TestAPI for Runtime { + impl self::test_api::TestAPI for Runtime { fn balance_of(id: AccountId) -> u64 { system::balance_of(id) } diff --git a/substrate/core/test-runtime/wasm/Cargo.lock b/substrate/core/test-runtime/wasm/Cargo.lock index c268f0c400..ddba821e1f 100644 --- a/substrate/core/test-runtime/wasm/Cargo.lock +++ b/substrate/core/test-runtime/wasm/Cargo.lock @@ -768,7 +768,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -835,6 +835,15 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sr-api-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sr-io" version = "0.1.0" @@ -936,6 +945,7 @@ dependencies = [ "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-api-macros 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", @@ -1095,7 +1105,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.6" +version = "0.15.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1550,7 +1560,7 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.6 (registry+https://github.com/rust-lang/crates.io-index)" = "854b08a640fc8f54728fb95321e3ec485b365a97fe47609797c671addd1dde69" +"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 1e1603db25f1ae1270c264dafde73776dd0499cf..46d88c5cbc8134e9e4f3dbfafbff615f7de335d4 100644 GIT binary patch delta 7713 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 delta 7268 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 Default for NodeConfig where F: substrate_service::ServiceFactory { construct_service_factory! { struct Factory { Block = Block, - RuntimeApi = ClientWithApi, + RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = node_executor::Executor, - FullTransactionPoolApi = transaction_pool::ChainApi, FullExecutor, Block, ClientWithApi>, Block> + FullTransactionPoolApi = transaction_pool::ChainApi, FullExecutor, Block, RuntimeApi>, Block> { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, - LightTransactionPoolApi = transaction_pool::ChainApi, LightExecutor, Block, ClientWithApi>, Block> + LightTransactionPoolApi = transaction_pool::ChainApi, LightExecutor, Block, RuntimeApi>, Block> { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, Genesis = GenesisConfig, Configuration = NodeConfig, @@ -125,7 +125,7 @@ construct_service_factory! { { |config, executor| >::new(config, executor) }, FullImportQueue = AuraImportQueue, NothingExtra> { |config: &mut FactoryFullConfiguration , client: Arc>| { - let (block_import, link_half) = grandpa::block_import::<_, _, _, ClientWithApi, FullClient>(client.clone(), client)?; + let (block_import, link_half) = grandpa::block_import::<_, _, _, RuntimeApi, FullClient>(client.clone(), client)?; let block_import = Arc::new(block_import); config.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index a5f1fd96f7..6abd5c2b05 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -54,27 +54,21 @@ extern crate srml_upgrade_key as upgrade_key; extern crate sr_version as version; extern crate node_primitives; -#[cfg(feature = "std")] -use codec::{Encode, Decode}; use rstd::prelude::*; use substrate_primitives::u32_trait::{_2, _4}; use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature }; -use grandpa::fg_primitives::{runtime::GrandpaApi, ScheduledChange, id::*}; -#[cfg(feature = "std")] -use node_primitives::Block as GBlock; -use client::{block_builder::api::runtime::*, runtime_api::{runtime::*, id::*}}; -#[cfg(feature = "std")] -use client::runtime_api::ApiExt; -use runtime_primitives::ApplyResult; +use grandpa::fg_primitives::{self, ScheduledChange, id::*}; +use client::{ + block_builder::api as block_builder_api, runtime_api::{self as client_api, id::*} +}; +use runtime_primitives::{ApplyResult, CheckInherentError}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::generic; -use runtime_primitives::traits::{Convert, BlakeTwo256, Block as BlockT, DigestFor, NumberFor}; -#[cfg(feature = "std")] -use runtime_primitives::traits::ApiRef; -#[cfg(feature = "std")] -use substrate_primitives::AuthorityId; +use runtime_primitives::traits::{ + Convert, BlakeTwo256, Block as BlockT, DigestFor, NumberFor, ProvideInherent +}; use version::RuntimeVersion; use council::{motions as council_motions, voting as council_voting}; #[cfg(feature = "std")] @@ -215,7 +209,7 @@ impl grandpa::Trait for Runtime { construct_runtime!( pub enum Runtime with Log(InternalLog: DigestItem) where Block = Block, - UncheckedExtrinsic = UncheckedExtrinsic + NodeBlock = node_primitives::Block { System: system::{default, Log(ChangesTrieRoot)}, Timestamp: timestamp::{Module, Call, Storage, Config, Inherent}, @@ -237,6 +231,7 @@ construct_runtime!( /// The address format for describing accounts. pub use balances::address::Address as RawAddress; + /// The address format for describing accounts. pub type Address = balances::Address; /// Block header type as expected by this runtime. @@ -254,168 +249,8 @@ pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = executive::Executive, Balances, AllModules>; -#[cfg(feature = "std")] -pub struct ClientWithApi { - call: ::std::ptr::NonNull>, - commit_on_success: ::std::cell::RefCell, - initialised_block: ::std::cell::RefCell>, - changes: ::std::cell::RefCell, -} - -#[cfg(feature = "std")] -unsafe impl Send for ClientWithApi {} -#[cfg(feature = "std")] -unsafe impl Sync for ClientWithApi {} - -#[cfg(feature = "std")] -impl ApiExt for ClientWithApi { - fn map_api_result Result, R, E>(&self, map_call: F) -> Result { - *self.commit_on_success.borrow_mut() = false; - let res = map_call(self); - *self.commit_on_success.borrow_mut() = true; - - self.commit_on_ok(&res); - - res - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::ConstructRuntimeApi for ClientWithApi { - fn construct_runtime_api<'a, T: client::runtime_api::CallApiAt>(call: &'a T) -> ApiRef<'a, Self> { - ClientWithApi { - call: unsafe { - ::std::ptr::NonNull::new_unchecked( - ::std::mem::transmute( - call as &client::runtime_api::CallApiAt - ) - ) - }, - commit_on_success: true.into(), - initialised_block: None.into(), - changes: Default::default(), - }.into() - } -} - -#[cfg(feature = "std")] -impl ClientWithApi { - fn call_api_at( - &self, - at: &GBlockId, - function: &'static str, - args: &A - ) -> client::error::Result { - let res = unsafe { - self.call.as_ref().call_api_at( - at, - function, - args.encode(), - &mut *self.changes.borrow_mut(), - &mut *self.initialised_block.borrow_mut() - ).and_then(|r| - R::decode(&mut &r[..]) - .ok_or_else(|| - client::error::ErrorKind::CallResultDecode(function).into() - ) - ) - }; - - self.commit_on_ok(&res); - res - } - - fn commit_on_ok(&self, res: &Result) { - if *self.commit_on_success.borrow() { - if res.is_err() { - self.changes.borrow_mut().discard_prospective(); - } else { - self.changes.borrow_mut().commit_prospective(); - } - } - } -} - -#[cfg(feature = "std")] -type GBlockId = generic::BlockId; - -#[cfg(feature = "std")] -impl client::runtime_api::Core for ClientWithApi { - fn version(&self, at: &GBlockId) -> Result { - self.call_api_at(at, "version", &()) - } - - fn authorities(&self, at: &GBlockId) -> Result, client::error::Error> { - self.call_api_at(at, "authorities", &()) - } - - fn execute_block(&self, at: &GBlockId, block: &GBlock) -> Result<(), client::error::Error> { - self.call_api_at(at, "execute_block", block) - } - - fn initialise_block(&self, at: &GBlockId, header: &::Header) -> Result<(), client::error::Error> { - self.call_api_at(at, "initialise_block", header) - } -} - -#[cfg(feature = "std")] -impl client::block_builder::api::BlockBuilder for ClientWithApi { - fn apply_extrinsic(&self, at: &GBlockId, extrinsic: &::Extrinsic) -> Result { - self.call_api_at(at, "apply_extrinsic", extrinsic) - } - - fn finalise_block(&self, at: &GBlockId) -> Result<::Header, client::error::Error> { - self.call_api_at(at, "finalise_block", &()) - } - - fn inherent_extrinsics( - &self, at: &GBlockId, inherent: &Inherent - ) -> Result, client::error::Error> { - self.call_api_at(at, "inherent_extrinsics", inherent) - } - - fn check_inherents(&self, at: &GBlockId, block: &GBlock, inherent: &Inherent) -> Result, client::error::Error> { - self.call_api_at(at, "check_inherents", &(block, inherent)) - } - - fn random_seed(&self, at: &GBlockId) -> Result<::Hash, client::error::Error> { - self.call_api_at(at, "random_seed", &()) - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::TaggedTransactionQueue for ClientWithApi { - fn validate_transaction( - &self, - at: &GBlockId, - utx: &::Extrinsic - ) -> Result { - self.call_api_at(at, "validate_transaction", utx) - } -} - -#[cfg(feature = "std")] -impl client::runtime_api::Metadata for ClientWithApi { - fn metadata(&self, at: &GBlockId) -> Result { - self.call_api_at(at, "metadata", &()) - } -} - -#[cfg(feature = "std")] -impl substrate_finality_grandpa_primitives::GrandpaApi for ClientWithApi { - fn grandpa_pending_change(&self, at: &GBlockId, digest: &DigestFor) - -> Result>>, client::error::Error> { - self.call_api_at(at, "grandpa_pending_change", digest) - } - - fn grandpa_authorities(&self, at: &GBlockId) - -> Result, client::error::Error> { - self.call_api_at(at, "grandpa_authorities", &()) - } -} - impl_runtime_apis! { - impl Core for Runtime { + impl client_api::Core for Runtime { fn version() -> RuntimeVersion { VERSION } @@ -433,13 +268,13 @@ impl_runtime_apis! { } } - impl Metadata for Runtime { + impl client_api::Metadata for Runtime { fn metadata() -> OpaqueMetadata { Runtime::metadata().into() } } - impl BlockBuilder for Runtime { + impl block_builder_api::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { Executive::apply_extrinsic(extrinsic) } @@ -448,12 +283,27 @@ impl_runtime_apis! { Executive::finalise_block() } - fn inherent_extrinsics(data: InherentData) -> Vec { - data.create_inherent_extrinsics() + fn inherent_extrinsics(data: runtime_primitives::InherentData) -> Vec<::Extrinsic> { + let mut inherent = Vec::new(); + + inherent.extend( + Timestamp::create_inherent_extrinsics(data.timestamp) + .into_iter() + .map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Timestamp(v.1)))) + ); + + inherent.extend( + Consensus::create_inherent_extrinsics(data.consensus) + .into_iter() + .map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Consensus(v.1)))) + ); + + inherent.as_mut_slice().sort_unstable_by_key(|v| v.0); + inherent.into_iter().map(|v| v.1).collect() } - fn check_inherents(block: Block, data: InherentData) -> Result<(), InherentError> { - data.check_inherents(block) + fn check_inherents(block: Block, data: runtime_primitives::InherentData) -> Result<(), CheckInherentError> { + InherentData::check_inherents(data, block) } fn random_seed() -> ::Hash { @@ -461,13 +311,13 @@ impl_runtime_apis! { } } - impl TaggedTransactionQueue for Runtime { + impl client_api::TaggedTransactionQueue for Runtime { fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity { Executive::validate_transaction(tx) } } - impl GrandpaApi for Runtime { + impl fg_primitives::GrandpaApi for Runtime { fn grandpa_pending_change(digest: DigestFor) -> Option>> { diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index 83b4a4cc4a..55354c02e9 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -829,7 +829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -896,6 +896,15 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sr-api-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sr-io" version = "0.1.0" @@ -1240,6 +1249,7 @@ dependencies = [ "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-api-macros 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", @@ -1394,7 +1404,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.6" +version = "0.15.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1851,7 +1861,7 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.6 (registry+https://github.com/rust-lang/crates.io-index)" = "854b08a640fc8f54728fb95321e3ec485b365a97fe47609797c671addd1dde69" +"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 56a3e347cea8854f841e6af0906632c55391fdd3..a12cd6a07e1ef6c060c673e11fd1af1cadbf66c5 100644 GIT binary patch delta 110544 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

q}LnMbV)+Acbq_ff3qt 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 Module { impl ProvideInherent for Module { type Inherent = Vec; type Call = Call; - type Error = RuntimeString; fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> { vec![(T::NOTE_OFFLINE_POSITION, Call::note_offline(data))] @@ -257,7 +256,7 @@ impl ProvideInherent for Module { fn check_inherent Option<&Self::Call>>( block: &Block, data: Self::Inherent, extract_function: &F - ) -> result::Result<(), Self::Error> { + ) -> result::Result<(), CheckInherentError> { let noted_offline = block .extrinsics().get(T::NOTE_OFFLINE_POSITION as usize) .and_then(|xt| match extract_function(&xt) { @@ -267,7 +266,7 @@ impl ProvideInherent for Module { noted_offline.iter().try_for_each(|n| if !data.contains(n) { - Err("Online node marked offline".into()) + Err(CheckInherentError::Other("Online node marked offline".into())) } else { Ok(()) } diff --git a/substrate/srml/support/src/inherent.rs b/substrate/srml/support/src/inherent.rs index f87a41806a..8be51f4224 100644 --- a/substrate/srml/support/src/inherent.rs +++ b/substrate/srml/support/src/inherent.rs @@ -17,7 +17,9 @@ #[doc(hidden)] pub use rstd::{result::Result, vec::Vec}; #[doc(hidden)] -pub use runtime_primitives::traits::ProvideInherent; +pub use runtime_primitives::{ + traits::{ProvideInherent, Block as BlockT}, CheckInherentError, InherentData +}; /// Implement the outer inherent. @@ -39,50 +41,43 @@ pub use runtime_primitives::traits::ProvideInherent; macro_rules! impl_outer_inherent { ( $(#[$attr:meta])* - pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident { - $( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )* + pub struct $name:ident where Block = $block:ident { + $( $module:ident: $module_ty:ident, )* } ) => { impl_outer_inherent!( $( #[$attr] )* - pub struct $name where Block = $block, UncheckedExtrinsic = $unchecked, Error = InherentError, Call = Call { - $( $module: $module_ty $(export Error as $error_name)*, )* + pub struct $name where Block = $block, Call = Call { + $( $module: $module_ty, )* } ); }; ( $(#[$attr:meta])* - pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident, Error = $error:ident { - $( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )* + pub struct $name:ident where Block = $block:ident { + $( $module:ident: $module_ty:ident, )* } ) => { impl_outer_inherent!( $( #[$attr] )* - pub struct $name where Block = $block, UncheckedExtrinsic = $unchecked, Error = $error, Call = Call { - $( $module: $module_ty $(export Error as $error_name)*, )* + pub struct $name where Block = $block, Call = Call { + $( $module: $module_ty, )* } ); }; ( $(#[$attr:meta])* - pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident, Error = $error:ident, Call = $call:ident { - $( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )* + pub struct $name:ident where Block = $block:ident, Call = $call:ident { + $( $module:ident: $module_ty:ident, )* } ) => { $( #[$attr] )* - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Encode, Decode)] /// Inherent data to include in a block. pub struct $name { $( $module: <$module_ty as $crate::inherent::ProvideInherent>::Inherent, )* } - $( - $( - pub type $error_name =<$module_ty as $crate::inherent::ProvideInherent>::Error; - )* - )* - impl $name { /// Create a new instance. pub fn new( $( $module: <$module_ty as $crate::inherent::ProvideInherent>::Inherent ),* ) -> Self { @@ -91,38 +86,19 @@ macro_rules! impl_outer_inherent { } } - fn create_inherent_extrinsics(self) -> Vec<$unchecked> { - let mut inherent = $crate::inherent::Vec::new(); - - $( - inherent.extend( - <$module_ty as $crate::inherent::ProvideInherent>::create_inherent_extrinsics(self.$module) - .into_iter() - .map(|v| (v.0, $unchecked::new_unsigned($call::$module_ty(v.1)))) - ); - )* - - inherent.as_mut_slice().sort_unstable_by_key(|v| v.0); - inherent.into_iter().map(|v| v.1).collect() - } - - fn check_inherents(self, block: $block) -> $crate::inherent::Result<(), $error> { + fn check_inherents( + data: $crate::inherent::InherentData, + block: $block + ) -> $crate::inherent::Result<(), $crate::inherent::CheckInherentError> { $( <$module_ty as $crate::inherent::ProvideInherent>::check_inherent( - &block, self.$module, &|xt| match xt.function { + &block, data.$module, &|xt| match xt.function { Call::$module_ty(ref data) => Some(data), _ => None, - }).map_err($error::$module_ty)?; + })?; )* Ok(()) } } - - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Encode)] - #[cfg_attr(feature = "std", derive(Decode))] - pub enum $error { - $( $module_ty(<$module_ty as $crate::inherent::ProvideInherent>::Error), )* - } }; } diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 20cf57ca71..adccf997eb 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -122,4 +122,5 @@ pub enum Void {} pub use mashup::*; #[cfg(feature = "std")] +#[doc(hidden)] pub use serde_derive::*; diff --git a/substrate/srml/support/src/runtime.rs b/substrate/srml/support/src/runtime.rs index 86eaaf1b04..0376179e38 100644 --- a/substrate/srml/support/src/runtime.rs +++ b/substrate/srml/support/src/runtime.rs @@ -20,7 +20,10 @@ /// /// ```nocompile /// construct_runtime!( -/// pub enum Runtime with Log(interalIdent: DigestItem) { +/// pub enum Runtime with Log(interalIdent: DigestItem) where +/// Block = Block, +/// NodeBlock = runtime::Block +/// { /// System: system, /// Test: test::{default, Log(Test)}, /// Test2: test_with_long_module::{Module}, @@ -48,7 +51,9 @@ macro_rules! construct_runtime { ( pub enum $runtime:ident with Log ($log_internal:ident: DigestItem<$( $log_genarg:ty ),+>) - where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident + where + Block = $block:ident, + NodeBlock = $node_block:ty { $( $rest:tt )* } @@ -56,7 +61,7 @@ macro_rules! construct_runtime { construct_runtime!( $runtime; $block; - $unchecked; + $node_block; $log_internal < $( $log_genarg ),* >; ; $( $rest )* @@ -65,7 +70,7 @@ macro_rules! construct_runtime { ( $runtime:ident; $block:ident; - $unchecked:ident; + $node_block:ty; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -92,7 +97,7 @@ macro_rules! construct_runtime { construct_runtime!( $runtime; $block; - $unchecked; + $node_block; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -119,7 +124,7 @@ macro_rules! construct_runtime { ( $runtime:ident; $block:ident; - $unchecked:ident; + $node_block:ty; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -153,7 +158,7 @@ macro_rules! construct_runtime { construct_runtime!( $runtime; $block; - $unchecked; + $node_block; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -186,7 +191,7 @@ macro_rules! construct_runtime { ( $runtime:ident; $block:ident; - $unchecked:ident; + $node_block:ty; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -219,7 +224,7 @@ macro_rules! construct_runtime { construct_runtime!( $runtime; $block; - $unchecked; + $node_block; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -251,7 +256,7 @@ macro_rules! construct_runtime { ( $runtime:ident; $block:ident; - $unchecked:ident; + $node_block:ty; $log_internal:ident <$( $log_genarg:ty ),+>; $( $name:ident: $module:ident::{ @@ -273,6 +278,12 @@ macro_rules! construct_runtime { #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct $runtime; + impl $crate::runtime_primitives::traits::GetNodeBlockType for $runtime { + type NodeBlock = $node_block; + } + impl $crate::runtime_primitives::traits::GetRuntimeBlockType for $runtime { + type RuntimeBlock = $block; + } __decl_outer_event!( $runtime; $( @@ -326,7 +337,6 @@ macro_rules! construct_runtime { __decl_outer_inherent!( $runtime; $block; - $unchecked; ; $( $name: $module::{ $( $modules $( <$modules_generic> )* ),* } @@ -1052,7 +1062,6 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $unchecked:ident; $( $parsed_modules:ident :: $parsed_name:ident ),*; $name:ident: $module:ident::{ Inherent $(, $modules:ident $( <$modules_generic:ident> )* )* @@ -1064,7 +1073,6 @@ macro_rules! __decl_outer_inherent { __decl_outer_inherent!( $runtime; $block; - $unchecked; $( $parsed_modules :: $parsed_name, )* $module::$name; $( $rest_name: $rest_module::{ @@ -1076,7 +1084,6 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $unchecked:ident; $( $parsed_modules:ident :: $parsed_name:ident ),*; $name:ident: $module:ident::{ $ingore:ident $( <$ignor:ident> )* $(, $modules:ident $( <$modules_generic:ident> )* )* @@ -1088,7 +1095,6 @@ macro_rules! __decl_outer_inherent { __decl_outer_inherent!( $runtime; $block; - $unchecked; $( $parsed_modules :: $parsed_name ),*; $name: $module::{ $( $modules $( <$modules_generic> )* ),* } $( @@ -1101,7 +1107,6 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $unchecked:ident; $( $parsed_modules:ident :: $parsed_name:ident ),*; $name:ident: $module:ident::{} $(, $rest_name:ident : $rest_module:ident::{ @@ -1111,7 +1116,6 @@ macro_rules! __decl_outer_inherent { __decl_outer_inherent!( $runtime; $block; - $unchecked; $( $parsed_modules :: $parsed_name ),*; $( $rest_name: $rest_module::{ @@ -1123,15 +1127,14 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $unchecked:ident; $( $parsed_modules:ident :: $parsed_name:ident ),*; ; ) => { substrate_generate_ident_name! { impl_outer_inherent!( - pub struct InherentData where Block = $block, UncheckedExtrinsic = $unchecked { + pub struct InherentData where Block = $block { $( - $parsed_modules: $parsed_name export Error as "inherent-error-ident" $parsed_name, + $parsed_modules: $parsed_name, )* } ); diff --git a/substrate/srml/timestamp/src/lib.rs b/substrate/srml/timestamp/src/lib.rs index db1e2934db..422fd1faad 100644 --- a/substrate/srml/timestamp/src/lib.rs +++ b/substrate/srml/timestamp/src/lib.rs @@ -52,7 +52,7 @@ extern crate parity_codec_derive; use codec::HasCompact; use runtime_support::{StorageValue, Parameter}; use runtime_support::dispatch::Result; -use runtime_primitives::RuntimeString; +use runtime_primitives::CheckInherentError; use runtime_primitives::traits::{ As, SimpleArithmetic, Zero, ProvideInherent, Block as BlockT, Extrinsic }; @@ -131,17 +131,9 @@ impl Module { } } -#[derive(Encode)] -#[cfg_attr(feature = "std", derive(Decode))] -pub enum InherentError { - Other(RuntimeString), - TimestampInFuture(u64), -} - impl ProvideInherent for Module { type Inherent = T::Moment; type Call = Call; - type Error = InherentError; fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> { vec![(T::TIMESTAMP_SET_POSITION, Call::set(data.into()))] @@ -149,19 +141,19 @@ impl ProvideInherent for Module { fn check_inherent Option<&Self::Call>>( block: &Block, data: Self::Inherent, extract_function: &F - ) -> result::Result<(), Self::Error> { + ) -> result::Result<(), CheckInherentError> { const MAX_TIMESTAMP_DRIFT: u64 = 60; let xt = block.extrinsics().get(T::TIMESTAMP_SET_POSITION as usize) - .ok_or_else(|| InherentError::Other("No valid timestamp inherent in block".into()))?; + .ok_or_else(|| CheckInherentError::Other("No valid timestamp inherent in block".into()))?; let t = match (xt.is_signed(), extract_function(&xt)) { (Some(false), Some(Call::set(ref t))) => t.clone(), - _ => return Err(InherentError::Other("No valid timestamp inherent in block".into())), + _ => return Err(CheckInherentError::Other("No valid timestamp inherent in block".into())), }.into().as_(); if t > data.as_() + MAX_TIMESTAMP_DRIFT { - Err(InherentError::TimestampInFuture(t)) + Err(CheckInherentError::TimestampInFuture(t)) } else { Ok(()) }