ChainSpec trait (#5185)

* ChainSpec trait

* Apply suggestions from code review

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Added docs

* Fixed build

* Fixed build

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Arkadiy Paronyan
2020-03-12 00:00:10 +01:00
committed by GitHub
parent d2345e8d5c
commit dc0bf210fb
38 changed files with 354 additions and 335 deletions
+51 -4
View File
@@ -26,6 +26,7 @@ use sp_core::storage::{StorageKey, StorageData, ChildInfo, Storage, StorageChild
use sp_runtime::BuildStorage;
use serde_json as json;
use crate::RuntimeGenesis;
use crate::extension::GetExtension;
use sc_network::Multiaddr;
use sc_telemetry::TelemetryEndpoints;
@@ -269,9 +270,9 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
}
}
impl<G: RuntimeGenesis, E: serde::Serialize> ChainSpec<G, E> {
impl<G: RuntimeGenesis, E: serde::Serialize + Clone> ChainSpec<G, E> {
/// Dump to json string.
pub fn to_json(self, raw: bool) -> Result<String, String> {
pub fn as_json(&self, raw: bool) -> Result<String, String> {
#[derive(Serialize, Deserialize)]
struct Container<G, E> {
#[serde(flatten)]
@@ -306,7 +307,7 @@ impl<G: RuntimeGenesis, E: serde::Serialize> ChainSpec<G, E> {
(_, genesis) => genesis,
};
let container = Container {
client_spec: self.client_spec,
client_spec: self.client_spec.clone(),
genesis,
};
json::to_string_pretty(&container)
@@ -314,6 +315,52 @@ impl<G: RuntimeGenesis, E: serde::Serialize> ChainSpec<G, E> {
}
}
impl<G, E> crate::ChainSpec for ChainSpec<G, E>
where
G: RuntimeGenesis,
E: GetExtension + serde::Serialize + Clone,
{
fn boot_nodes(&self) -> &[String] {
ChainSpec::boot_nodes(self)
}
fn name(&self) -> &str {
ChainSpec::name(self)
}
fn id(&self) -> &str {
ChainSpec::id(self)
}
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> {
ChainSpec::telemetry_endpoints(self)
}
fn protocol_id(&self) -> Option<&str> {
ChainSpec::protocol_id(self)
}
fn properties(&self) -> Properties {
ChainSpec::properties(self)
}
fn add_boot_node(&mut self, addr: Multiaddr) {
ChainSpec::add_boot_node(self, addr)
}
fn extensions(&self) -> &dyn GetExtension {
ChainSpec::extensions(self) as &dyn GetExtension
}
fn as_json(&self, raw: bool) -> Result<String, String> {
ChainSpec::as_json(self, raw)
}
fn as_storage_builder(&self) -> &dyn BuildStorage {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -344,7 +391,7 @@ mod tests {
PathBuf::from("./res/chain_spec.json")
).unwrap();
assert_eq!(spec1.to_json(false), spec2.to_json(false));
assert_eq!(spec1.as_json(false), spec2.as_json(false));
}
#[derive(Debug, Serialize, Deserialize)]
+30 -4
View File
@@ -17,6 +17,8 @@
//! Chain Spec extensions helpers.
use std::fmt::Debug;
use std::any::{TypeId, Any};
use std::collections::BTreeMap;
use serde::{Serialize, Deserialize, de::DeserializeOwned};
@@ -120,6 +122,8 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
/// Get an extension of specific type.
fn get<T: 'static>(&self) -> Option<&T>;
/// Get an extension of specific type as refernce to `Any`
fn get_any(&self, t: TypeId) -> &dyn Any;
/// Get forkable extensions of specific type.
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where
@@ -137,6 +141,7 @@ impl Extension for crate::NoExtension {
type Forks = Self;
fn get<T: 'static>(&self) -> Option<&T> { None }
fn get_any(&self, _t: TypeId) -> &dyn Any { self }
}
pub trait IsForks {
@@ -225,22 +230,25 @@ impl<B, E> Extension for Forks<B, E> where
type Forks = Self;
fn get<T: 'static>(&self) -> Option<&T> {
use std::any::{TypeId, Any};
match TypeId::of::<T>() {
x if x == TypeId::of::<E>() => Any::downcast_ref(&self.base),
_ => self.base.get(),
}
}
fn get_any(&self, t: TypeId) -> &dyn Any {
match t {
x if x == TypeId::of::<E>() => &self.base,
_ => self.base.get_any(t),
}
}
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>> where
BlockNumber: Ord + Clone + 'static,
T: Group + 'static,
<Self::Forks as IsForks>::Extension: Extension,
<<Self::Forks as IsForks>::Extension as Group>::Fork: Extension,
{
use std::any::{TypeId, Any};
if TypeId::of::<BlockNumber>() == TypeId::of::<B>() {
Any::downcast_ref(&self.for_type::<T>()?).cloned()
} else {
@@ -250,6 +258,24 @@ impl<B, E> Extension for Forks<B, E> where
}
}
/// A subset if the `Extension` trait that only allows for quering extensions.
pub trait GetExtension {
/// Get an extension of specific type.
fn get_any(&self, t: TypeId) -> &dyn Any;
}
impl <E: Extension> GetExtension for E {
fn get_any(&self, t: TypeId) -> &dyn Any {
Extension::get_any(self, t)
}
}
/// Helper function that queries an extension by type from `GetExtension`
/// trait object.
pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
Any::downcast_ref(GetExtension::get_any(e, TypeId::of::<T>()))
}
#[cfg(test)]
mod tests {
use super::*;
+37 -9
View File
@@ -30,14 +30,14 @@
//! ```rust
//! use std::collections::HashMap;
//! use serde::{Serialize, Deserialize};
//! use sc_chain_spec::{ChainSpec, ChainSpecExtension};
//! use sc_chain_spec::{GenericChainSpec, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
//! pub struct MyExtension {
//! pub known_blocks: HashMap<u64, String>,
//! }
//!
//! pub type MyChainSpec<G> = ChainSpec<G, MyExtension>;
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
//! ```
//!
//! Some parameters may require different values depending on the
@@ -49,7 +49,7 @@
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use sc_chain_spec::{Forks, ChainSpec, ChainSpecGroup, ChainSpecExtension};
//! use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec};
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct ClientParams {
@@ -71,10 +71,10 @@
//! pub type BlockNumber = u64;
//!
//! /// A chain spec supporting forkable `ClientParams`.
//! pub type MyChainSpec1<G> = ChainSpec<G, Forks<BlockNumber, ClientParams>>;
//! pub type MyChainSpec1<G> = GenericChainSpec<G, Forks<BlockNumber, ClientParams>>;
//!
//! /// A chain spec supporting forkable `Extension`.
//! pub type MyChainSpec2<G> = ChainSpec<G, Forks<BlockNumber, Extension>>;
//! pub type MyChainSpec2<G> = GenericChainSpec<G, Forks<BlockNumber, Extension>>;
//! ```
//!
//! It's also possible to have a set of parameters that is allowed to change
@@ -84,7 +84,7 @@
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use sc_chain_spec::{Forks, ChainSpec, ChainSpecGroup, ChainSpecExtension};
//! use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct ClientParams {
@@ -104,20 +104,48 @@
//! pub pool: Forks<u64, PoolParams>,
//! }
//!
//! pub type MyChainSpec<G> = ChainSpec<G, Extension>;
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
//! ```
mod chain_spec;
mod extension;
pub use chain_spec::{ChainSpec, Properties, NoExtension};
pub use extension::{Group, Fork, Forks, Extension};
pub use chain_spec::{ChainSpec as GenericChainSpec, Properties, NoExtension};
pub use extension::{Group, Fork, Forks, Extension, GetExtension, get_extension};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
use serde::{Serialize, de::DeserializeOwned};
use sp_runtime::BuildStorage;
use sc_network::Multiaddr;
use sc_telemetry::TelemetryEndpoints;
/// A set of traits for the runtime genesis config.
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
/// Common interface to `GenericChainSpec`
pub trait ChainSpec: BuildStorage {
/// Spec name.
fn name(&self) -> &str;
/// Spec id.
fn id(&self) -> &str;
/// A list of bootnode addresses.
fn boot_nodes(&self) -> &[String];
/// Telemetry endpoints (if any)
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>;
/// Network protocol id.
fn protocol_id(&self) -> Option<&str>;
/// Additional loosly-typed properties of the chain.
///
/// Returns an empty JSON object if 'properties' not defined in config
fn properties(&self) -> Properties;
/// Returns a reference to defined chain spec extensions.
fn extensions(&self) -> &dyn GetExtension;
/// Add a bootnode to the list.
fn add_boot_node(&mut self, addr: Multiaddr);
/// Return spec as JSON.
fn as_json(&self, raw: bool) -> Result<String, String>;
/// Return StorageBuilder for this spec.
fn as_storage_builder(&self) -> &dyn BuildStorage;
}