Make runtime api generate version and identifier information (#1226)

* Make `decl_runtime_apis!` implement `RuntimeApiInfo` for all runtime
apis

* Make the runtime side generate the info constants as well

* Make `RuntimeApiInfo` implementation use the correct generics

* Adds a test for the runtime api info stuff

* Remove duplicated code by using block from `test-client`

* Adds `compile_fail` tests for `api_version`

* Adds documentation for `api_version`

* Make `impl_runtime_apis!` generate `RUNTIME_API_VERSIONS`

* Update documentation and tests for `RUNTIME_API_VERSIONS`

* Implement `has_api` by using the `RuntimeApiInfo`

* Make `impl_runtime_apis` check that trait identifiers are unique

* Prefix all runtime api function with the corresponding trait

So `execute_block` will be called `Core_execute_block`.
This makes it possible to have traits implement a function with the
same name.

* Rebase master

* Update after master rebase
This commit is contained in:
Bastian Köcher
2018-12-10 11:48:07 +01:00
committed by GitHub
parent a4a67ccbe7
commit 1f6719346f
25 changed files with 661 additions and 396 deletions
+3 -3
View File
@@ -2710,14 +2710,14 @@ dependencies = [
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)",
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.24 (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",
"sr-version 0.1.0",
"substrate-client 0.1.0",
"substrate-primitives 0.1.0",
"substrate-test-client 0.1.0",
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
+23 -7
View File
@@ -32,7 +32,7 @@ use runtime_primitives::traits::{
ApiRef, ProvideRuntimeApi, Digest, DigestItem,
};
use runtime_primitives::BuildStorage;
use runtime_api::{Core as CoreAPI, CallApiAt, TaggedTransactionQueue, ConstructRuntimeApi};
use runtime_api::{Core as CoreAPI, CallRuntimeAt, TaggedTransactionQueue, ConstructRuntimeApi};
use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash};
use primitives::storage::{StorageKey, StorageData};
use primitives::storage::well_known_keys;
@@ -288,7 +288,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
pub fn authorities_at(&self, id: &BlockId<Block>) -> error::Result<Vec<AuthorityId>> {
match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) {
Some(cached_value) => Ok(cached_value),
None => self.executor.call(id, "authorities",&[])
None => self.executor.call(id, "Core_authorities",&[])
.and_then(|r| Vec::<AuthorityId>::decode(&mut &r.return_data[..])
.ok_or(error::ErrorKind::InvalidAuthoritiesSet.into()))
}
@@ -635,7 +635,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
let mut r = self.executor.call_at_state(
transaction_state,
&mut overlay,
"execute_block",
"Core_execute_block",
&<Block as BlockT>::new(import_headers.pre().clone(), body.clone().unwrap_or_default()).encode(),
match (origin, self.block_execution_strategy) {
(BlockOrigin::NetworkInitialSync, _) | (_, ExecutionStrategy::NativeWhenPossible) =>
@@ -1034,7 +1034,7 @@ impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
}
}
impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
Block: BlockT<Hash=H256>,
@@ -1050,7 +1050,8 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
initialised_block: &mut Option<BlockId<Block>>,
) -> error::Result<Vec<u8>> {
//TODO: Find a better way to prevent double block initialization
if function != "initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) {
if function != "Core_initialise_block"
&& initialised_block.map(|id| id != *at).unwrap_or(true) {
let parent = at;
let header = <<Block as BlockT>::Header as HeaderT>::new(
self.block_number_from_id(parent)?
@@ -1062,12 +1063,16 @@ impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA> where
.ok_or_else(|| error::ErrorKind::UnknownBlock(format!("{:?}", parent)))?,
Default::default()
);
self.call_at_state(at, "initialise_block", header.encode(), changes)?;
self.call_at_state(at, "Core_initialise_block", header.encode(), changes)?;
*initialised_block = Some(*at);
}
self.call_at_state(at, function, args, changes)
}
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion> {
self.runtime_version_at(at)
}
}
@@ -1238,7 +1243,7 @@ pub(crate) mod tests {
use runtime_primitives::generic::DigestItem;
use test_client::{self, TestClient};
use consensus::BlockOrigin;
use test_client::client::backend::Backend as TestBackend;
use test_client::client::{backend::Backend as TestBackend, runtime_api::ApiExt};
use test_client::BlockBuilderExt;
use test_client::runtime::{self, Block, Transfer, RuntimeApi, test_api::TestAPI};
@@ -1335,6 +1340,17 @@ pub(crate) mod tests {
);
}
#[test]
fn runtime_api_has_test_api() {
let client = test_client::new();
assert!(
client.runtime_api().has_api::<TestAPI<Block>>(
&BlockId::Number(client.info().unwrap().chain.best_number),
).unwrap()
);
}
#[test]
fn authorities_call_works() {
let client = test_client::new();
+6 -6
View File
@@ -91,7 +91,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&executor(),
"initialise_block",
"Core_initialise_block",
&header.encode(),
ExecutionStrategy::NativeWhenPossible,
).unwrap();
@@ -102,7 +102,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&executor(),
"apply_extrinsic",
"BlockBuilder_apply_extrinsic",
&tx.encode(),
ExecutionStrategy::NativeWhenPossible,
).unwrap();
@@ -113,7 +113,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&executor(),
"finalise_block",
"BlockBuilder_finalise_block",
&[],
ExecutionStrategy::NativeWhenPossible,
).unwrap();
@@ -157,7 +157,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&executor(),
"execute_block",
"Core_execute_block",
&b1data,
ExecutionStrategy::NativeWhenPossible,
).unwrap();
@@ -182,7 +182,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&executor(),
"execute_block",
"Core_execute_block",
&b1data,
ExecutionStrategy::AlwaysWasm,
).unwrap();
@@ -208,7 +208,7 @@ mod tests {
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
&Executor::new(),
"execute_block",
"Core_execute_block",
&b1data,
ExecutionStrategy::NativeWhenPossible,
).unwrap();
@@ -166,7 +166,7 @@ mod tests {
.unwrap().storage_root(::std::iter::empty()).0;
// 'fetch' execution proof from remote node
let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "authorities", &[]).unwrap().1;
let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "Core_authorities", &[]).unwrap().1;
// check remote execution proof locally
let local_executor = test_client::LocalExecutor::new();
@@ -179,7 +179,7 @@ mod tests {
extrinsics_root: Default::default(),
digest: Default::default(),
},
method: "authorities".into(),
method: "Core_authorities".into(),
call_data: vec![],
retry_count: None,
}, remote_execution_proof).unwrap();
+21 -47
View File
@@ -21,12 +21,13 @@
pub use state_machine::OverlayedChanges;
#[doc(hidden)]
pub use runtime_primitives::{
traits::{Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef}, generic::BlockId,
transaction_validity::TransactionValidity
traits::{Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef, RuntimeApiInfo},
generic::BlockId, transaction_validity::TransactionValidity
};
pub use runtime_version::{ApiId, RuntimeVersion};
#[doc(hidden)]
pub use rstd::slice;
pub use runtime_version::{ApiId, RuntimeVersion, ApisVec, create_apis_vec};
#[doc(hidden)]
pub use rstd::{slice, mem};
#[cfg(feature = "std")]
use rstd::result;
pub use codec::{Encode, Decode};
@@ -38,14 +39,16 @@ use primitives::{AuthorityId, OpaqueMetadata};
/// Something that can be constructed to a runtime api.
#[cfg(feature = "std")]
pub trait ConstructRuntimeApi<Block: BlockT>: Sized {
pub trait ConstructRuntimeApi<Block: BlockT> {
/// Construct an instance of the runtime api.
fn construct_runtime_api<'a, T: CallApiAt<Block>>(call: &'a T) -> ApiRef<'a, Self>;
fn construct_runtime_api<'a, T: CallRuntimeAt<Block>>(
call: &'a T
) -> ApiRef<'a, Self> where Self: Sized;
}
/// An extension for the `RuntimeApi`.
#[cfg(feature = "std")]
pub trait ApiExt {
pub trait ApiExt<Block: BlockT> {
/// The given closure will be called with api instance. Inside the closure any api call is
/// allowed. After doing the api call, the closure is allowed to map the `Result` to a
/// different `Result` type. This can be important, as the internal data structure that keeps
@@ -54,12 +57,18 @@ pub trait ApiExt {
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
&self,
map_call: F
) -> result::Result<R, E>;
) -> result::Result<R, E> where Self: Sized;
/// Checks if the given api is implemented and versions match.
fn has_api<A: RuntimeApiInfo + ?Sized>(
&self,
at: &BlockId<Block>
) -> error::Result<bool> where Self: Sized;
}
/// Something that can call the runtime api at a given block.
/// Something that can call into the runtime at a given block.
#[cfg(feature = "std")]
pub trait CallApiAt<Block: BlockT> {
pub trait CallRuntimeAt<Block: BlockT> {
/// Calls the given api function with the given encoded arguments at the given block
/// and returns the encoded result.
fn call_api_at(
@@ -71,43 +80,8 @@ pub trait CallApiAt<Block: BlockT> {
initialised_block: &mut Option<BlockId<Block>>,
) -> error::Result<Vec<u8>>;
/// Call the given api function with strong arguments at the given block
/// and returns the decoded result.
fn call_api_at_strong<In: Encode, Out: Decode>(
&self,
at: &BlockId<Block>,
function: &'static str,
args: &In,
changes: &mut OverlayedChanges,
initialised_block: &mut Option<BlockId<Block>>,
) -> error::Result<Out> where Self: Sized {
let raw = self.call_api_at(
at,
function,
args.encode(),
changes,
initialised_block,
)?;
match Out::decode(&mut &raw[..]) {
Some(out) => Ok(out),
None => bail!(error::ErrorKind::CallResultDecode(function)),
}
}
}
/// The ApiIds for the various standard runtime APIs.
pub mod id {
use super::ApiId;
/// ApiId for the BlockBuilder trait.
pub const BLOCK_BUILDER: ApiId = *b"blkbuild";
/// ApiId for the TaggedTransactionQueue trait.
pub const TAGGED_TRANSACTION_QUEUE: ApiId = *b"validatx";
/// ApiId for the Metadata trait.
pub const METADATA: ApiId = *b"metadata";
/// Returns the runtime version at the given block.
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion>;
}
decl_runtime_apis! {
@@ -61,7 +61,7 @@ fn fetch_cached_runtime_version<'a, E: Externalities<Blake2Hasher>>(
let maybe_runtime_preproc = cache.entry(gen_cache_key(code))
.or_insert_with(|| match WasmModule::from_buffer(code) {
Ok(module) => {
let version = wasm_executor.call_in_wasm_module(ext, heap_pages, &module, "version", &[])
let version = wasm_executor.call_in_wasm_module(ext, heap_pages, &module, "Core_version", &[])
.ok()
.and_then(|v| RuntimeVersion::decode(&mut v.as_slice()));
RuntimePreproc::ValidCode(module, version)
+9 -5
View File
@@ -24,14 +24,14 @@ use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::Keyring;
use client::{
BlockchainEvents, runtime_api::{Core, RuntimeVersion, ApiExt, ConstructRuntimeApi, CallApiAt},
error::Result
BlockchainEvents, error::Result,
runtime_api::{Core, RuntimeVersion, ApiExt, ConstructRuntimeApi, CallRuntimeAt},
};
use test_client::{self, runtime::BlockNumber};
use codec::Decode;
use consensus_common::BlockOrigin;
use std::{collections::HashSet, result};
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi};
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi, RuntimeApiInfo};
use runtime_primitives::generic::BlockId;
use authorities::AuthoritySet;
@@ -277,17 +277,21 @@ impl Core<Block> for RuntimeApi {
}
}
impl ApiExt for RuntimeApi {
impl ApiExt<Block> for RuntimeApi {
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
&self,
_: F
) -> result::Result<R, E> {
unimplemented!("Not required for testing!")
}
fn has_api<A: RuntimeApiInfo + ?Sized>(&self, _: &BlockId<Block>) -> Result<bool> {
unimplemented!("Not required for testing!")
}
}
impl ConstructRuntimeApi<Block> for RuntimeApi {
fn construct_runtime_api<'a, T: CallApiAt<Block>>(_: &'a T) -> ApiRef<'a, Self> {
fn construct_runtime_api<'a, T: CallRuntimeAt<Block>>(_: &'a T) -> ApiRef<'a, Self> {
unimplemented!("Not required for testing!")
}
}
+2 -9
View File
@@ -17,7 +17,7 @@
use super::*;
use jsonrpc_macros::pubsub;
use test_client::{self, TestClient};
use test_client::runtime::{Block, Header};
use test_client::runtime::{Block, Header, VERSION};
use consensus::BlockOrigin;
#[test]
@@ -259,13 +259,6 @@ fn should_return_runtime_version() {
assert_matches!(
client.runtime_version(None.into()),
Ok(ref ver) if ver == &RuntimeVersion {
spec_name: "test".into(),
impl_name: "parity-test".into(),
authoring_version: 1,
spec_version: 1,
impl_version: 1,
apis: (&[][..]).into()
}
Ok(ref ver) if ver == &VERSION
);
}
+5 -5
View File
@@ -23,7 +23,7 @@ use std::time::{self, Duration, Instant};
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 client::{block_builder::api::BlockBuilder as BlockBuilderApi, runtime_api::Core};
use codec::{Decode, Encode};
use consensus_common::{self, evaluation, offline_tracker::OfflineTracker};
use primitives::{H256, AuthorityId, ed25519, Blake2Hasher};
@@ -93,11 +93,11 @@ impl<B, E, Block, RA> AuthoringApi for SubstrateClient<B, E, Block, RA> where
inherent_data: BasicInherentData,
mut build_ctx: F,
) -> Result<Self::Block, error::Error> {
let runtime_version = self.runtime_version_at(at)?;
let mut block_builder = self.new_block_at(at)?;
if runtime_version.has_api(BLOCK_BUILDER, 1) {
self.runtime_api().inherent_extrinsics(at, &inherent_data)?
let runtime_api = self.runtime_api();
if runtime_api.has_api::<BlockBuilderApi<Block, BasicInherentData>>(at)? {
runtime_api.inherent_extrinsics(at, &inherent_data)?
.into_iter().try_for_each(|i| block_builder.push(i))?;
}
+3 -3
View File
@@ -10,11 +10,11 @@ proc-macro = true
quote = "0.6"
syn = { version = "^0.15.22", features = [ "full", "fold", "extra-traits", "visit" ] }
proc-macro2 = "0.4"
blake2-rfc = "0.2"
[dev-dependencies]
substrate-client = { path = "../client" }
substrate-test-client = { path = "../test-client" }
sr-primitives = { path = "../sr-primitives" }
sr-version = { path = "../sr-version" }
substrate-primitives = { path = "../primitives" }
parity-codec = "2.1"
parity-codec-derive = "2.1"
serde = "1.0"
@@ -110,40 +110,74 @@ mod adding_parameter_with_type_reference {
*/
}
mod missing_block_generic_parameter {
mod invalid_api_version {
/*!
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_primitives as primitives;
decl_runtime_apis! {
#[api_version]
pub trait Api {
fn test(data: u64);
}
}
fn main() {}
```
*/
}
mod invalid_api_version_2 {
/*!
```compile_fail
#[macro_use]
extern crate parity_codec_derive;
extern crate serde;
extern crate core;
extern crate substrate_client;
extern crate sr_primitives as runtime_primitives;
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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
decl_runtime_apis! {
#[api_version("1")]
pub trait Api {
fn test(data: u64);
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
fn main() {}
```
*/
}
mod invalid_api_version_3 {
/*!
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate sr_primitives as runtime_primitives;
decl_runtime_apis! {
#[api_version()]
pub trait Api {
fn test(data: u64);
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
fn main() {}
```
*/
}
mod missing_block_generic_parameter {
/*!
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_client;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_primitives as primitives;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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.
@@ -176,35 +210,12 @@ mod missing_path_for_trait {
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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.
@@ -237,35 +248,12 @@ mod empty_impl_runtime_apis_call {
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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.
@@ -292,35 +280,12 @@ mod type_reference_in_impl_runtime_apis_call {
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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.
@@ -353,35 +318,12 @@ mod impl_incorrect_method_signature {
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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.
@@ -406,3 +348,51 @@ mod impl_incorrect_method_signature {
```
*/
}
mod impl_two_traits_with_same_name {
/*!
```compile_fail
#[macro_use]
extern crate substrate_client;
extern crate substrate_test_client as test_client;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_primitives as primitives;
use runtime_primitives::traits::GetNodeBlockType;
use test_client::runtime::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);
}
}
mod second {
decl_runtime_apis! {
pub trait Api {
fn test2(data: u64);
}
}
}
impl_runtime_apis! {
impl self::Api<Block> for Runtime {
fn test(data: u64) {}
}
impl second::Api<Block> for Runtime {
fn test2(data: u64) {}
}
}
fn main() {}
```
*/
}
@@ -16,7 +16,7 @@
use utils::{
generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait,
fold_fn_decl_for_client_side
fold_fn_decl_for_client_side, unwrap_or_error
};
use proc_macro;
@@ -27,12 +27,23 @@ 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
visit::{Visit, self}, FnArg, Pat, TraitBound, Type, Meta, NestedMeta, Lit
};
use std::collections::HashMap;
use blake2_rfc;
/// Unique identifier used to make the hidden includes unique for this macro.
const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS";
/// The `core_trait` attribute.
const CORE_TRAIT_ATTRIBUTE: &str = "core_trait";
/// The `api_version` attribute.
const API_VERSION_ATTRIBUTE: &str = "api_version";
/// All attributes that we support in the declaratio of a runtime api trait.
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE];
/// The structure used for parsing the runtime api declarations.
struct RuntimeApiDecls {
decls: Vec<ItemTrait>,
@@ -59,15 +70,22 @@ fn extend_generics_with_block(generics: &mut Generics) {
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<Attribute>) -> bool {
let mut found = false;
/// Remove all attributes from the vector that are supported by us in the declaration of a runtime
/// api trait. The returned hashmap contains all found attribute names as keys and the rest of the
/// attribute body as `TokenStream`.
fn remove_supported_attributes(attrs: &mut Vec<Attribute>) -> HashMap<&'static str, Attribute> {
let mut result = HashMap::new();
attrs.retain(|v| {
let res = v.path.is_ident("core_trait");
found |= res;
!res
match SUPPORTED_ATTRIBUTE_NAMES.iter().filter(|a| v.path.is_ident(a)).next() {
Some(attribute) => {
result.insert(*attribute, v.clone());
false
},
None => true,
}
});
found
result
}
/// Generate the decleration of the trait for the runtime.
@@ -78,7 +96,11 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream {
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);
let found_attributes = remove_supported_attributes(&mut decl.attrs);
let api_version = unwrap_or_error(get_api_version(&found_attributes).map(|v| {
generate_runtime_api_version(v as u32)
}));
let id = generate_runtime_api_id(&decl.ident.to_string());
result.push(quote!(
#[doc(hidden)]
@@ -86,6 +108,10 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream {
use super::*;
#decl
pub #api_version
pub #id
}
));
}
@@ -97,6 +123,7 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream {
struct ToClientSideDecl<'a> {
block_id: &'a TokenStream,
crate_: &'a TokenStream,
found_attributes: &'a mut HashMap<&'static str, Attribute>,
}
impl<'a> Fold for ToClientSideDecl<'a> {
@@ -113,8 +140,9 @@ impl<'a> Fold for ToClientSideDecl<'a> {
fn fold_item_trait(&mut self, mut input: ItemTrait) -> ItemTrait {
extend_generics_with_block(&mut input.generics);
*self.found_attributes = remove_supported_attributes(&mut input.attrs);
// Check if this is the `Core` runtime api trait.
let is_core_trait = remove_core_trait_attribute(&mut input.attrs);
let is_core_trait = self.found_attributes.contains_key(CORE_TRAIT_ATTRIBUTE);
if is_core_trait {
// Add all the supertraits we want to have for `Core`.
@@ -124,7 +152,7 @@ impl<'a> Fold for ToClientSideDecl<'a> {
+ Send
+ Sync
+ #crate_::runtime_api::ConstructRuntimeApi<Block>
+ #crate_::runtime_api::ApiExt
+ #crate_::runtime_api::ApiExt<Block>
);
} else {
// Add the `Core` runtime api as super trait.
@@ -139,6 +167,77 @@ impl<'a> Fold for ToClientSideDecl<'a> {
}
}
/// Parse the given attribute as `API_VERSION_ATTRIBUTE`.
fn parse_runtime_api_version(version: &Attribute) -> Result<u64> {
let meta = version.parse_meta()?;
let err = Err(Error::new(
meta.span(),
&format!(
"Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`",
api_version = API_VERSION_ATTRIBUTE
)
)
);
match meta {
Meta::List(list) => {
if list.nested.len() > 1 && list.nested.is_empty() {
err
} else {
match list.nested.first().as_ref().map(|v| v.value()) {
Some(NestedMeta::Literal(Lit::Int(i))) => {
Ok(i.value())
},
_ => err,
}
}
},
_ => err,
}
}
/// Generates the identifier as const variable for the given `trait_name`
/// by hashing the `trait_name`.
fn generate_runtime_api_id(trait_name: &str) -> TokenStream {
let mut res = [0; 8];
res.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], trait_name.as_bytes()).as_bytes());
quote!( const ID: [u8; 8] = [ #( #res ),* ]; )
}
/// Generates the const variable that holds the runtime api version.
fn generate_runtime_api_version(version: u32) -> TokenStream {
quote!( const VERSION: u32 = #version; )
}
/// Generates the implementation of `RuntimeApiInfo` for the given trait.
fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream {
let trait_name = &trait_.ident;
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
let id = generate_runtime_api_id(&trait_name.to_string());
let version = generate_runtime_api_version(version as u32);
let (impl_generics, ty_generics, where_clause) = trait_.generics.split_for_impl();
quote!(
#[cfg(any(feature = "std", test))]
impl #impl_generics #crate_::runtime_api::RuntimeApiInfo
for #trait_name #ty_generics #where_clause
{
#id
#version
}
)
}
/// Get the api version from the user given attribute or `Ok(1)`, if no attribute was given.
fn get_api_version(found_attributes: &HashMap<&'static str, Attribute>) -> Result<u64> {
match found_attributes.get(&API_VERSION_ATTRIBUTE) {
Some(attr) => parse_runtime_api_version(attr),
None => Ok(1),
}
}
/// Generate the decleration of the trait for the client side.
fn generate_client_side_decls(decls: &[ItemTrait]) -> TokenStream {
let mut result = Vec::new();
@@ -148,9 +247,24 @@ fn generate_client_side_decls(decls: &[ItemTrait]) -> TokenStream {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
let block_id = quote!( #crate_::runtime_api::BlockId<Block> );
let mut to_client_side = ToClientSideDecl { crate_: &crate_, block_id: &block_id };
let mut found_attributes = HashMap::new();
result.push(to_client_side.fold_item_trait(decl));
let decl = {
let mut to_client_side = ToClientSideDecl {
crate_: &crate_,
block_id: &block_id,
found_attributes: &mut found_attributes
};
to_client_side.fold_item_trait(decl)
};
let api_version = get_api_version(&found_attributes);
let runtime_info = unwrap_or_error(
api_version.map(|v| generate_runtime_info_impl(&decl, v))
);
result.push(quote!( #decl #runtime_info ));
}
quote!( #( #result )* )
@@ -30,7 +30,7 @@ use syn::{
fold::{self, Fold}, FnDecl, parse_quote, Pat
};
use std::iter;
use std::{collections::HashSet, iter};
/// Unique identifier used to make the hidden includes unique for this macro.
const HIDDEN_INCLUDES_ID: &str = "IMPL_RUNTIME_APIS";
@@ -165,11 +165,21 @@ fn extract_runtime_block_ident(trait_: &Path) -> Result<&TypePath> {
}
/// Generate all the implementation calls for the given functions.
fn generate_impl_calls(impls: &[ItemImpl], input: &Ident) -> Result<Vec<(Ident, TokenStream)>> {
fn generate_impl_calls(
impls: &[ItemImpl],
input: &Ident
) -> Result<Vec<(Ident, Ident, TokenStream)>> {
let mut impl_calls = Vec::new();
for impl_ in impls {
let impl_trait = extend_with_runtime_decl_path(extract_impl_trait(impl_)?.clone());
let impl_trait_path = extract_impl_trait(impl_)?;
let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
let impl_trait_ident = &impl_trait_path
.segments
.last()
.ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
.value()
.ident;
for item in &impl_.items {
match item {
@@ -181,7 +191,9 @@ fn generate_impl_calls(impls: &[ItemImpl], input: &Ident) -> Result<Vec<(Ident,
&impl_trait
)?;
impl_calls.push((method.sig.ident.clone(), impl_call));
impl_calls.push(
(impl_trait_ident.clone(), method.sig.ident.clone(), impl_call)
);
},
_ => {},
}
@@ -191,13 +203,19 @@ fn generate_impl_calls(impls: &[ItemImpl], input: &Ident) -> Result<Vec<(Ident,
Ok(impl_calls)
}
fn prefix_function_with_trait(trait_: &Ident, function: &Ident) -> String {
format!("{}_{}", trait_.to_string(), function.to_string())
}
/// Generate the dispatch function that is used in native to call into the runtime.
fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
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_ }), )
});
let impl_calls = generate_impl_calls(impls, &data)?
.into_iter()
.map(|(trait_, fn_name, impl_)| {
let name = prefix_function_with_trait(&trait_, &fn_name);
quote!( #name => Some({ #impl_ }), )
});
Ok(quote!(
#[cfg(feature = "std")]
@@ -214,30 +232,37 @@ fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
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 impl_calls = generate_impl_calls(impls, &input)?
.into_iter()
.map(|(trait_, fn_name, impl_)| {
let fn_name = Ident::new(
&prefix_function_with_trait(&trait_, &fn_name),
Span::call_site()
);
let output = { #impl_ };
let res = output.as_ptr() as u64 + ((output.len() as u64) << 32);
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)
}
};
// 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
}
)
});
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.
#c::runtime_api::mem::forget(output);
res
}
)
});
Ok(quote!( #( #impl_calls )* ))
}
@@ -272,7 +297,7 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
/// 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>>,
call: ::std::ptr::NonNull<#crate_::runtime_api::CallRuntimeAt<#block>>,
commit_on_success: ::std::cell::RefCell<bool>,
initialised_block: ::std::cell::RefCell<Option<#block_id>>,
changes: ::std::cell::RefCell<#crate_::runtime_api::OverlayedChanges>,
@@ -287,11 +312,11 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
unsafe impl Sync for RuntimeApi {}
#[cfg(any(feature = "std", test))]
impl #crate_::runtime_api::ApiExt for RuntimeApi {
impl #crate_::runtime_api::ApiExt<#block> for RuntimeApi {
fn map_api_result<F: FnOnce(&Self) -> ::std::result::Result<R, E>, R, E>(
&self,
map_call: F
) -> ::std::result::Result<R, E> {
) -> ::std::result::Result<R, E> where Self: Sized {
*self.commit_on_success.borrow_mut() = false;
let res = map_call(self);
*self.commit_on_success.borrow_mut() = true;
@@ -300,17 +325,25 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
res
}
fn has_api<A: #crate_::runtime_api::RuntimeApiInfo + ?Sized>(
&self,
at: &#block_id
) -> #crate_::error::Result<bool> where Self: Sized {
unsafe { self.call.as_ref().runtime_version_at(at) }.map(|r| r.has_api::<A>())
}
}
#[cfg(any(feature = "std", test))]
impl #crate_::runtime_api::ConstructRuntimeApi<#block> for RuntimeApi {
fn construct_runtime_api<'a, T: #crate_::runtime_api::CallApiAt<#block>>(
fn construct_runtime_api<'a, T: #crate_::runtime_api::CallRuntimeAt<#block>>(
call: &'a T
) -> #crate_::runtime_api::ApiRef<'a, Self> {
) -> #crate_::runtime_api::ApiRef<'a, Self> where Self: Sized {
RuntimeApi {
call: unsafe {
::std::ptr::NonNull::new_unchecked(
call as &#crate_::runtime_api::CallApiAt<#block> as *const _ as *mut _
call as
&#crate_::runtime_api::CallRuntimeAt<#block> as *const _ as *mut _
)
},
commit_on_success: true.into(),
@@ -423,6 +456,7 @@ struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
node_block: &'a TokenStream,
runtime_block: &'a TypePath,
node_block_id: &'a TokenStream,
impl_trait_ident: &'a Ident,
}
impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
@@ -457,7 +491,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
*p = generate_unique_pattern(p.clone(), &mut generated_name_counter);
p
});
let name = input.sig.ident.to_string();
let name = prefix_function_with_trait(self.impl_trait_ident, &input.sig.ident);
// Generate the new method implementation that calls into the runime.
input.block = parse_quote!( { self.call_api_at(at, #name, &( #( #arg_names ),* )) } );
@@ -478,17 +512,26 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
}
}
/// Generate the implementations of the runtime apis for the `RuntimeApi` type.
fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream> {
let mut result = Vec::with_capacity(impls.len());
for impl_ in impls {
let runtime_block = extract_runtime_block_ident(extract_impl_trait(&impl_)?)?;
let impl_trait = extract_impl_trait(&impl_)?;
let impl_trait_ident = &impl_trait
.segments
.last()
.ok_or_else(|| Error::new(impl_trait.span(), "Empty trait path not possible!"))?
.value()
.ident;
let runtime_block = extract_runtime_block_ident(impl_trait)?;
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,
impl_trait_ident: &impl_trait_ident,
};
result.push(visitor.fold_item_impl(impl_.clone()));
@@ -497,6 +540,48 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream>
Ok(quote!( #( #result )* ))
}
/// Generates `RUNTIME_API_VERSIONS` that holds all version information about the implemented
/// runtime apis.
fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
let mut result = Vec::with_capacity(impls.len());
let mut processed_traits = HashSet::new();
for impl_ in impls {
let mut path = extend_with_runtime_decl_path(extract_impl_trait(&impl_)?.clone());
// Remove the trait
let trait_ = path
.segments
.pop()
.expect("extract_impl_trait already checks that this is valid; qed")
.into_value()
.ident;
let span = trait_.span();
if !processed_traits.insert(trait_) {
return Err(
Error::new(
span,
"Two traits with the same name detected! \
The trait name is used to generate its ID. \
Please rename one trait at the declaration!"
)
)
}
let id: Path = parse_quote!( #path ID );
let version: Path = parse_quote!( #path VERSION );
result.push(quote!( (#id, #version) ));
}
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
Ok(quote!(
const RUNTIME_API_VERSIONS: #c::runtime_api::ApisVec =
#c::runtime_api::create_apis_vec!([ #( #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
@@ -507,6 +592,7 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
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));
let runtime_api_versions = unwrap_or_error(generate_runtime_api_versions(&api_impls));
quote!(
#hidden_includes
@@ -517,6 +603,8 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
#api_impls_for_runtime_api
#runtime_api_versions
pub mod api {
use super::*;
+55 -29
View File
@@ -16,11 +16,12 @@
//! Macros for declaring and implementing runtime apis.
#![recursion_limit = "128"]
#![recursion_limit = "256"]
extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate syn;
extern crate blake2_rfc;
use proc_macro::TokenStream;
@@ -38,43 +39,27 @@ mod compile_fail_tests;
/// 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`.
/// The macro also generates the api implementations for the client side and provides it through
/// the `RuntimeApi` type. The `RuntimeApi` is hidden behind a `feature` called `std`.
///
/// To expose version information about all implemented api traits, the constant
/// `RUNTIME_API_VERSIONS` is generated. This constant should be used to instantiate the `apis`
/// field of `RuntimeVersion`.
///
/// # Example
///
/// ```rust
/// #[macro_use]
/// extern crate substrate_client;
/// extern crate sr_version as version;
///
/// use version::create_runtime_str;
/// # extern crate substrate_test_client as test_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<H256, u64>;
/// # pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
/// # #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
/// # pub struct Extrinsic {}
/// #
/// # impl serde::Serialize for Extrinsic {
/// # fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
/// # unimplemented!()
/// # }
/// # }
/// # impl ExtrinsicT for Extrinsic {
/// # fn is_signed(&self) -> Option<bool> {
/// # unimplemented!()
/// # }
/// # }
/// # pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
/// # pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
/// # use runtime_primitives::traits::GetNodeBlockType;
/// # use test_client::runtime::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.
@@ -114,6 +99,17 @@ mod compile_fail_tests;
/// }
/// }
///
/// /// Runtime version. This needs to be declared for each runtime.
/// pub const VERSION: version::RuntimeVersion = version::RuntimeVersion {
/// spec_name: create_runtime_str!("node"),
/// impl_name: create_runtime_str!("test-node"),
/// authoring_version: 1,
/// spec_version: 1,
/// impl_version: 0,
/// // Here we are exposing the runtime api versions.
/// apis: RUNTIME_API_VERSIONS,
/// };
///
/// # fn main() {}
/// ```
#[proc_macro]
@@ -158,6 +154,36 @@ pub fn impl_runtime_apis(input: TokenStream) -> TokenStream {
///
/// # fn main() {}
/// ```
///
/// # Runtime api trait versioning
///
/// To support versioning of the traits, the macro supports the attribute `#[api_version(1)]`.
/// The attribute supports any `u32` as version. By default, each trait is at version `1`, if no
/// version is provided.
///
/// ```rust
/// #[macro_use]
/// extern crate substrate_client;
///
/// decl_runtime_apis! {
/// /// Declare the api trait.
/// #[api_version(2)]
/// pub trait Balance {
/// /// Get the balance.
/// fn get_balance() -> u64;
/// /// Set the balance.
/// fn set_balance(val: u64);
/// /// In version 2, we added this new function.
/// fn increase_balance(val: u64);
/// }
/// }
///
/// # fn main() {}
/// ```
///
/// To check if a given runtime implements a runtime api trait, the `RuntimeVersion` has the
/// function `has_api<A>()`. Also the `ApiExt` provides a function `has_api<A>(at: &BlockId)` to
/// check if the runtime at the given block id implements the requested runtime api trait.
#[proc_macro]
pub fn decl_runtime_apis(input: TokenStream) -> TokenStream {
decl_runtime_apis::decl_runtime_apis_impl(input)
@@ -2,42 +2,14 @@
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;
extern crate substrate_test_client as test_client;
use primitives::hash::H256;
use runtime_primitives::traits::{
BlakeTwo256, GetNodeBlockType, Extrinsic as ExtrinsicT, Block as BlockT
};
use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT};
use runtime_primitives::generic::BlockId;
use substrate_client::runtime_api;
use primitives::AuthorityId;
use substrate_client::runtime_api::{self, RuntimeApiInfo};
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<H256, u64>;
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub struct Extrinsic {}
impl serde::Serialize for Extrinsic {
fn serialize<S>(
&self,
_: S
) -> ::std::result::Result<S::Ok, S::Error> where S: ::serde::Serializer {
unimplemented!()
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
unimplemented!()
}
}
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, DigestItem>;
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
use test_client::runtime::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.
@@ -51,6 +23,12 @@ decl_runtime_apis! {
fn test(data: u64);
fn something_with_block(block: Block) -> Block;
fn function_with_two_args(data: u64, block: Block);
fn same_name();
}
#[api_version(2)]
pub trait ApiWithCustomVersion {
fn same_name();
}
}
@@ -67,6 +45,12 @@ impl_runtime_apis! {
fn function_with_two_args(_: u64, _: Block) {
unimplemented!()
}
fn same_name() {}
}
impl self::ApiWithCustomVersion<Block> for Runtime {
fn same_name() {}
}
impl runtime_api::Core<Block> for Runtime {
@@ -91,3 +75,34 @@ fn test_client_side_function_signature() {
let _something_with_block: fn(&RuntimeApi, &BlockId<Block>, &Block) -> Result<Block> =
RuntimeApi::something_with_block;
}
#[test]
fn test_runtime_side_function_signature() {
let _api_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = api::Api_same_name;
let _api_with_version_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 =
api::ApiWithCustomVersion_same_name;
}
#[test]
fn check_runtime_api_info() {
assert_eq!(&Api::<Block>::ID, &runtime_decl_for_Api::ID);
assert_eq!(Api::<Block>::VERSION, runtime_decl_for_Api::VERSION);
assert_eq!(Api::<Block>::VERSION, 1);
assert_eq!(
ApiWithCustomVersion::<Block>::VERSION, runtime_decl_for_ApiWithCustomVersion::VERSION
);
assert_eq!(&ApiWithCustomVersion::<Block>::ID, &runtime_decl_for_ApiWithCustomVersion::ID);
assert_eq!(ApiWithCustomVersion::<Block>::VERSION, 2);
}
fn check_runtime_api_versions_contains<T: RuntimeApiInfo + ?Sized>() {
assert!(RUNTIME_API_VERSIONS.iter().any(|v| v == &(T::ID, T::VERSION)));
}
#[test]
fn check_runtime_api_versions() {
check_runtime_api_versions_contains::<Api<Block>>();
check_runtime_api_versions_contains::<ApiWithCustomVersion<Block>>();
check_runtime_api_versions_contains::<runtime_api::Core<Block>>();
}
+15 -3
View File
@@ -64,11 +64,23 @@ pub type Justification = Vec<u8>;
use traits::{Verify, Lazy};
/// A String that is a `&'static str` on `no_std` and a `String` on `std`.
#[cfg(not(feature = "std"))]
pub type RuntimeString = &'static str;
/// A String that is a `&'static str` on `no_std` and a `Cow<'static, str>` on `std`.
#[cfg(feature = "std")]
pub type RuntimeString = ::std::borrow::Cow<'static, str>;
#[cfg(not(feature = "std"))]
pub type RuntimeString = &'static str;
/// Create a const [RuntimeString].
#[cfg(feature = "std")]
#[macro_export]
macro_rules! create_runtime_str {
( $y:expr ) => {{ ::std::borrow::Cow::Borrowed($y) }}
}
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! create_runtime_str {
( $y:expr ) => {{ $y }}
}
#[cfg(feature = "std")]
pub use serde::{Serialize, de::DeserializeOwned};
@@ -639,3 +639,11 @@ pub trait GetNodeBlockType {
/// The `NodeBlock` type.
type NodeBlock: self::Block;
}
/// Something that provides information about a runtime api.
pub trait RuntimeApiInfo {
/// The identifier of the runtime api.
const ID: [u8; 8];
/// The version of the runtime api.
const VERSION: u32;
}
+22 -17
View File
@@ -35,8 +35,11 @@ extern crate sr_primitives as runtime_primitives;
use std::fmt;
#[cfg(feature = "std")]
use std::collections::HashSet;
#[cfg(feature = "std")]
use runtime_primitives::traits::RuntimeApiInfo;
use runtime_primitives::RuntimeString;
pub use runtime_primitives::create_runtime_str;
/// The identity of a particular API interface that the runtime might provide.
pub type ApiId = [u8; 8];
@@ -50,22 +53,16 @@ pub type ApisVec = ::std::borrow::Cow<'static, [(ApiId, u32)]>;
#[cfg(not(feature = "std"))]
pub type ApisVec = &'static [(ApiId, u32)];
#[cfg(feature = "std")]
#[macro_export]
macro_rules! ver_str {
( $y:expr ) => {{ ::std::borrow::Cow::Borrowed($y) }}
}
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! ver_str {
( $y:expr ) => {{ $y }}
}
/// Create a vector of Api declarations.
#[macro_export]
macro_rules! apis_vec {
( $y:expr ) => { ver_str!(& $y) }
#[cfg(feature = "std")]
macro_rules! create_apis_vec {
( $y:expr ) => { ::std::borrow::Cow::Borrowed(& $y) }
}
#[macro_export]
#[cfg(not(feature = "std"))]
macro_rules! create_apis_vec {
( $y:expr ) => { & $y }
}
/// Runtime version.
@@ -112,7 +109,13 @@ pub struct RuntimeVersion {
#[cfg(feature = "std")]
impl fmt::Display for RuntimeVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}-{}:{}({}-{})", self.spec_name, self.spec_version, self.authoring_version, self.impl_name, self.impl_version)
write!(f, "{}-{}:{}({}-{})",
self.spec_name,
self.spec_version,
self.authoring_version,
self.impl_name,
self.impl_version
)
}
}
@@ -126,8 +129,10 @@ impl RuntimeVersion {
}
/// Check if this version supports a particular API.
pub fn has_api(&self, api: ApiId, version: u32) -> bool {
self.apis.iter().any(|&(ref s, v)| &api == s && version == v)
pub fn has_api<A: RuntimeApiInfo + ?Sized>(&self) -> bool {
self.apis.iter().any(|(s, v)| {
s == &A::ID && *v == A::VERSION
})
}
}
+3 -3
View File
@@ -67,12 +67,12 @@ use runtime_version::NativeVersion;
/// Test runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: ver_str!("test"),
impl_name: ver_str!("parity-test"),
spec_name: create_runtime_str!("test"),
impl_name: create_runtime_str!("parity-test"),
authoring_version: 1,
spec_version: 1,
impl_version: 1,
apis: apis_vec!([]),
apis: RUNTIME_API_VERSIONS,
};
fn version() -> RuntimeVersion {
+6 -4
View File
@@ -766,8 +766,8 @@ name = "serde_derive"
version = "1.0.79"
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)",
"proc-macro2 0.4.24 (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.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -839,8 +839,9 @@ dependencies = [
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)",
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.24 (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.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -927,6 +928,7 @@ version = "0.1.0"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-api-macros 0.1.0",
"srml-support-procedural-tools 0.1.0",
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
+48 -27
View File
@@ -134,9 +134,9 @@ mod tests {
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32]
]);
let r = executor().call(&mut t, 8, BLOATY_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
let r = executor().call(&mut t, 8, BLOATY_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
assert!(r.is_ok());
let v = executor().call(&mut t, 8, BLOATY_CODE, "apply_extrinsic", &vec![].and(&xt()), true).0.unwrap();
let v = executor().call(&mut t, 8, BLOATY_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap();
let r = ApplyResult::decode(&mut &v[..]).unwrap();
assert_eq!(r, Err(ApplyError::CantPay));
}
@@ -155,9 +155,9 @@ mod tests {
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32]
]);
let r = executor().call(&mut t, 8, COMPACT_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
let r = executor().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
assert!(r.is_ok());
let v = executor().call(&mut t, 8, COMPACT_CODE, "apply_extrinsic", &vec![].and(&xt()), true).0.unwrap();
let v = executor().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap();
let r = ApplyResult::decode(&mut &v[..]).unwrap();
assert_eq!(r, Err(ApplyError::CantPay));
}
@@ -176,9 +176,9 @@ mod tests {
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32]
]);
let r = executor().call(&mut t, 8, COMPACT_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
let r = executor().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
assert!(r.is_ok());
let r = executor().call(&mut t, 8, COMPACT_CODE, "apply_extrinsic", &vec![].and(&xt()), true).0;
let r = executor().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0;
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
@@ -201,9 +201,9 @@ mod tests {
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32]
]);
let r = executor().call(&mut t, 8, BLOATY_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
let r = executor().call(&mut t, 8, BLOATY_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0;
assert!(r.is_ok());
let r = executor().call(&mut t, 8, BLOATY_CODE, "apply_extrinsic", &vec![].and(&xt()), true).0;
let r = executor().call(&mut t, 8, BLOATY_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0;
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
@@ -387,7 +387,7 @@ mod tests {
fn full_native_block_import_works() {
let mut t = new_test_ext(false);
executor().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(false).0, true).0.unwrap();
executor().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0, true).0.unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 41);
@@ -429,7 +429,7 @@ mod tests {
]);
});
executor().call(&mut t, 8, COMPACT_CODE, "execute_block", &block2().0, true).0.unwrap();
executor().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0, true).0.unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 30);
@@ -505,14 +505,14 @@ mod tests {
fn full_wasm_block_import_works() {
let mut t = new_test_ext(false);
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(false).0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 41);
assert_eq!(Balances::total_balance(&bob()), 69);
});
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block2().0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 30);
@@ -680,7 +680,7 @@ mod tests {
]
);
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &b.0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &b.0).unwrap();
runtime_io::with_externalities(&mut t, || {
// Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed.
@@ -692,24 +692,45 @@ mod tests {
fn wasm_big_block_import_fails() {
let mut t = new_test_ext(false);
let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1big().0);
assert!(!r.is_ok());
assert!(
WasmExecutor::new().call(
&mut t,
8,
COMPACT_CODE,
"Core_execute_block",
&block1big().0
).is_err()
);
}
#[test]
fn native_big_block_import_succeeds() {
let mut t = new_test_ext(false);
let r = Executor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1big().0, true).0;
assert!(r.is_ok());
Executor::new().call(
&mut t,
8,
COMPACT_CODE,
"Core_execute_block",
&block1big().0,
true
).0.unwrap();
}
#[test]
fn native_big_block_import_fails_on_fallback() {
let mut t = new_test_ext(false);
let r = Executor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1big().0, false).0;
assert!(!r.is_ok());
assert!(
Executor::new().call(
&mut t,
8,
COMPACT_CODE,
"Core_execute_block",
&block1big().0,
false
).0.is_err()
);
}
#[test]
@@ -727,9 +748,9 @@ mod tests {
]);
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm");
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64)));
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "Core_initialise_block", &vec![].and(&from_block_number(1u64)));
assert!(r.is_ok());
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt())).unwrap();
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap();
let r = ApplyResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Err(ApplyError::CantPay));
}
@@ -749,9 +770,9 @@ mod tests {
]);
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm");
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "initialise_block", &vec![].and(&from_block_number(1u64)));
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "Core_initialise_block", &vec![].and(&from_block_number(1u64)));
assert!(r.is_ok());
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "apply_extrinsic", &vec![].and(&xt())).unwrap();
let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap();
let r = ApplyResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Ok(ApplyOutcome::Success));
@@ -764,7 +785,7 @@ mod tests {
#[test]
fn full_native_block_import_works_with_changes_trie() {
let mut t = new_test_ext(true);
Executor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(true).0, true).0.unwrap();
Executor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(true).0, true).0.unwrap();
assert!(t.storage_changes_root(Default::default(), 0).is_some());
}
@@ -772,7 +793,7 @@ mod tests {
#[test]
fn full_wasm_block_import_works_with_changes_trie() {
let mut t = new_test_ext(true);
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(true).0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(true).0).unwrap();
assert!(t.storage_changes_root(Default::default(), 0).is_some());
}
@@ -786,8 +807,8 @@ mod tests {
fn wasm_execute_block(b: &mut Bencher) {
b.iter(|| {
let mut t = new_test_ext(false);
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(false).0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block2().0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0).unwrap();
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0).unwrap();
});
}
}
+5 -10
View File
@@ -59,9 +59,9 @@ use substrate_primitives::u32_trait::{_2, _4};
use node_primitives::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature
};
use grandpa::fg_primitives::{self, ScheduledChange, id::*};
use grandpa::fg_primitives::{self, ScheduledChange};
use client::{
block_builder::api as block_builder_api, runtime_api::{self as client_api, id::*}
block_builder::api as block_builder_api, runtime_api as client_api
};
use runtime_primitives::{ApplyResult, CheckInherentError, BasicInherentData};
use runtime_primitives::transaction_validity::TransactionValidity;
@@ -91,17 +91,12 @@ const NOTE_OFFLINE_POSITION: u32 = 1;
/// Runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: ver_str!("node"),
impl_name: ver_str!("substrate-node"),
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 1,
spec_version: 1,
impl_version: 0,
apis: apis_vec!([
(BLOCK_BUILDER, 1),
(TAGGED_TRANSACTION_QUEUE, 1),
(METADATA, 1),
(GRANDPA_API, 1),
]),
apis: RUNTIME_API_VERSIONS,
};
/// Native version.
+6 -4
View File
@@ -827,8 +827,8 @@ name = "serde_derive"
version = "1.0.79"
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)",
"proc-macro2 0.4.24 (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.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -900,8 +900,9 @@ dependencies = [
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)",
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.24 (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.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1164,6 +1165,7 @@ version = "0.1.0"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-api-macros 0.1.0",
"srml-support-procedural-tools 0.1.0",
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
]