ChainSpec extensions (#3692)

* Add some chainspec tests and make sure we validate it.

* Manual implementation of Extension + Forks definitions.

* Move chain spec to separate crate.

* Allow using ChainSpec with extensions.

* Renames.

* Implement Extension derive.

* Implement Extension for Forks.

* Support specifying fork blocks.

* make for_blocks work

* Support forks correctly.

* Add a bunch of docs.

* Make fork blocks optional.

* Add missing docs.

* Fix build.

* Use struct for check_block params.

* Fix tests?

* Clean up.
This commit is contained in:
Tomasz Drwięga
2019-09-28 19:05:36 +02:00
committed by Gavin Wood
parent c555b9bf88
commit 667ee95f5d
39 changed files with 1368 additions and 336 deletions
+54 -35
View File
@@ -22,6 +22,7 @@ use client::{
BlockchainEvents, Client, runtime_api,
backend::RemoteBackend, light::blockchain::RemoteBlockchain,
};
use chain_spec::{RuntimeGenesis, Extension};
use codec::{Decode, Encode, IoReader};
use consensus_common::import_queue::ImportQueue;
use futures::{prelude::*, sync::mpsc};
@@ -33,12 +34,11 @@ use network::{config::BoxFinalityProofRequestBuilder, specialization::NetworkSpe
use parking_lot::{Mutex, RwLock};
use primitives::{Blake2Hasher, H256, Hasher};
use rpc::{self, system::SystemInfo};
use sr_primitives::{BuildStorage, generic::BlockId};
use sr_primitives::generic::BlockId;
use sr_primitives::traits::{
Block as BlockT, Extrinsic, ProvideRuntimeApi, NumberFor, One, Zero, Header, SaturatedConversion
};
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
use serde::{Serialize, de::DeserializeOwned};
use std::{io::{Read, Write, Seek}, marker::PhantomData, sync::Arc, sync::atomic::AtomicBool};
use sysinfo::{get_current_pid, ProcessExt, System, SystemExt};
use tel::{telemetry, SUBSTRATE_INFO};
@@ -62,10 +62,10 @@ use transaction_pool::txpool::{self, ChainApi, Pool as TransactionPool};
/// The order in which the `with_*` methods are called doesn't matter, as the correct binding of
/// generics is done when you call `build`.
///
pub struct ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
pub struct ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>
{
config: Configuration<TCfg, TGen>,
config: Configuration<TCfg, TGen, TCSExt>,
client: Arc<TCl>,
backend: Arc<Backend>,
keystore: Arc<RwLock<Keystore>>,
@@ -128,16 +128,17 @@ type TLightCallExecutor<TBl, TExecDisp> = client::light::call_executor::GenesisC
>,
>;
impl<TCfg, TGen> ServiceBuilder<(), (), TCfg, TGen, (), (), (), (), (), (), (), (), (), (), ()>
where TGen: Serialize + DeserializeOwned + BuildStorage {
impl<TCfg, TGen, TCSExt> ServiceBuilder<(), (), TCfg, TGen, TCSExt, (), (), (), (), (), (), (), (), (), (), ()>
where TGen: RuntimeGenesis, TCSExt: Extension {
/// Start the service builder with a configuration.
pub fn new_full<TBl: BlockT<Hash=H256>, TRtApi, TExecDisp: NativeExecutionDispatch>(
config: Configuration<TCfg, TGen>
config: Configuration<TCfg, TGen, TCSExt>
) -> Result<ServiceBuilder<
TBl,
TRtApi,
TCfg,
TGen,
TCSExt,
TFullClient<TBl, TRtApi, TExecDisp>,
Arc<OnDemand<TBl>>,
(),
@@ -163,10 +164,17 @@ where TGen: Serialize + DeserializeOwned + BuildStorage {
let executor = NativeExecutor::<TExecDisp>::new(config.default_heap_pages);
let fork_blocks = config.chain_spec
.extensions()
.get::<client::ForkBlocks<TBl>>()
.cloned()
.unwrap_or_default();
let (client, backend) = client_db::new_client(
db_settings,
executor,
&config.chain_spec,
fork_blocks,
config.execution_strategies.clone(),
Some(keystore.clone()),
)?;
@@ -196,12 +204,13 @@ where TGen: Serialize + DeserializeOwned + BuildStorage {
/// Start the service builder with a configuration.
pub fn new_light<TBl: BlockT<Hash=H256>, TRtApi, TExecDisp: NativeExecutionDispatch + 'static>(
config: Configuration<TCfg, TGen>
config: Configuration<TCfg, TGen, TCSExt>
) -> Result<ServiceBuilder<
TBl,
TRtApi,
TCfg,
TGen,
TCSExt,
TLightClient<TBl, TRtApi, TExecDisp>,
Arc<OnDemand<TBl>>,
(),
@@ -264,8 +273,8 @@ where TGen: Serialize + DeserializeOwned + BuildStorage {
}
}
impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>
ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
impl<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>
ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend> {
/// Returns a reference to the client that was stored in this builder.
@@ -286,8 +295,10 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
/// Defines which head-of-chain strategy to use.
pub fn with_opt_select_chain<USc>(
self,
select_chain_builder: impl FnOnce(&Configuration<TCfg, TGen>, &Arc<Backend>) -> Result<Option<USc>, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, USc, TImpQu, TFprb, TFpp,
select_chain_builder: impl FnOnce(
&Configuration<TCfg, TGen, TCSExt>, &Arc<Backend>
) -> Result<Option<USc>, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, USc, TImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error> {
let select_chain = select_chain_builder(&self.config, &self.backend)?;
@@ -313,8 +324,8 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
/// Defines which head-of-chain strategy to use.
pub fn with_select_chain<USc>(
self,
builder: impl FnOnce(&Configuration<TCfg, TGen>, &Arc<Backend>) -> Result<USc, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, USc, TImpQu, TFprb, TFpp,
builder: impl FnOnce(&Configuration<TCfg, TGen, TCSExt>, &Arc<Backend>) -> Result<USc, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, USc, TImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error> {
self.with_opt_select_chain(|cfg, b| builder(cfg, b).map(Option::Some))
}
@@ -322,9 +333,9 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
/// Defines which import queue to use.
pub fn with_import_queue<UImpQu>(
self,
builder: impl FnOnce(&Configuration<TCfg, TGen>, Arc<TCl>, Option<TSc>, Arc<TExPool>)
builder: impl FnOnce(&Configuration<TCfg, TGen, TCSExt>, Arc<TCl>, Option<TSc>, Arc<TExPool>)
-> Result<UImpQu, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, UImpQu, TFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, UImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error>
where TSc: Clone {
let import_queue = builder(
@@ -356,8 +367,8 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
/// Defines which network specialization protocol to use.
pub fn with_network_protocol<UNetP>(
self,
network_protocol_builder: impl FnOnce(&Configuration<TCfg, TGen>) -> Result<UNetP, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
network_protocol_builder: impl FnOnce(&Configuration<TCfg, TGen, TCSExt>) -> Result<UNetP, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
UNetP, TExPool, TRpc, TRpcB, Backend>, Error> {
let network_protocol = network_protocol_builder(&self.config)?;
@@ -389,6 +400,7 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
TRtApi,
TCfg,
TGen,
TCSExt,
TCl,
TFchr,
TSc,
@@ -431,6 +443,7 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
TRtApi,
TCfg,
TGen,
TCSExt,
TCl,
TFchr,
TSc,
@@ -450,14 +463,14 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
pub fn with_import_queue_and_opt_fprb<UImpQu, UFprb>(
self,
builder: impl FnOnce(
&Configuration<TCfg, TGen>,
&Configuration<TCfg, TGen, TCSExt>,
Arc<TCl>,
Arc<Backend>,
Option<TFchr>,
Option<TSc>,
Arc<TExPool>,
) -> Result<(UImpQu, Option<UFprb>), Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, UImpQu, UFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, UImpQu, UFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error>
where TSc: Clone, TFchr: Clone {
let (import_queue, fprb) = builder(
@@ -492,14 +505,14 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
pub fn with_import_queue_and_fprb<UImpQu, UFprb>(
self,
builder: impl FnOnce(
&Configuration<TCfg, TGen>,
&Configuration<TCfg, TGen, TCSExt>,
Arc<TCl>,
Arc<Backend>,
Option<TFchr>,
Option<TSc>,
Arc<TExPool>,
) -> Result<(UImpQu, UFprb), Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, UImpQu, UFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, UImpQu, UFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error>
where TSc: Clone, TFchr: Clone {
self.with_import_queue_and_opt_fprb(|cfg, cl, b, f, sc, tx|
@@ -512,7 +525,7 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
pub fn with_transaction_pool<UExPool>(
self,
transaction_pool_builder: impl FnOnce(transaction_pool::txpool::Options, Arc<TCl>) -> Result<UExPool, Error>
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
TNetP, UExPool, TRpc, TRpcB, Backend>, Error> {
let transaction_pool = transaction_pool_builder(self.config.transaction_pool.clone(), self.client.clone())?;
@@ -539,7 +552,7 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
pub fn with_rpc_extensions<URpc>(
self,
rpc_ext_builder: impl FnOnce(Arc<TCl>, Arc<TExPool>) -> URpc
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
TNetP, TExPool, URpc, TRpcB, Backend>, Error> {
let rpc_extensions = rpc_ext_builder(self.client.clone(), self.transaction_pool.clone());
@@ -567,7 +580,7 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo
pub fn with_dht_event_tx(
self,
dht_event_tx: mpsc::Sender<DhtEvent>,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, TCl, TFchr, TSc, TImpQu, TFprb, TFpp,
TNetP, TExPool, TRpc, TRpcB, Backend>, Error> {
Ok(ServiceBuilder {
config: self.config,
@@ -708,10 +721,14 @@ pub trait ServiceBuilderRevert {
) -> Result<(), Error>;
}
impl<TBl, TRtApi, TCfg, TGen, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>
ServiceBuilderImport for ServiceBuilder<TBl, TRtApi, TCfg, TGen, Client<TBackend, TExec, TBl, TRtApi>,
TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>
where
impl<
TBl, TRtApi, TCfg, TGen, TCSExt, TBackend,
TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP,
TExPool, TRpc, TRpcB, Backend
> ServiceBuilderImport for ServiceBuilder<
TBl, TRtApi, TCfg, TGen, TCSExt, Client<TBackend, TExec, TBl, TRtApi>,
TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend
> where
TBl: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
TBackend: 'static + client::backend::Backend<TBl, Blake2Hasher> + Send,
TExec: 'static + client::CallExecutor<TBl, Blake2Hasher> + Send + Sync + Clone,
@@ -730,8 +747,8 @@ where
}
}
impl<TBl, TRtApi, TCfg, TGen, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB>
ServiceBuilderExport for ServiceBuilder<TBl, TRtApi, TCfg, TGen, Client<TBackend, TExec, TBl, TRtApi>,
impl<TBl, TRtApi, TCfg, TGen, TCSExt, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB>
ServiceBuilderExport for ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, Client<TBackend, TExec, TBl, TRtApi>,
TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, TBackend>
where
TBl: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
@@ -753,8 +770,8 @@ where
}
}
impl<TBl, TRtApi, TCfg, TGen, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB>
ServiceBuilderRevert for ServiceBuilder<TBl, TRtApi, TCfg, TGen, Client<TBackend, TExec, TBl, TRtApi>,
impl<TBl, TRtApi, TCfg, TGen, TCSExt, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB>
ServiceBuilderRevert for ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCSExt, Client<TBackend, TExec, TBl, TRtApi>,
TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, TBackend>
where
TBl: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
@@ -772,12 +789,13 @@ where
}
}
impl<TBl, TRtApi, TCfg, TGen, TBackend, TExec, TSc, TImpQu, TNetP, TExPoolApi, TRpc, TRpcB>
impl<TBl, TRtApi, TCfg, TGen, TCSExt, TBackend, TExec, TSc, TImpQu, TNetP, TExPoolApi, TRpc, TRpcB>
ServiceBuilder<
TBl,
TRtApi,
TCfg,
TGen,
TCSExt,
Client<TBackend, TExec, TBl, TRtApi>,
Arc<OnDemand<TBl>>,
TSc,
@@ -799,7 +817,8 @@ ServiceBuilder<
TBl: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
TRtApi: 'static + Send + Sync,
TCfg: Default,
TGen: Serialize + DeserializeOwned + BuildStorage,
TGen: RuntimeGenesis,
TCSExt: Extension,
TBackend: 'static + client::backend::Backend<TBl, Blake2Hasher> + Send,
TExec: 'static + client::CallExecutor<TBl, Blake2Hasher> + Send + Sync + Clone,
TSc: Clone,
+4 -4
View File
@@ -16,9 +16,8 @@
//! Chain utilities.
use crate::RuntimeGenesis;
use crate::error;
use crate::chain_spec::ChainSpec;
use chain_spec::{ChainSpec, RuntimeGenesis, Extension};
/// Defines the logic for an operation exporting blocks within a range.
#[macro_export]
@@ -222,8 +221,9 @@ macro_rules! revert_chain {
}
/// Build a chain spec json
pub fn build_spec<G>(spec: ChainSpec<G>, raw: bool) -> error::Result<String>
where G: RuntimeGenesis,
pub fn build_spec<G, E>(spec: ChainSpec<G, E>, raw: bool) -> error::Result<String> where
G: RuntimeGenesis,
E: Extension,
{
Ok(spec.to_json(raw)?)
}
-256
View File
@@ -1,256 +0,0 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Substrate chain configurations.
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use primitives::storage::{StorageKey, StorageData};
use sr_primitives::{BuildStorage, StorageOverlay, ChildrenStorageOverlay};
use serde_json as json;
use crate::RuntimeGenesis;
use network::Multiaddr;
use tel::TelemetryEndpoints;
enum GenesisSource<G> {
File(PathBuf),
Binary(Cow<'static, [u8]>),
Factory(fn() -> G),
}
impl<G> Clone for GenesisSource<G> {
fn clone(&self) -> Self {
match *self {
GenesisSource::File(ref path) => GenesisSource::File(path.clone()),
GenesisSource::Binary(ref d) => GenesisSource::Binary(d.clone()),
GenesisSource::Factory(f) => GenesisSource::Factory(f),
}
}
}
impl<G: RuntimeGenesis> GenesisSource<G> {
fn resolve(&self) -> Result<Genesis<G>, String> {
#[derive(Serialize, Deserialize)]
struct GenesisContainer<G> {
genesis: Genesis<G>,
}
match self {
GenesisSource::File(path) => {
let file = File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?;
let genesis: GenesisContainer<G> =
json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(genesis.genesis)
},
GenesisSource::Binary(buf) => {
let genesis: GenesisContainer<G> =
json::from_reader(buf.as_ref()).map_err(|e| format!("Error parsing embedded file: {}", e))?;
Ok(genesis.genesis)
},
GenesisSource::Factory(f) => Ok(Genesis::Runtime(f())),
}
}
}
impl<'a, G: RuntimeGenesis> BuildStorage for &'a ChainSpec<G> {
fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> {
match self.genesis.resolve()? {
Genesis::Runtime(gc) => gc.build_storage(),
Genesis::Raw(map, children_map) => Ok((
map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
children_map.into_iter().map(|(sk, map)| (
sk.0,
map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
)).collect(),
)),
}
}
fn assimilate_storage(self, _: &mut (StorageOverlay, ChildrenStorageOverlay)) -> Result<(), String> {
Err("`assimilate_storage` not implemented for `ChainSpec`.".into())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
enum Genesis<G> {
Runtime(G),
Raw(
HashMap<StorageKey, StorageData>,
HashMap<StorageKey, HashMap<StorageKey, StorageData>>,
),
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct ChainSpecFile {
pub name: String,
pub id: String,
pub boot_nodes: Vec<String>,
pub telemetry_endpoints: Option<TelemetryEndpoints>,
pub protocol_id: Option<String>,
pub consensus_engine: Option<String>,
pub properties: Option<Properties>,
}
/// Arbitrary properties defined in chain spec as a JSON object
pub type Properties = json::map::Map<String, json::Value>;
/// A configuration of a chain. Can be used to build a genesis block.
pub struct ChainSpec<G> {
spec: ChainSpecFile,
genesis: GenesisSource<G>,
}
impl<G> Clone for ChainSpec<G> {
fn clone(&self) -> Self {
ChainSpec {
spec: self.spec.clone(),
genesis: self.genesis.clone(),
}
}
}
impl<G> ChainSpec<G> {
/// A list of bootnode addresses.
pub fn boot_nodes(&self) -> &[String] {
&self.spec.boot_nodes
}
/// Spec name.
pub fn name(&self) -> &str {
&self.spec.name
}
/// Spec id.
pub fn id(&self) -> &str {
&self.spec.id
}
/// Telemetry endpoints (if any)
pub fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> {
&self.spec.telemetry_endpoints
}
/// Network protocol id.
pub fn protocol_id(&self) -> Option<&str> {
self.spec.protocol_id.as_ref().map(String::as_str)
}
/// Name of the consensus engine.
pub fn consensus_engine(&self) -> Option<&str> {
self.spec.consensus_engine.as_ref().map(String::as_str)
}
/// Additional loosly-typed properties of the chain.
pub fn properties(&self) -> Properties {
// Return an empty JSON object if 'properties' not defined in config
self.spec.properties.as_ref().unwrap_or(&json::map::Map::new()).clone()
}
/// Add a bootnode to the list.
pub fn add_boot_node(&mut self, addr: Multiaddr) {
self.spec.boot_nodes.push(addr.to_string())
}
/// Parse json content into a `ChainSpec`
pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> {
let json = json.into();
let spec = json::from_slice(json.as_ref()).map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(ChainSpec {
spec,
genesis: GenesisSource::Binary(json),
})
}
/// Parse json file into a `ChainSpec`
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?;
let spec = json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(ChainSpec {
spec,
genesis: GenesisSource::File(path),
})
}
/// Create hardcoded spec.
pub fn from_genesis(
name: &str,
id: &str,
constructor: fn() -> G,
boot_nodes: Vec<String>,
telemetry_endpoints: Option<TelemetryEndpoints>,
protocol_id: Option<&str>,
consensus_engine: Option<&str>,
properties: Option<Properties>,
) -> Self
{
let spec = ChainSpecFile {
name: name.to_owned(),
id: id.to_owned(),
boot_nodes: boot_nodes,
telemetry_endpoints,
protocol_id: protocol_id.map(str::to_owned),
consensus_engine: consensus_engine.map(str::to_owned),
properties,
};
ChainSpec {
spec,
genesis: GenesisSource::Factory(constructor),
}
}
}
impl<G: RuntimeGenesis> ChainSpec<G> {
/// Dump to json string.
pub fn to_json(self, raw: bool) -> Result<String, String> {
#[derive(Serialize, Deserialize)]
struct Container<G> {
#[serde(flatten)]
spec: ChainSpecFile,
genesis: Genesis<G>,
};
let genesis = match (raw, self.genesis.resolve()?) {
(true, Genesis::Runtime(g)) => {
let storage = g.build_storage()?;
let top = storage.0.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect();
let children = storage.1.into_iter()
.map(|(sk, child)| (
StorageKey(sk),
child.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
))
.collect();
Genesis::Raw(top, children)
},
(_, genesis) => genesis,
};
let spec = Container {
spec: self.spec,
genesis,
};
json::to_string_pretty(&spec).map_err(|e| format!("Error generating spec json: {}", e))
}
}
+9 -7
View File
@@ -22,16 +22,14 @@ pub use network::config::{ExtTransport, NetworkConfiguration, Roles};
use std::{path::PathBuf, net::SocketAddr};
use transaction_pool;
use crate::chain_spec::ChainSpec;
use chain_spec::{ChainSpec, RuntimeGenesis, Extension, NoExtension};
use primitives::crypto::Protected;
use sr_primitives::BuildStorage;
use serde::{Serialize, de::DeserializeOwned};
use target_info::Target;
use tel::TelemetryEndpoints;
/// Service configuration.
#[derive(Clone)]
pub struct Configuration<C, G> {
pub struct Configuration<C, G, E = NoExtension> {
/// Implementation name
pub impl_name: &'static str,
/// Implementation version
@@ -57,7 +55,7 @@ pub struct Configuration<C, G> {
/// Pruning settings.
pub pruning: PruningMode,
/// Chain configuration.
pub chain_spec: ChainSpec<G>,
pub chain_spec: ChainSpec<G, E>,
/// Custom configuration.
pub custom: C,
/// Node name.
@@ -95,9 +93,13 @@ pub struct Configuration<C, G> {
pub dev_key_seed: Option<String>,
}
impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C, G> {
impl<C, G, E> Configuration<C, G, E> where
C: Default,
G: RuntimeGenesis,
E: Extension,
{
/// Create default config for given chain spec.
pub fn default_with_spec(chain_spec: ChainSpec<G>) -> Self {
pub fn default_with_spec(chain_spec: ChainSpec<G, E>) -> Self {
let mut configuration = Configuration {
impl_name: "parity-substrate",
impl_version: "0.0.0",
+8 -15
View File
@@ -19,7 +19,6 @@
#![warn(missing_docs)]
mod chain_spec;
pub mod config;
#[macro_use]
pub mod chain_ops;
@@ -31,7 +30,6 @@ use std::net::SocketAddr;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use serde::{Serialize, de::DeserializeOwned};
use futures::sync::mpsc;
use parking_lot::Mutex;
@@ -43,14 +41,13 @@ use network::{NetworkService, NetworkState, specialization::NetworkSpecializatio
use log::{log, warn, debug, error, Level};
use codec::{Encode, Decode};
use primitives::{Blake2Hasher, H256};
use sr_primitives::BuildStorage;
use sr_primitives::generic::BlockId;
use sr_primitives::traits::NumberFor;
pub use self::error::Error;
pub use self::builder::{ServiceBuilder, ServiceBuilderExport, ServiceBuilderImport, ServiceBuilderRevert};
pub use config::{Configuration, Roles, PruningMode};
pub use chain_spec::{ChainSpec, Properties};
pub use chain_spec::{ChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension};
pub use transaction_pool::txpool::{
self, Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, IntoPoolError
};
@@ -100,10 +97,6 @@ pub struct NewService<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> {
marker: PhantomData<TBl>,
}
/// A set of traits for the runtime genesis config.
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
/// Alias for a an implementation of `futures::future::Executor`.
pub type TaskExecutor = Arc<dyn Executor<Box<dyn Future<Item = (), Error = ()> + Send>> + Send + Sync>;
@@ -349,7 +342,7 @@ macro_rules! new_impl {
chain_name: $config.chain_spec.name().into(),
impl_name: $config.impl_name.into(),
impl_version: $config.impl_version.into(),
properties: $config.chain_spec.properties(),
properties: $config.chain_spec.properties().clone(),
};
$start_rpc(
client.clone(),
@@ -805,8 +798,8 @@ impl<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> Drop for
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(not(target_os = "unknown"))]
fn start_rpc_servers<C, G, H: FnMut() -> rpc_servers::RpcHandler<rpc::Metadata>>(
config: &Configuration<C, G>,
fn start_rpc_servers<C, G, E, H: FnMut() -> rpc_servers::RpcHandler<rpc::Metadata>>(
config: &Configuration<C, G, E>,
mut gen_handler: H
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
fn maybe_start_server<T, F>(address: Option<SocketAddr>, mut start: F) -> Result<Option<T>, io::Error>
@@ -846,8 +839,8 @@ fn start_rpc_servers<C, G, H: FnMut() -> rpc_servers::RpcHandler<rpc::Metadata>>
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(target_os = "unknown")]
fn start_rpc_servers<C, G, H: FnMut() -> components::RpcHandler>(
_: &Configuration<C, G>,
fn start_rpc_servers<C, G, E, H: FnMut() -> components::RpcHandler>(
_: &Configuration<C, G, E>,
_: H
) -> Result<Box<std::any::Any + Send + Sync>, error::Error> {
Ok(Box::new(()))
@@ -888,7 +881,7 @@ fn transactions_to_propagate<PoolApi, B, H, E>(pool: &TransactionPool<PoolApi>)
where
PoolApi: ChainApi<Block=B, Hash=H, Error=E>,
B: BlockT,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + serde::Serialize,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + sr_primitives::traits::MaybeSerialize,
E: txpool::error::IntoPoolError + From<txpool::error::Error>,
{
pool.ready()
@@ -907,7 +900,7 @@ where
C: network::ClientHandle<B> + Send + Sync,
PoolApi: ChainApi<Block=B, Hash=H, Error=E>,
B: BlockT,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + serde::Serialize,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + sr_primitives::traits::MaybeSerialize,
E: txpool::error::IntoPoolError + From<txpool::error::Error>,
{
fn transactions(&self) -> Vec<(H, <B as BlockT>::Extrinsic)> {