mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 15:51:12 +00:00
Make API backwards compatible with CC (#1697)
* Rework how a runtime api calls into the runtime Now we generate a default implementation for each api call that calls a generated method `method_runtime_api_impl`. This newly generated method is the one that will be implemented by the `impl_runtime_apis` macro in the runtime for the client side. * Support `changed_in` to change runtime api function signatures * Update documentation * Fixes tests * Implement checking the api version with a predicate * Make the implementation backwards compatible with CC * Update wasm files after merge * Check for wasm runtime differences by building master and current branch * Update spec_version and wasm files * Fixes * Revert my changes * Remove `patch.crates-io` from test-runtime
This commit is contained in:
Generated
+2
@@ -3487,6 +3487,7 @@ dependencies = [
|
||||
"kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (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",
|
||||
@@ -3981,6 +3982,7 @@ dependencies = [
|
||||
name = "substrate-test-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
@@ -96,10 +96,10 @@ impl<B, E, Block, RA> AuthoringApi for SubstrateClient<B, E, Block, RA> where
|
||||
let mut block_builder = self.new_block_at(at)?;
|
||||
|
||||
let runtime_api = self.runtime_api();
|
||||
if runtime_api.has_api::<BlockBuilderApi<Block>>(at)? {
|
||||
runtime_api.inherent_extrinsics(at, inherent_data)?
|
||||
.into_iter().try_for_each(|i| block_builder.push(i))?;
|
||||
}
|
||||
// We don't check the API versions any further here since the dispatch compatibility
|
||||
// check should be enough.
|
||||
runtime_api.inherent_extrinsics(at, inherent_data)?
|
||||
.into_iter().try_for_each(|i| block_builder.push(i))?;
|
||||
|
||||
build_ctx(&mut block_builder);
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ substrate-telemetry = { path = "../telemetry", optional = true }
|
||||
hash-db = { version = "0.9" , optional = true }
|
||||
kvdb = { git = "https://github.com/paritytech/parity-common", optional = true, rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" }
|
||||
|
||||
codec = { package = "parity-codec", version = "3.0", default-features = false }
|
||||
parity-codec = { version = "3.0", default-features = false }
|
||||
parity-codec-derive = { version = "3.0", default-features = false }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
|
||||
runtime-primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
|
||||
runtime-version = { package = "sr-version", path = "../sr-version", default-features = false }
|
||||
@@ -37,7 +38,8 @@ kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b031
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"parity-codec/std",
|
||||
"parity-codec-derive/std",
|
||||
"consensus",
|
||||
"primitives/std",
|
||||
"inherents/std",
|
||||
|
||||
@@ -16,13 +16,50 @@
|
||||
|
||||
//! The runtime api for building blocks.
|
||||
|
||||
use runtime_primitives::{traits::Block as BlockT, ApplyResult};
|
||||
use runtime_primitives::{traits::Block as BlockT, ApplyResult, RuntimeString};
|
||||
use rstd::vec::Vec;
|
||||
use sr_api_macros::decl_runtime_apis;
|
||||
pub use inherents::{InherentData, CheckInherentsResult};
|
||||
use parity_codec_derive::{Encode, Decode};
|
||||
|
||||
/// The old representation of the inherent data.
|
||||
#[doc(hide)]
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct OldInherentData {
|
||||
/// Current timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Blank report.
|
||||
pub consensus: (),
|
||||
/// Aura expected slot. Can take any value during block construction.
|
||||
pub aura_expected_slot: u64,
|
||||
}
|
||||
|
||||
impl OldInherentData {
|
||||
/// Create a new `BasicInherentData` instance.
|
||||
pub fn new(timestamp: u64, expected_slot: u64) -> Self {
|
||||
Self {
|
||||
timestamp,
|
||||
consensus: (),
|
||||
aura_expected_slot: expected_slot,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type used while checking inherents.
|
||||
#[doc(hide)]
|
||||
#[derive(Encode, PartialEq)]
|
||||
#[cfg_attr(feature = "std", derive(Decode))]
|
||||
pub enum OldCheckInherentError {
|
||||
/// The inherents are generally valid but a delay until the given timestamp
|
||||
/// is required.
|
||||
ValidAtTimestamp(u64),
|
||||
/// Some other error has occurred.
|
||||
Other(RuntimeString),
|
||||
}
|
||||
|
||||
decl_runtime_apis! {
|
||||
/// The `BlockBuilder` api trait that provides required functions for building a block for a runtime.
|
||||
#[api_version(2)]
|
||||
pub trait BlockBuilder {
|
||||
/// Apply the given extrinsics.
|
||||
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult;
|
||||
@@ -32,6 +69,11 @@ decl_runtime_apis! {
|
||||
fn inherent_extrinsics(inherent: InherentData) -> Vec<<Block as BlockT>::Extrinsic>;
|
||||
/// Check that the inherents are valid. The inherent data will vary from chain to chain.
|
||||
fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult;
|
||||
/// Check that the inherents are valid. The inherent data will vary from chain to chain.
|
||||
///
|
||||
/// Old version that is used by the CC network.
|
||||
#[changed_in(2)]
|
||||
fn check_inherents(block: Block, data: OldInherentData) -> ::std::result::Result<(), OldCheckInherentError>;
|
||||
/// Generate a random seed.
|
||||
fn random_seed() -> <Block as BlockT>::Hash;
|
||||
}
|
||||
|
||||
@@ -1426,7 +1426,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, runtime_api::ApiExt};
|
||||
use test_client::client::backend::Backend as TestBackend;
|
||||
use test_client::BlockBuilderExt;
|
||||
use test_client::runtime::{self, Block, Transfer, RuntimeApi, TestAPI};
|
||||
|
||||
@@ -1523,17 +1523,6 @@ 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();
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#![warn(missing_docs)]
|
||||
#![recursion_limit="128"]
|
||||
|
||||
extern crate parity_codec as codec;
|
||||
|
||||
#[macro_use]
|
||||
pub mod runtime_api;
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -69,7 +69,21 @@ pub trait ApiExt<Block: BlockT> {
|
||||
fn has_api<A: RuntimeApiInfo + ?Sized>(
|
||||
&self,
|
||||
at: &BlockId<Block>
|
||||
) -> error::Result<bool> where Self: Sized;
|
||||
) -> error::Result<bool> where Self: Sized {
|
||||
self.runtime_version_at(at).map(|v| v.has_api::<A>())
|
||||
}
|
||||
|
||||
/// Check if the given api is implemented and the version passes a predicate.
|
||||
fn has_api_with<A: RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
pred: P,
|
||||
) -> error::Result<bool> where Self: Sized {
|
||||
self.runtime_version_at(at).map(|v| v.has_api_with::<A, _>(pred))
|
||||
}
|
||||
|
||||
/// Returns the runtime version at the given block id.
|
||||
fn runtime_version_at(&self, at: &BlockId<Block>) -> error::Result<RuntimeVersion>;
|
||||
}
|
||||
|
||||
/// Something that can call into the runtime at a given block.
|
||||
|
||||
@@ -34,7 +34,8 @@ use consensus_common::{
|
||||
};
|
||||
use consensus_common::import_queue::{Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport};
|
||||
use client::ChainHead;
|
||||
use client::block_builder::api::BlockBuilder as BlockBuilderApi;
|
||||
use client::block_builder::api::{BlockBuilder as BlockBuilderApi, self as block_builder_api};
|
||||
use client::runtime_api::ApiExt;
|
||||
use consensus_common::{ImportBlock, BlockOrigin};
|
||||
use runtime_primitives::{generic, generic::BlockId, Justification};
|
||||
use runtime_primitives::traits::{
|
||||
@@ -465,6 +466,50 @@ impl<C, E> AuraVerifier<C, E>
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn old_check_inherents<B: Block>(
|
||||
&self,
|
||||
block: B,
|
||||
block_id: BlockId<B>,
|
||||
inherent_data: InherentData,
|
||||
timestamp_now: u64,
|
||||
) -> Result<(), String>
|
||||
where C: ProvideRuntimeApi, C::Api: BlockBuilderApi<B>
|
||||
{
|
||||
use block_builder_api::{OldInherentData, OldCheckInherentError};
|
||||
const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60;
|
||||
|
||||
let (timestamp, slot) = AuraSlotCompatible::extract_timestamp_and_slot(&inherent_data).map_err(|e| format!("{:?}", e))?;
|
||||
let inherent_data = OldInherentData::new(timestamp, slot);
|
||||
|
||||
let inherent_res = self.client.runtime_api().check_inherents_before_version_2(
|
||||
&block_id,
|
||||
block,
|
||||
inherent_data,
|
||||
).map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
match inherent_res {
|
||||
Ok(()) => Ok(()),
|
||||
Err(OldCheckInherentError::ValidAtTimestamp(timestamp)) => {
|
||||
// halt import until timestamp is valid.
|
||||
// reject when too far ahead.
|
||||
if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS {
|
||||
return Err("Rejecting block too far in future".into());
|
||||
}
|
||||
|
||||
let diff = timestamp.saturating_sub(timestamp_now);
|
||||
info!(
|
||||
target: "aura",
|
||||
"halting for block {} seconds in the future",
|
||||
diff
|
||||
);
|
||||
thread::sleep(Duration::from_secs(diff));
|
||||
Ok(())
|
||||
},
|
||||
Err(OldCheckInherentError::Other(e)) => Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// No-op extra verification.
|
||||
@@ -519,12 +564,25 @@ impl<B: Block, C, E> Verifier<B> for AuraVerifier<C, E> where
|
||||
inherent_data.aura_replace_inherent_data(slot_num);
|
||||
let block = B::new(pre_header.clone(), inner_body);
|
||||
|
||||
self.check_inherents(
|
||||
block.clone(),
|
||||
BlockId::Hash(parent_hash),
|
||||
inherent_data,
|
||||
timestamp_now,
|
||||
)?;
|
||||
if self.client
|
||||
.runtime_api()
|
||||
.has_api_with::<BlockBuilderApi<B>, _>(&BlockId::Hash(parent_hash), |v| v < 2)
|
||||
.map_err(|e| format!("{:?}", e))?
|
||||
{
|
||||
self.old_check_inherents(
|
||||
block.clone(),
|
||||
BlockId::Hash(parent_hash),
|
||||
inherent_data,
|
||||
timestamp_now,
|
||||
)?;
|
||||
} else {
|
||||
self.check_inherents(
|
||||
block.clone(),
|
||||
BlockId::Hash(parent_hash),
|
||||
inherent_data,
|
||||
timestamp_now,
|
||||
)?;
|
||||
}
|
||||
|
||||
let (_, inner_body) = block.deconstruct();
|
||||
body = Some(inner_body);
|
||||
|
||||
@@ -34,8 +34,9 @@ use consensus_common::BlockOrigin;
|
||||
use consensus_common::import_queue::{SharedBlockImport, SharedJustificationImport};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::result;
|
||||
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi, RuntimeApiInfo};
|
||||
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use substrate_primitives::NativeOrEncoded;
|
||||
|
||||
use authorities::AuthoritySet;
|
||||
|
||||
@@ -273,23 +274,39 @@ impl ProvideRuntimeApi for TestApi {
|
||||
}
|
||||
|
||||
impl Core<Block> for RuntimeApi {
|
||||
fn version(&self, _: &BlockId<Block>) -> Result<RuntimeVersion> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn authorities(&self, _: &BlockId<Block>) -> Result<Vec<Ed25519AuthorityId>> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn execute_block(&self, _: &BlockId<Block>, _: Block) -> Result<()> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn initialise_block(
|
||||
fn version_runtime_api_impl(
|
||||
&self,
|
||||
_: &BlockId<Block>,
|
||||
_: &<Block as BlockT>::Header
|
||||
) -> Result<()> {
|
||||
_: Option<()>,
|
||||
_: Vec<u8>
|
||||
) -> Result<NativeOrEncoded<RuntimeVersion>> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn authorities_runtime_api_impl(
|
||||
&self,
|
||||
_: &BlockId<Block>,
|
||||
_: Option<()>,
|
||||
_: Vec<u8>
|
||||
) -> Result<NativeOrEncoded<Vec<Ed25519AuthorityId>>> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn execute_block_runtime_api_impl(
|
||||
&self,
|
||||
_: &BlockId<Block>,
|
||||
_: Option<(Block)>,
|
||||
_: Vec<u8>
|
||||
) -> Result<NativeOrEncoded<()>> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn initialise_block_runtime_api_impl(
|
||||
&self,
|
||||
_: &BlockId<Block>,
|
||||
_: Option<&<Block as BlockT>::Header>,
|
||||
_: Vec<u8>,
|
||||
) -> Result<NativeOrEncoded<()>> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
}
|
||||
@@ -302,26 +319,31 @@ impl ApiExt<Block> for RuntimeApi {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
|
||||
fn has_api<A: RuntimeApiInfo + ?Sized>(&self, _: &BlockId<Block>) -> Result<bool> {
|
||||
fn runtime_version_at(&self, _: &BlockId<Block>) -> Result<RuntimeVersion> {
|
||||
unimplemented!("Not required for testing!")
|
||||
}
|
||||
}
|
||||
|
||||
impl GrandpaApi<Block> for RuntimeApi {
|
||||
fn grandpa_authorities(
|
||||
fn grandpa_authorities_runtime_api_impl(
|
||||
&self,
|
||||
at: &BlockId<Block>
|
||||
) -> Result<Vec<(Ed25519AuthorityId, u64)>> {
|
||||
at: &BlockId<Block>,
|
||||
_: Option<()>,
|
||||
_: Vec<u8>,
|
||||
) -> Result<NativeOrEncoded<Vec<(Ed25519AuthorityId, u64)>>> {
|
||||
if at == &BlockId::Number(0) {
|
||||
Ok(self.inner.genesis_authorities.clone())
|
||||
Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
|
||||
} else {
|
||||
panic!("should generally only request genesis authorities")
|
||||
}
|
||||
}
|
||||
|
||||
fn grandpa_pending_change(&self, at: &BlockId<Block>, _: &DigestFor<Block>)
|
||||
-> Result<Option<ScheduledChange<NumberFor<Block>>>>
|
||||
{
|
||||
fn grandpa_pending_change_runtime_api_impl(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
_: Option<(&DigestFor<Block>)>,
|
||||
_: Vec<u8>
|
||||
) -> Result<NativeOrEncoded<Option<ScheduledChange<NumberFor<Block>>>>> {
|
||||
let parent_hash = match at {
|
||||
&BlockId::Hash(at) => at,
|
||||
_ => panic!("not requested by block hash!!"),
|
||||
@@ -329,7 +351,7 @@ impl GrandpaApi<Block> for RuntimeApi {
|
||||
|
||||
// we take only scheduled changes at given block number where there are no
|
||||
// extrinsics.
|
||||
Ok(self.inner.scheduled_changes.lock().get(&parent_hash).map(|c| c.clone()))
|
||||
Ok(self.inner.scheduled_changes.lock().get(&parent_hash).map(|c| c.clone())).map(NativeOrEncoded::Native)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,14 +215,9 @@ fn should_return_runtime_version() {
|
||||
let client = Arc::new(test_client::new());
|
||||
let api = State::new(client.clone(), Subscriptions::new(core.executor()));
|
||||
|
||||
assert_matches!(
|
||||
api.runtime_version(None.into()),
|
||||
Ok(ref ver) if ver == &runtime::VERSION
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
::serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(),
|
||||
r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",1],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1]]}"#
|
||||
r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",2],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1]]}"#
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -378,3 +378,35 @@ mod impl_two_traits_with_same_name {
|
||||
```
|
||||
*/
|
||||
}
|
||||
|
||||
mod changed_at_unknown_version {
|
||||
/*!
|
||||
```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 {
|
||||
#[changed_in(2)]
|
||||
fn test(data: u64);
|
||||
fn test(data: u64);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use utils::{
|
||||
generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait,
|
||||
fold_fn_decl_for_client_side, unwrap_or_error, extract_parameter_names_types_and_borrows,
|
||||
generate_native_call_generator_fn_name, return_type_extract_type,
|
||||
generate_method_runtime_api_impl_name
|
||||
};
|
||||
|
||||
use proc_macro;
|
||||
@@ -27,8 +28,9 @@ use quote::quote;
|
||||
|
||||
use syn::{
|
||||
spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, ReturnType,
|
||||
fold::{self, Fold}, FnDecl, parse_quote, ItemTrait, Generics, GenericParam, Attribute,
|
||||
visit::{Visit, self}, FnArg, Pat, TraitBound, Meta, NestedMeta, Lit, TraitItem, Ident, Type
|
||||
fold::{self, Fold}, parse_quote, ItemTrait, Generics, GenericParam, Attribute, FnArg,
|
||||
visit::{Visit, self}, Pat, TraitBound, Meta, NestedMeta, Lit, TraitItem, Ident, Type,
|
||||
TraitItemMethod
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
@@ -44,9 +46,16 @@ const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS";
|
||||
/// The `core_trait` attribute.
|
||||
const CORE_TRAIT_ATTRIBUTE: &str = "core_trait";
|
||||
/// The `api_version` attribute.
|
||||
/// Is used to set the current version of the trait.
|
||||
const API_VERSION_ATTRIBUTE: &str = "api_version";
|
||||
/// The `changed_in` attribute.
|
||||
/// Is used when the function signature changed between different versions of a trait.
|
||||
/// This attribute should be placed on the old signature of the function.
|
||||
const CHANGED_IN_ATTRIBUTE: &str = "changed_in";
|
||||
/// All attributes that we support in the declaratio of a runtime api trait.
|
||||
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE];
|
||||
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[
|
||||
CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE
|
||||
];
|
||||
|
||||
/// The structure used for parsing the runtime api declarations.
|
||||
struct RuntimeApiDecls {
|
||||
@@ -279,6 +288,20 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream {
|
||||
generate_runtime_api_version(v as u32)
|
||||
}));
|
||||
let id = generate_runtime_api_id(&decl.ident.to_string());
|
||||
|
||||
// Remove methods that have the `changed_in` attribute as they are not required for the
|
||||
// runtime anymore.
|
||||
decl.items = decl.items.iter_mut().filter_map(|i| match i {
|
||||
TraitItem::Method(ref mut method) => {
|
||||
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
|
||||
None
|
||||
} else {
|
||||
Some(TraitItem::Method(method.clone()))
|
||||
}
|
||||
}
|
||||
r => Some(r.clone()),
|
||||
}).collect();
|
||||
|
||||
let native_call_generators = unwrap_or_error(generate_native_call_generators(&decl));
|
||||
|
||||
result.push(quote!(
|
||||
@@ -306,19 +329,164 @@ struct ToClientSideDecl<'a> {
|
||||
block_id: &'a TokenStream,
|
||||
crate_: &'a TokenStream,
|
||||
found_attributes: &'a mut HashMap<&'static str, Attribute>,
|
||||
/// Any error that we found while converting this declaration.
|
||||
errors: &'a mut Vec<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,
|
||||
impl<'a> ToClientSideDecl<'a> {
|
||||
fn fold_item_trait_items(&mut self, items: Vec<TraitItem>) -> Vec<TraitItem> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
items.into_iter().for_each(|i| match i {
|
||||
TraitItem::Method(method) => {
|
||||
let (fn_decl, fn_impl) = self.fold_trait_item_method(method);
|
||||
result.push(fn_decl.into());
|
||||
|
||||
if let Some(fn_impl) = fn_impl {
|
||||
result.push(fn_impl.into());
|
||||
}
|
||||
},
|
||||
r => result.push(r),
|
||||
});
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn fold_trait_item_method(&mut self, method: TraitItemMethod) -> (TraitItemMethod, Option<TraitItemMethod>) {
|
||||
let fn_impl = self.create_method_runtime_api_impl(method.clone());
|
||||
let fn_decl = self.create_method_decl(method);
|
||||
|
||||
(fn_decl, fn_impl)
|
||||
}
|
||||
|
||||
/// Takes the given method and creates a `method_runtime_api_impl` method that will be
|
||||
/// implemented in the runtime for the client side.
|
||||
fn create_method_runtime_api_impl(&mut self, mut method: TraitItemMethod) -> Option<TraitItemMethod> {
|
||||
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let fn_decl = &method.sig.decl;
|
||||
let ret_type = return_type_extract_type(&fn_decl.output);
|
||||
|
||||
// Get types and if the value is borrowed from all parameters.
|
||||
// If there is an error, we push it as the block to the user.
|
||||
let param_types = match extract_parameter_names_types_and_borrows(fn_decl) {
|
||||
Ok(res) => res.into_iter().map(|v| {
|
||||
let ty = v.1;
|
||||
let borrow = v.2;
|
||||
quote!( #borrow #ty )
|
||||
}).collect::<Vec<_>>(),
|
||||
Err(e) => {
|
||||
self.errors.push(e.to_compile_error());
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
let name = generate_method_runtime_api_impl_name(&method.sig.ident);
|
||||
let block_id = self.block_id;
|
||||
let crate_ = self.crate_;
|
||||
|
||||
Some(
|
||||
parse_quote!{
|
||||
#[doc(hidden)]
|
||||
fn #name(
|
||||
&self,
|
||||
at: &#block_id,
|
||||
params: Option<( #( #param_types ),* )>,
|
||||
params_encoded: Vec<u8>
|
||||
) -> #crate_::error::Result<#crate_::runtime_api::NativeOrEncoded<#ret_type>>;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Takes the method declared by the user and creates the declaration we require for the runtime
|
||||
/// api client side. This method will call by default the `method_runtime_api_impl` for doing
|
||||
/// the actual call into the runtime.
|
||||
fn create_method_decl(&mut self, mut method: TraitItemMethod) -> TraitItemMethod {
|
||||
let params = match extract_parameter_names_types_and_borrows(&method.sig.decl) {
|
||||
Ok(res) => res.into_iter().map(|v| v.0).collect::<Vec<_>>(),
|
||||
Err(e) => {
|
||||
self.errors.push(e.to_compile_error());
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
let params2 = params.clone();
|
||||
let ret_type = return_type_extract_type(&method.sig.decl.output);
|
||||
|
||||
method.sig.decl = fold_fn_decl_for_client_side(
|
||||
method.sig.decl.clone(),
|
||||
&self.block_id,
|
||||
&self.crate_
|
||||
);
|
||||
let name_impl = generate_method_runtime_api_impl_name(&method.sig.ident);
|
||||
let crate_ = self.crate_;
|
||||
|
||||
fold::fold_fn_decl(self, input)
|
||||
let found_attributes = remove_supported_attributes(&mut method.attrs);
|
||||
// If the method has a `changed_in` attribute, we need to alter the method name to
|
||||
// `method_before_version_VERSION`.
|
||||
let (native_handling, param_tuple) = match get_changed_in(&found_attributes) {
|
||||
Ok(Some(version)) => {
|
||||
// Make sure that the `changed_in` version is at least the current `api_version`.
|
||||
if get_api_version(&self.found_attributes).ok() < Some(version) {
|
||||
self.errors.push(
|
||||
Error::new(
|
||||
method.span(),
|
||||
"`changed_in` version can not be greater than the `api_version`",
|
||||
).to_compile_error()
|
||||
);
|
||||
}
|
||||
|
||||
let ident = Ident::new(
|
||||
&format!("{}_before_version_{}", method.sig.ident, version),
|
||||
method.sig.ident.span()
|
||||
);
|
||||
method.sig.ident = ident;
|
||||
method.attrs.push(parse_quote!( #[deprecated] ));
|
||||
|
||||
let panic = format!("Calling `{}` should not return a native value!", method.sig.ident);
|
||||
(quote!( panic!(#panic) ), quote!( None ))
|
||||
},
|
||||
Ok(None) => (quote!( Ok(n) ), quote!( Some(( #( #params2 ),* )) )),
|
||||
Err(e) => {
|
||||
self.errors.push(e.to_compile_error());
|
||||
(quote!( unimplemented!() ), quote!( None ))
|
||||
}
|
||||
};
|
||||
|
||||
let function_name = method.sig.ident.to_string();
|
||||
|
||||
// Generate the default implementation that calls the `method_runtime_api_impl` method.
|
||||
method.default = Some(
|
||||
parse_quote! {
|
||||
{
|
||||
let runtime_api_impl_params_encoded =
|
||||
#crate_::runtime_api::Encode::encode(&( #( &#params ),* ));
|
||||
|
||||
self.#name_impl(at, #param_tuple, runtime_api_impl_params_encoded)
|
||||
.and_then(|r|
|
||||
match r {
|
||||
#crate_::runtime_api::NativeOrEncoded::Native(n) => {
|
||||
#native_handling
|
||||
},
|
||||
#crate_::runtime_api::NativeOrEncoded::Encoded(r) => {
|
||||
<#ret_type as #crate_::runtime_api::Decode>::decode(&mut &r[..])
|
||||
.ok_or_else(||
|
||||
#crate_::error::ErrorKind::CallResultDecode(
|
||||
#function_name
|
||||
).into()
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
method
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Fold for ToClientSideDecl<'a> {
|
||||
fn fold_item_trait(&mut self, mut input: ItemTrait) -> ItemTrait {
|
||||
extend_generics_with_block(&mut input.generics);
|
||||
|
||||
@@ -344,6 +512,7 @@ impl<'a> Fold for ToClientSideDecl<'a> {
|
||||
|
||||
// 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))] ));
|
||||
input.items = self.fold_item_trait_items(input.items);
|
||||
|
||||
fold::fold_item_trait(self, input)
|
||||
}
|
||||
@@ -412,12 +581,16 @@ fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream {
|
||||
)
|
||||
}
|
||||
|
||||
/// Get changed in version from the user given attribute or `Ok(None)`, if no attribute was given.
|
||||
fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result<Option<u64>> {
|
||||
found_attributes.get(&CHANGED_IN_ATTRIBUTE)
|
||||
.map(|v| parse_runtime_api_version(v).map(Some))
|
||||
.unwrap_or(Ok(None))
|
||||
}
|
||||
|
||||
/// 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),
|
||||
}
|
||||
found_attributes.get(&API_VERSION_ATTRIBUTE).map(parse_runtime_api_version).unwrap_or(Ok(1))
|
||||
}
|
||||
|
||||
/// Generate the decleration of the trait for the client side.
|
||||
@@ -430,12 +603,14 @@ 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 found_attributes = HashMap::new();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let decl = {
|
||||
let mut to_client_side = ToClientSideDecl {
|
||||
crate_: &crate_,
|
||||
block_id: &block_id,
|
||||
found_attributes: &mut found_attributes
|
||||
found_attributes: &mut found_attributes,
|
||||
errors: &mut errors,
|
||||
};
|
||||
to_client_side.fold_item_trait(decl)
|
||||
};
|
||||
@@ -446,7 +621,7 @@ fn generate_client_side_decls(decls: &[ItemTrait]) -> TokenStream {
|
||||
api_version.map(|v| generate_runtime_info_impl(&decl, v))
|
||||
);
|
||||
|
||||
result.push(quote!( #decl #runtime_info ));
|
||||
result.push(quote!( #decl #runtime_info #( #errors )* ));
|
||||
}
|
||||
|
||||
quote!( #( #result )* )
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
use utils::{
|
||||
unwrap_or_error, generate_crate_access, generate_hidden_includes,
|
||||
generate_runtime_mod_name_for_trait, fold_fn_decl_for_client_side, generate_unique_pattern,
|
||||
extract_parameter_names_types_and_borrows, generate_native_call_generator_fn_name
|
||||
generate_runtime_mod_name_for_trait, generate_method_runtime_api_impl_name,
|
||||
extract_parameter_names_types_and_borrows, generate_native_call_generator_fn_name, return_type_extract_type
|
||||
};
|
||||
|
||||
use proc_macro;
|
||||
@@ -28,7 +28,7 @@ use quote::quote;
|
||||
use syn::{
|
||||
spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, MethodSig, Path,
|
||||
ImplItem, parse::{Parse, ParseStream, Result, Error}, PathArguments, GenericArgument, TypePath,
|
||||
fold::{self, Fold}, FnDecl, parse_quote, FnArg
|
||||
fold::{self, Fold}, parse_quote
|
||||
};
|
||||
|
||||
use std::{collections::HashSet, iter};
|
||||
@@ -300,11 +300,11 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
|
||||
res
|
||||
}
|
||||
|
||||
fn has_api<A: #crate_::runtime_api::RuntimeApiInfo + ?Sized>(
|
||||
fn runtime_version_at(
|
||||
&self,
|
||||
at: &#block_id
|
||||
) -> #crate_::error::Result<bool> where Self: Sized {
|
||||
self.call.runtime_version_at(at).map(|r| r.has_api::<A>())
|
||||
) -> #crate_::error::Result<#crate_::runtime_api::RuntimeVersion> {
|
||||
self.call.runtime_version_at(at)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,8 +336,8 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
|
||||
at: &#block_id,
|
||||
function: &'static str,
|
||||
args: Vec<u8>,
|
||||
native_call: NC,
|
||||
) -> #crate_::error::Result<R> {
|
||||
native_call: Option<NC>,
|
||||
) -> #crate_::error::Result<#crate_::runtime_api::NativeOrEncoded<R>> {
|
||||
let res = unsafe {
|
||||
self.call.call_api_at(
|
||||
at,
|
||||
@@ -345,21 +345,7 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
|
||||
args,
|
||||
&mut *self.changes.borrow_mut(),
|
||||
&mut *self.initialised_block.borrow_mut(),
|
||||
Some(native_call),
|
||||
).and_then(|r|
|
||||
match r {
|
||||
#crate_::runtime_api::NativeOrEncoded::Native(n) => {
|
||||
Ok(n)
|
||||
},
|
||||
#crate_::runtime_api::NativeOrEncoded::Encoded(r) => {
|
||||
R::decode(&mut &r[..])
|
||||
.ok_or_else(||
|
||||
#crate_::error::ErrorKind::CallResultDecode(
|
||||
function
|
||||
).into()
|
||||
)
|
||||
}
|
||||
}
|
||||
native_call,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -446,50 +432,69 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
|
||||
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 block = {
|
||||
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
|
||||
let mut generated_name_counter = 0;
|
||||
// Replace `_` with unique patterns and collect all patterns.
|
||||
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.clone()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let runtime_mod_path = self.runtime_mod_path;
|
||||
let runtime = self.runtime_type;
|
||||
let arg_names2 = arg_names.clone();
|
||||
let fn_name = prefix_function_with_trait(self.impl_trait_ident, &input.sig.ident);
|
||||
let native_call_generator_ident =
|
||||
generate_native_call_generator_fn_name(&input.sig.ident);
|
||||
let trait_generic_arguments = self.trait_generic_arguments;
|
||||
let node_block = self.node_block;
|
||||
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
|
||||
let block_id = self.node_block_id;
|
||||
|
||||
// Generate the access to the native parameters
|
||||
let param_tuple_access = if input.sig.decl.inputs.len() == 1 {
|
||||
vec![ quote!( p ) ]
|
||||
} else {
|
||||
input.sig.decl.inputs.iter().enumerate().map(|(i, _)| {
|
||||
let i = syn::Index::from(i);
|
||||
quote!( p.#i )
|
||||
}).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let (param_types, error) = match extract_parameter_names_types_and_borrows(&input.sig.decl) {
|
||||
Ok(res) => (
|
||||
res.into_iter().map(|v| {
|
||||
let ty = v.1;
|
||||
let borrow = v.2;
|
||||
quote!( #borrow #ty )
|
||||
}).collect::<Vec<_>>(),
|
||||
None
|
||||
),
|
||||
Err(e) => (Vec::new(), Some(e.to_compile_error())),
|
||||
};
|
||||
|
||||
// Rewrite the input parameters.
|
||||
input.sig.decl.inputs = parse_quote! {
|
||||
&self, at: &#block_id, params: Option<( #( #param_types ),* )>, params_encoded: Vec<u8>
|
||||
};
|
||||
|
||||
input.sig.ident = generate_method_runtime_api_impl_name(&input.sig.ident);
|
||||
let ret_type = return_type_extract_type(&input.sig.decl.output);
|
||||
|
||||
// Generate the correct return type.
|
||||
input.sig.decl.output = parse_quote!(
|
||||
-> #crate_::error::Result<#crate_::runtime_api::NativeOrEncoded<#ret_type>>
|
||||
);
|
||||
|
||||
// Generate the new method implementation that calls into the runime.
|
||||
parse_quote!(
|
||||
{
|
||||
let args = #crate_::runtime_api::Encode::encode(&( #( &#arg_names ),* ));
|
||||
// Get the error to the user (if we have one).
|
||||
#( #error )*
|
||||
|
||||
self.call_api_at(
|
||||
at,
|
||||
#fn_name,
|
||||
args,
|
||||
#runtime_mod_path #native_call_generator_ident ::
|
||||
<#runtime, #node_block #(, #trait_generic_arguments )*> (
|
||||
#( #arg_names2 ),*
|
||||
)
|
||||
params_encoded,
|
||||
params.map(|p| {
|
||||
#runtime_mod_path #native_call_generator_ident ::
|
||||
<#runtime, #node_block #(, #trait_generic_arguments )*> (
|
||||
#( #param_tuple_access ),*
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -159,7 +159,11 @@ pub fn impl_runtime_apis(input: TokenStream) -> TokenStream {
|
||||
///
|
||||
/// 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.
|
||||
/// version is provided. We also support chaning the signature of a method. This signature
|
||||
/// change is highlighted with the `#[changed_in(2)]` attribute above a method. A method that is
|
||||
/// tagged with this attribute is callable by the name `METHOD_before_version_VERSION`. This
|
||||
/// method will only support calling into wasm, trying to call into native will fail (change the
|
||||
/// spec version!). Such a method also does not need to be implemented in the runtime.
|
||||
///
|
||||
/// ```rust
|
||||
/// #[macro_use]
|
||||
@@ -171,8 +175,13 @@ pub fn impl_runtime_apis(input: TokenStream) -> TokenStream {
|
||||
/// pub trait Balance {
|
||||
/// /// Get the balance.
|
||||
/// fn get_balance() -> u64;
|
||||
/// /// Set the balance.
|
||||
/// /// Set balance.
|
||||
/// fn set_balance(val: u64);
|
||||
/// /// Set balance, old version.
|
||||
/// ///
|
||||
/// /// Is callable by `set_balance_before_version_2`.
|
||||
/// #[changed_in(2)]
|
||||
/// fn set_balance(val: u8);
|
||||
/// /// In version 2, we added this new function.
|
||||
/// fn increase_balance(val: u64);
|
||||
/// }
|
||||
|
||||
@@ -58,6 +58,11 @@ pub fn generate_runtime_mod_name_for_trait(trait_: &Ident) -> Ident {
|
||||
Ident::new(&format!("runtime_decl_for_{}", trait_.to_string()), Span::call_site())
|
||||
}
|
||||
|
||||
/// Generates a name for a method that needs to be implemented in the runtime for the client side.
|
||||
pub fn generate_method_runtime_api_impl_name(method: &Ident) -> Ident {
|
||||
Ident::new(&format!("{}_runtime_api_impl", method.to_string()), Span::call_site())
|
||||
}
|
||||
|
||||
/// Get the type of a `syn::ReturnType`.
|
||||
pub fn return_type_extract_type(rt: &syn::ReturnType) -> Type {
|
||||
match rt {
|
||||
|
||||
@@ -28,6 +28,8 @@ decl_runtime_apis! {
|
||||
#[api_version(2)]
|
||||
pub trait ApiWithCustomVersion {
|
||||
fn same_name();
|
||||
#[changed_in(2)]
|
||||
fn same_name() -> String;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +79,11 @@ fn test_client_side_function_signature() {
|
||||
let _something_with_block:
|
||||
fn(&RuntimeApiImpl<TestClient>, &BlockId<Block>, Block) -> Result<Block> =
|
||||
RuntimeApiImpl::<TestClient>::something_with_block;
|
||||
|
||||
#[allow(deprecated)]
|
||||
let _same_name_before_version_2:
|
||||
fn(&RuntimeApiImpl<TestClient>, &BlockId<Block>) -> Result<String> =
|
||||
RuntimeApiImpl::<TestClient>::same_name_before_version_2;
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -58,3 +58,23 @@ fn calling_native_runtime_function_with_non_decodable_return_value() {
|
||||
let block_id = BlockId::Number(client.info().unwrap().chain.best_number);
|
||||
runtime_api.fail_convert_return_value(&block_id).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_native_runtime_signature_changed_function() {
|
||||
let client = test_client::new_with_api_execution_strat(ExecutionStrategy::NativeWhenPossible);
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.info().unwrap().chain.best_number);
|
||||
|
||||
assert_eq!(runtime_api.function_signature_changed(&block_id).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_wasm_runtime_signature_changed_old_function() {
|
||||
let client = test_client::new_with_api_execution_strat(ExecutionStrategy::AlwaysWasm);
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.info().unwrap().chain.best_number);
|
||||
|
||||
#[allow(deprecated)]
|
||||
let res = runtime_api.function_signature_changed_before_version_2(&block_id).unwrap();
|
||||
assert_eq!(&res, &[1, 2]);
|
||||
}
|
||||
|
||||
@@ -136,6 +136,16 @@ impl RuntimeVersion {
|
||||
s == &A::ID && *v == A::VERSION
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if the given api is implemented and the version passes a predicate.
|
||||
pub fn has_api_with<A: RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
|
||||
&self,
|
||||
pred: P,
|
||||
) -> bool {
|
||||
self.apis.iter().any(|(s, v)| {
|
||||
s == &A::ID && pred(*v)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -21,6 +21,7 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
|
||||
runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
|
||||
runtime_version = { package = "sr-version", path = "../sr-version", default-features = false }
|
||||
srml-support = { path = "../../srml/support", default-features = false }
|
||||
cfg-if = "0.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-executor = { path = "../executor" }
|
||||
@@ -44,13 +45,3 @@ std = [
|
||||
"runtime_version/std",
|
||||
"consensus_aura/std",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
hash-db = { git = "https://github.com/paritytech/trie" }
|
||||
hash256-std-hasher = { git = "https://github.com/paritytech/trie" }
|
||||
keccak-hasher = { git = "https://github.com/paritytech/trie" }
|
||||
memory-db = { git = "https://github.com/paritytech/trie" }
|
||||
trie-bench = { git = "https://github.com/paritytech/trie" }
|
||||
trie-db = { git = "https://github.com/paritytech/trie" }
|
||||
trie-root = { git = "https://github.com/paritytech/trie" }
|
||||
trie-standardmap = { git = "https://github.com/paritytech/trie" }
|
||||
|
||||
@@ -46,6 +46,7 @@ use primitives::{Ed25519AuthorityId, OpaqueMetadata};
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use runtime_version::NativeVersion;
|
||||
use inherents::{CheckInherentsResult, InherentData};
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
/// Test runtime version.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
@@ -193,19 +194,47 @@ impl<B: BlockT> Decode for DecodeFails<B> {
|
||||
}
|
||||
}
|
||||
|
||||
decl_runtime_apis! {
|
||||
pub trait TestAPI {
|
||||
/// Return the balance of the given account id.
|
||||
fn balance_of(id: AccountId) -> u64;
|
||||
/// A benchmkark function that adds one to the given value and returns the result.
|
||||
fn benchmark_add_one(val: &u64) -> u64;
|
||||
/// A benchmark function that adds one to each value in the given vector and returns the
|
||||
/// result.
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64>;
|
||||
/// A function that always fails to convert a parameter between runtime and node.
|
||||
fn fail_convert_parameter(param: DecodeFails<Block>);
|
||||
/// A function that always fails to convert its return value between runtime and node.
|
||||
fn fail_convert_return_value() -> DecodeFails<Block>;
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
decl_runtime_apis! {
|
||||
#[api_version(2)]
|
||||
pub trait TestAPI {
|
||||
/// Return the balance of the given account id.
|
||||
fn balance_of(id: AccountId) -> u64;
|
||||
/// A benchmkark function that adds one to the given value and returns the result.
|
||||
fn benchmark_add_one(val: &u64) -> u64;
|
||||
/// A benchmark function that adds one to each value in the given vector and returns the
|
||||
/// result.
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64>;
|
||||
/// A function that always fails to convert a parameter between runtime and node.
|
||||
fn fail_convert_parameter(param: DecodeFails<Block>);
|
||||
/// A function that always fails to convert its return value between runtime and node.
|
||||
fn fail_convert_return_value() -> DecodeFails<Block>;
|
||||
/// A function for that the signature changed in version `2`.
|
||||
#[changed_in(2)]
|
||||
fn function_signature_changed() -> Vec<u64>;
|
||||
/// The new signature.
|
||||
fn function_signature_changed() -> u64;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decl_runtime_apis! {
|
||||
pub trait TestAPI {
|
||||
/// Return the balance of the given account id.
|
||||
fn balance_of(id: AccountId) -> u64;
|
||||
/// A benchmkark function that adds one to the given value and returns the result.
|
||||
fn benchmark_add_one(val: &u64) -> u64;
|
||||
/// A benchmark function that adds one to each value in the given vector and returns the
|
||||
/// result.
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64>;
|
||||
/// A function that always fails to convert a parameter between runtime and node.
|
||||
fn fail_convert_parameter(param: DecodeFails<Block>);
|
||||
/// A function that always fails to convert its return value between runtime and node.
|
||||
fn fail_convert_return_value() -> DecodeFails<Block>;
|
||||
/// In wasm we just emulate the old behavior.
|
||||
fn function_signature_changed() -> Vec<u64>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,82 +248,177 @@ impl GetRuntimeBlockType for Runtime {
|
||||
type RuntimeBlock = Block;
|
||||
}
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl client_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
version()
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
impl_runtime_apis! {
|
||||
impl client_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
version()
|
||||
}
|
||||
|
||||
fn authorities() -> Vec<Ed25519AuthorityId> {
|
||||
system::authorities()
|
||||
}
|
||||
|
||||
fn execute_block(block: Block) {
|
||||
system::execute_block(block)
|
||||
}
|
||||
|
||||
fn initialise_block(header: &<Block as BlockT>::Header) {
|
||||
system::initialise_block(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::Metadata<Block> for Runtime {
|
||||
fn metadata() -> OpaqueMetadata {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
system::validate_transaction(utx)
|
||||
}
|
||||
}
|
||||
|
||||
impl block_builder_api::BlockBuilder<Block> for Runtime {
|
||||
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
|
||||
system::execute_transaction(extrinsic)
|
||||
}
|
||||
|
||||
fn finalise_block() -> <Block as BlockT>::Header {
|
||||
system::finalise_block()
|
||||
}
|
||||
|
||||
fn inherent_extrinsics(_data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult {
|
||||
CheckInherentsResult::new()
|
||||
}
|
||||
|
||||
fn random_seed() -> <Block as BlockT>::Hash {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl self::TestAPI<Block> for Runtime {
|
||||
fn balance_of(id: AccountId) -> u64 {
|
||||
system::balance_of(id)
|
||||
}
|
||||
|
||||
fn benchmark_add_one(val: &u64) -> u64 {
|
||||
val + 1
|
||||
}
|
||||
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64> {
|
||||
let mut vec = vec.clone();
|
||||
vec.iter_mut().for_each(|v| *v += 1);
|
||||
vec
|
||||
}
|
||||
|
||||
fn fail_convert_parameter(_: DecodeFails<Block>) {}
|
||||
|
||||
fn fail_convert_return_value() -> DecodeFails<Block> {
|
||||
DecodeFails::new()
|
||||
}
|
||||
|
||||
fn function_signature_changed() -> u64 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl consensus_aura::AuraApi<Block> for Runtime {
|
||||
fn slot_duration() -> u64 { 1 }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl_runtime_apis! {
|
||||
impl client_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion {
|
||||
version()
|
||||
}
|
||||
|
||||
fn authorities() -> Vec<Ed25519AuthorityId> {
|
||||
system::authorities()
|
||||
fn authorities() -> Vec<Ed25519AuthorityId> {
|
||||
system::authorities()
|
||||
}
|
||||
|
||||
fn execute_block(block: Block) {
|
||||
system::execute_block(block)
|
||||
}
|
||||
|
||||
fn initialise_block(header: &<Block as BlockT>::Header) {
|
||||
system::initialise_block(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::Metadata<Block> for Runtime {
|
||||
fn metadata() -> OpaqueMetadata {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
system::validate_transaction(utx)
|
||||
}
|
||||
}
|
||||
|
||||
impl block_builder_api::BlockBuilder<Block> for Runtime {
|
||||
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
|
||||
system::execute_transaction(extrinsic)
|
||||
}
|
||||
|
||||
fn finalise_block() -> <Block as BlockT>::Header {
|
||||
system::finalise_block()
|
||||
}
|
||||
|
||||
fn inherent_extrinsics(_data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult {
|
||||
CheckInherentsResult::new()
|
||||
}
|
||||
|
||||
fn random_seed() -> <Block as BlockT>::Hash {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl self::TestAPI<Block> for Runtime {
|
||||
fn balance_of(id: AccountId) -> u64 {
|
||||
system::balance_of(id)
|
||||
}
|
||||
|
||||
fn benchmark_add_one(val: &u64) -> u64 {
|
||||
val + 1
|
||||
}
|
||||
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64> {
|
||||
let mut vec = vec.clone();
|
||||
vec.iter_mut().for_each(|v| *v += 1);
|
||||
vec
|
||||
}
|
||||
|
||||
fn fail_convert_parameter(_: DecodeFails<Block>) {}
|
||||
|
||||
fn fail_convert_return_value() -> DecodeFails<Block> {
|
||||
DecodeFails::new()
|
||||
}
|
||||
|
||||
fn function_signature_changed() -> Vec<u64> {
|
||||
let mut vec = Vec::new();
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
impl consensus_aura::AuraApi<Block> for Runtime {
|
||||
fn slot_duration() -> u64 { 1 }
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_block(block: Block) {
|
||||
system::execute_block(block)
|
||||
}
|
||||
|
||||
fn initialise_block(header: &<Block as BlockT>::Header) {
|
||||
system::initialise_block(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::Metadata<Block> for Runtime {
|
||||
fn metadata() -> OpaqueMetadata {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl client_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
system::validate_transaction(utx)
|
||||
}
|
||||
}
|
||||
|
||||
impl block_builder_api::BlockBuilder<Block> for Runtime {
|
||||
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
|
||||
system::execute_transaction(extrinsic)
|
||||
}
|
||||
|
||||
fn finalise_block() -> <Block as BlockT>::Header {
|
||||
system::finalise_block()
|
||||
}
|
||||
|
||||
fn inherent_extrinsics(_data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult {
|
||||
CheckInherentsResult::new()
|
||||
}
|
||||
|
||||
fn random_seed() -> <Block as BlockT>::Hash {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl self::TestAPI<Block> for Runtime {
|
||||
fn balance_of(id: AccountId) -> u64 {
|
||||
system::balance_of(id)
|
||||
}
|
||||
|
||||
fn benchmark_add_one(val: &u64) -> u64 {
|
||||
val + 1
|
||||
}
|
||||
|
||||
fn benchmark_vector_add_one(vec: &Vec<u64>) -> Vec<u64> {
|
||||
let mut vec = vec.clone();
|
||||
vec.iter_mut().for_each(|v| *v += 1);
|
||||
vec
|
||||
}
|
||||
|
||||
fn fail_convert_parameter(_: DecodeFails<Block>) {}
|
||||
|
||||
fn fail_convert_return_value() -> DecodeFails<Block> {
|
||||
DecodeFails::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl consensus_aura::AuraApi<Block> for Runtime {
|
||||
fn slot_duration() -> u64 { 1 }
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -1155,6 +1155,7 @@ dependencies = [
|
||||
"kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (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",
|
||||
@@ -1320,6 +1321,7 @@ dependencies = [
|
||||
name = "substrate-test-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
BIN
Binary file not shown.
@@ -66,8 +66,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("node"),
|
||||
impl_name: create_runtime_str!("substrate-node"),
|
||||
authoring_version: 10,
|
||||
spec_version: 20,
|
||||
impl_version: 20,
|
||||
spec_version: 21,
|
||||
impl_version: 21,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
Generated
+1
@@ -1525,6 +1525,7 @@ dependencies = [
|
||||
"kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (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",
|
||||
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user