From 7d5745cd1120006585f4d51d53284cce60b6f465 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 27 Sep 2018 14:34:19 +0200 Subject: [PATCH] Support authoring for multiple runtime versions --- core/client/src/call_executor.rs | 8 +++---- core/client/src/client.rs | 4 ++-- core/client/src/genesis.rs | 2 +- core/client/src/light/call_executor.rs | 4 ++-- core/executor/src/lib.rs | 9 ++++---- core/executor/src/native_executor.rs | 29 ++++++++++++++++---------- core/sr-version/src/lib.rs | 27 ++++++++++++++++++------ core/test-client/src/lib.rs | 2 +- core/test-runtime/src/lib.rs | 11 ++++++++++ node/executor/src/lib.rs | 2 +- node/runtime/src/lib.rs | 11 ++++++++++ 11 files changed, 77 insertions(+), 32 deletions(-) diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index aa862904500d0..372f20893b654 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -20,7 +20,7 @@ use runtime_primitives::generic::BlockId; use runtime_primitives::traits::Block as BlockT; use state_machine::{self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, native_when_possible}; -use executor::{RuntimeVersion, RuntimeInfo}; +use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; use trie::MemoryDB; use codec::Decode; @@ -89,7 +89,7 @@ where ) -> Result<(Vec, Vec>), error::Error>; /// Get runtime version if supported. - fn native_runtime_version(&self) -> Option; + fn native_runtime_version(&self) -> Option<&NativeVersion>; } /// Call executor that executes methods locally, querying all required @@ -194,7 +194,7 @@ where .map_err(Into::into) } - fn native_runtime_version(&self) -> Option { - ::NATIVE_VERSION + fn native_runtime_version(&self) -> Option<&NativeVersion> { + Some(self.executor.native_version()) } } diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 580c6f689cf9b..7fc3597db75e2 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -790,8 +790,8 @@ impl bft::Authorities for Client let native_version: Result<_, bft::Error> = self.executor.native_runtime_version() .ok_or_else(|| bft::ErrorKind::NativeRuntimeMissing.into()); let native_version = native_version?; - if !on_chain_version.can_author_with(&native_version) { - return Err(bft::ErrorKind::IncompatibleAuthoringRuntime(on_chain_version, native_version).into()) + if !native_version.can_author_with(&on_chain_version) { + return Err(bft::ErrorKind::IncompatibleAuthoringRuntime(on_chain_version, native_version.runtime_version.clone()).into()) } self.authorities_at(at).map_err(|_| { let descriptor = format!("{:?}", at); diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index ab6912bbbc014..927b923970fdc 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -52,7 +52,7 @@ mod tests { use test_client::runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic}; use primitives::{Blake2Hasher, ed25519::{Public, Pair}}; - native_executor_instance!(Executor, test_client::runtime::api::dispatch, test_client::runtime::VERSION, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); + native_executor_instance!(Executor, test_client::runtime::api::dispatch, test_client::runtime::native_version, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); fn executor() -> ::executor::NativeExecutor { NativeExecutionDispatch::new() diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index 11bd8faa0afb8..7efea9b00bc52 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -31,7 +31,7 @@ use blockchain::Backend as ChainBackend; use call_executor::{CallExecutor, CallResult}; use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::fetcher::{Fetcher, RemoteCallRequest}; -use executor::RuntimeVersion; +use executor::{RuntimeVersion, NativeVersion}; use codec::Decode; use heapsize::HeapSizeOf; use trie::MemoryDB; @@ -118,7 +118,7 @@ where Err(ClientErrorKind::NotAvailableOnLightClient.into()) } - fn native_runtime_version(&self) -> Option { + fn native_runtime_version(&self) -> Option<&NativeVersion> { None } } diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index 77c6818551e02..67e676abb838c 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -46,7 +46,8 @@ extern crate parking_lot; extern crate twox_hash; extern crate hash_db; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; #[macro_use] extern crate lazy_static; @@ -75,14 +76,14 @@ pub mod error; pub use wasm_executor::WasmExecutor; pub use native_executor::{with_native_environment, NativeExecutor, NativeExecutionDispatch}; pub use state_machine::Externalities; -pub use runtime_version::RuntimeVersion; +pub use runtime_version::{RuntimeVersion, NativeVersion}; pub use codec::Codec; use primitives::Blake2Hasher; /// Provides runtime information. pub trait RuntimeInfo { - /// Native runtime information if any. - const NATIVE_VERSION: Option; + /// Native runtime information. + fn native_version(&self) -> &NativeVersion; /// Extract RuntimeVersion of given :code block fn runtime_version> ( diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index 48636a0a48ad3..9ab82c1058485 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -18,7 +18,7 @@ use error::{Error, ErrorKind, Result}; use state_machine::{CodeExecutor, Externalities}; use wasm_executor::WasmExecutor; use wasmi::Module as WasmModule; -use runtime_version::RuntimeVersion; +use runtime_version::{NativeVersion, RuntimeVersion}; use std::collections::HashMap; use codec::Decode; use primitives::hashing::blake2_256; @@ -106,13 +106,11 @@ pub trait NativeExecutionDispatch: Send + Sync { // fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result>; fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result>; - /// Get native runtime version. - const VERSION: RuntimeVersion; + /// Provide native runtime version. + fn native_version() -> NativeVersion; /// Construct corresponding `NativeExecutor` - fn new() -> NativeExecutor where Self: Sized { - NativeExecutor::new() - } + fn new() -> NativeExecutor where Self: Sized; } /// A generic `CodeExecutor` implementation that uses a delegate to determine wasm code equivalence @@ -123,6 +121,8 @@ pub struct NativeExecutor { _dummy: ::std::marker::PhantomData, /// The fallback executor in case native isn't available. fallback: WasmExecutor, + /// Native runtime version info. + native_version: NativeVersion, } impl NativeExecutor { @@ -131,6 +131,7 @@ impl NativeExecutor { NativeExecutor { _dummy: Default::default(), fallback: WasmExecutor::new(), + native_version: D::native_version(), } } } @@ -140,12 +141,15 @@ impl Clone for NativeExecutor { NativeExecutor { _dummy: Default::default(), fallback: self.fallback.clone(), + native_version: D::native_version(), } } } impl RuntimeInfo for NativeExecutor { - const NATIVE_VERSION: Option = Some(D::VERSION); + fn native_version(&self) -> &NativeVersion { + &self.native_version + } fn runtime_version>( &self, @@ -174,16 +178,16 @@ impl CodeExecutor for NativeExecutor (module, onchain_version), Err(_) => return (Err(ErrorKind::InvalidCode(code.into()).into()), false), }; - match (use_native, onchain_version.as_ref().map_or(false, |v| v.can_call_with(&D::VERSION))) { + match (use_native, onchain_version.as_ref().map_or(false, |v| v.can_call_with(&self.native_version.runtime_version))) { (_, false) => { - trace!(target: "executor", "Request for native execution failed (native: {}, chain: {})", D::VERSION, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); + trace!(target: "executor", "Request for native execution failed (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); (self.fallback.call_in_wasm_module(ext, heap_pages, module, method, data), false) } (false, _) => { (self.fallback.call_in_wasm_module(ext, heap_pages, module, method, data), false) } _ => { - trace!(target: "executor", "Request for native execution succeeded (native: {}, chain: {})", D::VERSION, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); + trace!(target: "executor", "Request for native execution succeeded (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); (D::dispatch(ext, method, data), true) } } @@ -205,7 +209,6 @@ macro_rules! native_executor_instance { // TODO: this is not so great – I think I should go back to have dispatch take a type param and modify this macro to accept a type param and then pass it in from the test-client instead use primitives::Blake2Hasher as _Blake2Hasher; impl $crate::NativeExecutionDispatch for $name { - const VERSION: $crate::RuntimeVersion = $version; fn native_equivalent() -> &'static [u8] { // WARNING!!! This assumes that the runtime was built *before* the main project. Until we // get a proper build script, this must be strictly adhered to or things will go wrong. @@ -216,6 +219,10 @@ macro_rules! native_executor_instance { .ok_or_else(|| $crate::error::ErrorKind::MethodNotFound(method.to_owned()).into()) } + fn native_version() -> $crate::NativeVersion { + $version() + } + fn new() -> $crate::NativeExecutor<$name> { $crate::NativeExecutor::new() } diff --git a/core/sr-version/src/lib.rs b/core/sr-version/src/lib.rs index 1a008ef5d6063..0459ac7710779 100644 --- a/core/sr-version/src/lib.rs +++ b/core/sr-version/src/lib.rs @@ -36,6 +36,8 @@ extern crate parity_codec as codec; #[cfg(feature = "std")] use std::fmt; +#[cfg(feature = "std")] +use std::collections::HashSet; #[cfg(feature = "std")] pub type VersionString = ::std::borrow::Cow<'static, str>; @@ -129,14 +131,27 @@ impl RuntimeVersion { self.authoring_version == other.authoring_version } - /// Check if this version matches other version for authoring blocks. - pub fn can_author_with(&self, other: &RuntimeVersion) -> bool { - self.authoring_version == other.authoring_version && - self.spec_name == other.spec_name - } - /// 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) } } + +#[cfg(feature = "std")] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct NativeVersion { + /// Basic runtime version info. + pub runtime_version: RuntimeVersion, + /// Authoring runtimes that this native runtime supports. + pub can_author_with: HashSet, +} + +#[cfg(feature = "std")] +impl NativeVersion { + /// Check if this version matches other version for authoring blocks. + pub fn can_author_with(&self, other: &RuntimeVersion) -> bool { + self.runtime_version.spec_name == other.spec_name && + (self.runtime_version.authoring_version == other.authoring_version || + self.can_author_with.contains(&other.authoring_version)) + } +} diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index 48809c68f7281..5358b699498d7 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -45,7 +45,7 @@ mod local_executor { #![allow(missing_docs)] use super::runtime; // TODO: change the macro and pass in the `BlakeHasher` that dispatch needs from here instead - native_executor_instance!(pub LocalExecutor, runtime::api::dispatch, runtime::VERSION, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); + native_executor_instance!(pub LocalExecutor, runtime::api::dispatch, runtime::native_version, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); } /// Native executor used for tests. diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 320020b5655a5..dacf4be8e757d 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -59,6 +59,8 @@ use runtime_primitives::traits::{BlindCheckable, BlakeTwo256}; use runtime_primitives::Ed25519Signature; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; +#[cfg(any(feature = "std", test))] +use runtime_version::NativeVersion; /// Test runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -74,6 +76,15 @@ fn version() -> RuntimeVersion { VERSION } +/// Native version. +#[cfg(any(feature = "std", test))] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + /// Calls in transactions. #[derive(Clone, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index b0e7ba25f3200..6d1a630a3d188 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -39,7 +39,7 @@ extern crate substrate_trie as trie; #[cfg(test)] #[macro_use] extern crate hex_literal; pub use substrate_executor::NativeExecutor; -native_executor_instance!(pub Executor, node_runtime::api::dispatch, node_runtime::VERSION, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm")); +native_executor_instance!(pub Executor, node_runtime::api::dispatch, node_runtime::native_version, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm")); #[cfg(test)] mod tests { diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index e63a904797826..3696eaefca4f7 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -69,6 +69,8 @@ use runtime_primitives::generic; use runtime_primitives::traits::{Convert, BlakeTwo256, DigestItem}; use version::{RuntimeVersion, ApiId}; use council::{motions as council_motions, voting as council_voting}; +#[cfg(any(feature = "std", test))] +use version::NativeVersion; #[cfg(any(feature = "std", test))] pub use runtime_primitives::BuildStorage; @@ -94,6 +96,15 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { apis: apis_vec!([(INHERENT, 1), (VALIDATX, 1)]), }; +/// Native version. +#[cfg(any(feature = "std", test))] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + impl system::Trait for Runtime { type Origin = Origin; type Index = Index;