-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #532 from subspace/sc-subspace-chain-specs
Introduce `sc-subspace-chain-specs` crate
- Loading branch information
Showing
12 changed files
with
388 additions
and
313 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "sc-subspace-chain-specs" | ||
description = "Chain specification data structures tailored for Subspace" | ||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0" | ||
version = "0.1.0" | ||
authors = ["Nazar Mokrynskyi <[email protected]>"] | ||
edition = "2021" | ||
include = [ | ||
"/src", | ||
"/Cargo.toml", | ||
"/README.md", | ||
] | ||
|
||
[dependencies] | ||
sc-chain-spec = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" } | ||
sc-service = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd", features = ["wasmtime"] } | ||
sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" } | ||
serde = "1.0.137" | ||
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" } | ||
sp-runtime = { version = "6.0.0", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright (C) 2021 Subspace Labs, Inc. | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
// This program 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. | ||
|
||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
//! Chain specification data structures tailored for Subspace. | ||
mod utils; | ||
|
||
use crate::utils::SerializableChainSpec; | ||
use sc_chain_spec::{ChainSpecExtension, RuntimeGenesis}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// The extensions for the [`ConsensusChainSpec`]. | ||
#[derive(Serialize, Deserialize, ChainSpecExtension)] | ||
#[serde(deny_unknown_fields, rename_all = "camelCase")] | ||
#[serde(bound = "")] | ||
pub struct ChainSpecExtensions<ExecutionGenesisConfig> | ||
where | ||
ExecutionGenesisConfig: RuntimeGenesis + 'static, | ||
{ | ||
/// Chain spec of execution chain. | ||
pub execution_chain_spec: ExecutionChainSpec<ExecutionGenesisConfig>, | ||
} | ||
|
||
impl<ExecutionGenesisConfig> Clone for ChainSpecExtensions<ExecutionGenesisConfig> | ||
where | ||
ExecutionGenesisConfig: RuntimeGenesis + 'static, | ||
{ | ||
fn clone(&self) -> Self { | ||
Self { | ||
execution_chain_spec: self.execution_chain_spec.clone(), | ||
} | ||
} | ||
} | ||
|
||
/// Specialized `ChainSpec` for the consensus runtime. | ||
pub type ConsensusChainSpec<GenesisConfig, ExecutionGenesisConfig> = | ||
SerializableChainSpec<GenesisConfig, ChainSpecExtensions<ExecutionGenesisConfig>>; | ||
|
||
/// Specialized `ChainSpec` for the execution runtime. | ||
pub type ExecutionChainSpec<ExecutionGenesisConfig> = SerializableChainSpec<ExecutionGenesisConfig>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
use sc_chain_spec::{ | ||
ChainSpec, ChainType, GenericChainSpec, GetExtension, NoExtension, RuntimeGenesis, | ||
}; | ||
use sc_service::config::MultiaddrWithPeerId; | ||
use sc_service::Properties; | ||
use sc_telemetry::TelemetryEndpoints; | ||
use serde::de::Visitor; | ||
use serde::ser::Error as _; | ||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; | ||
use sp_core::storage::Storage; | ||
use sp_runtime::BuildStorage; | ||
use std::borrow::Cow; | ||
use std::collections::BTreeMap; | ||
use std::fmt; | ||
use std::marker::PhantomData; | ||
use std::path::PathBuf; | ||
|
||
pub struct SerializableChainSpec<GenesisConfig, Extensions = NoExtension> { | ||
chain_spec: GenericChainSpec<GenesisConfig, Extensions>, | ||
} | ||
|
||
impl<GenesisConfig, Extensions> Clone for SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
Extensions: Clone, | ||
{ | ||
fn clone(&self) -> Self { | ||
Self { | ||
chain_spec: self.chain_spec.clone(), | ||
} | ||
} | ||
} | ||
|
||
impl<GenesisConfig, Extensions> Serialize for SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
GenesisConfig: RuntimeGenesis + 'static, | ||
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static, | ||
{ | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
{ | ||
serializer.serialize_str(&self.as_json(true).map_err(S::Error::custom)?) | ||
} | ||
} | ||
|
||
impl<'de, GenesisConfig, Extensions> Deserialize<'de> | ||
for SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
Extensions: de::DeserializeOwned, | ||
{ | ||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
where | ||
D: Deserializer<'de>, | ||
{ | ||
struct StringVisitor<GenesisConfig, Extensions> { | ||
_phantom_data: PhantomData<(GenesisConfig, Extensions)>, | ||
} | ||
|
||
impl<'de, GenesisConfig, Extensions> Visitor<'de> for StringVisitor<GenesisConfig, Extensions> | ||
where | ||
Extensions: de::DeserializeOwned, | ||
{ | ||
type Value = SerializableChainSpec<GenesisConfig, Extensions>; | ||
|
||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | ||
formatter.write_str("ExecutionChainSpec") | ||
} | ||
|
||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> | ||
where | ||
E: de::Error, | ||
{ | ||
self.visit_string(value.to_string()) | ||
} | ||
|
||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> | ||
where | ||
E: de::Error, | ||
{ | ||
Self::Value::from_json_bytes(value.into_bytes()).map_err(E::custom) | ||
} | ||
} | ||
deserializer.deserialize_string(StringVisitor { | ||
_phantom_data: PhantomData::default(), | ||
}) | ||
} | ||
} | ||
|
||
impl<GenesisConfig, Extensions> BuildStorage for SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
GenesisConfig: RuntimeGenesis, | ||
{ | ||
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> { | ||
self.chain_spec.assimilate_storage(storage) | ||
} | ||
} | ||
|
||
impl<GenesisConfig, Extensions> ChainSpec for SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
GenesisConfig: RuntimeGenesis + 'static, | ||
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static, | ||
{ | ||
fn name(&self) -> &str { | ||
self.chain_spec.name() | ||
} | ||
|
||
fn id(&self) -> &str { | ||
self.chain_spec.id() | ||
} | ||
|
||
fn chain_type(&self) -> ChainType { | ||
ChainSpec::chain_type(&self.chain_spec) | ||
} | ||
|
||
fn boot_nodes(&self) -> &[MultiaddrWithPeerId] { | ||
self.chain_spec.boot_nodes() | ||
} | ||
|
||
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> { | ||
self.chain_spec.telemetry_endpoints() | ||
} | ||
|
||
fn protocol_id(&self) -> Option<&str> { | ||
self.chain_spec.protocol_id() | ||
} | ||
|
||
fn fork_id(&self) -> Option<&str> { | ||
self.chain_spec.fork_id() | ||
} | ||
|
||
fn properties(&self) -> Properties { | ||
self.chain_spec.properties() | ||
} | ||
|
||
fn extensions(&self) -> &dyn GetExtension { | ||
self.chain_spec.extensions() | ||
} | ||
|
||
fn extensions_mut(&mut self) -> &mut dyn GetExtension { | ||
self.chain_spec.extensions_mut() | ||
} | ||
|
||
fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) { | ||
self.chain_spec.add_boot_node(addr) | ||
} | ||
|
||
fn as_json(&self, raw: bool) -> Result<String, String> { | ||
self.chain_spec.as_json(raw) | ||
} | ||
|
||
fn as_storage_builder(&self) -> &dyn BuildStorage { | ||
self.chain_spec.as_storage_builder() | ||
} | ||
|
||
fn cloned_box(&self) -> Box<dyn ChainSpec> { | ||
self.chain_spec.cloned_box() | ||
} | ||
|
||
fn set_storage(&mut self, storage: Storage) { | ||
self.chain_spec.set_storage(storage) | ||
} | ||
|
||
fn code_substitutes(&self) -> BTreeMap<String, Vec<u8>> { | ||
self.chain_spec.code_substitutes() | ||
} | ||
} | ||
|
||
impl<GenesisConfig, Extensions> SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
GenesisConfig: RuntimeGenesis + 'static, | ||
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static, | ||
{ | ||
/// A list of bootnode addresses. | ||
pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] { | ||
self.chain_spec.boot_nodes() | ||
} | ||
|
||
/// Spec name. | ||
pub fn name(&self) -> &str { | ||
self.chain_spec.name() | ||
} | ||
|
||
/// Spec id. | ||
pub fn id(&self) -> &str { | ||
self.chain_spec.id() | ||
} | ||
|
||
/// Telemetry endpoints (if any) | ||
pub fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> { | ||
self.chain_spec.telemetry_endpoints() | ||
} | ||
|
||
/// Network protocol id. | ||
pub fn protocol_id(&self) -> Option<&str> { | ||
self.chain_spec.protocol_id() | ||
} | ||
|
||
/// Optional network fork identifier. | ||
pub fn fork_id(&self) -> Option<&str> { | ||
self.chain_spec.fork_id() | ||
} | ||
|
||
/// Additional loosly-typed properties of the chain. | ||
/// | ||
/// Returns an empty JSON object if 'properties' not defined in config | ||
pub fn properties(&self) -> Properties { | ||
self.chain_spec.properties() | ||
} | ||
|
||
/// Add a bootnode to the list. | ||
pub fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) { | ||
self.chain_spec.add_boot_node(addr) | ||
} | ||
|
||
/// Returns a reference to the defined chain spec extensions. | ||
pub fn extensions(&self) -> &Extensions { | ||
self.chain_spec.extensions() | ||
} | ||
|
||
/// Returns a mutable reference to the defined chain spec extensions. | ||
pub fn extensions_mut(&mut self) -> &mut Extensions { | ||
self.chain_spec.extensions_mut() | ||
} | ||
|
||
/// Create hardcoded spec. | ||
#[allow(clippy::too_many_arguments)] | ||
pub fn from_genesis<F: Fn() -> GenesisConfig + 'static + Send + Sync>( | ||
name: &str, | ||
id: &str, | ||
chain_type: ChainType, | ||
constructor: F, | ||
boot_nodes: Vec<MultiaddrWithPeerId>, | ||
telemetry_endpoints: Option<TelemetryEndpoints>, | ||
protocol_id: Option<&str>, | ||
fork_id: Option<&str>, | ||
properties: Option<Properties>, | ||
extensions: Extensions, | ||
) -> Self { | ||
Self { | ||
chain_spec: GenericChainSpec::from_genesis( | ||
name, | ||
id, | ||
chain_type, | ||
constructor, | ||
boot_nodes, | ||
telemetry_endpoints, | ||
protocol_id, | ||
fork_id, | ||
properties, | ||
extensions, | ||
), | ||
} | ||
} | ||
} | ||
|
||
impl<GenesisConfig, Extensions> SerializableChainSpec<GenesisConfig, Extensions> | ||
where | ||
Extensions: de::DeserializeOwned, | ||
{ | ||
/// Parse json content into a `ChainSpec` | ||
pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> { | ||
GenericChainSpec::from_json_bytes(json).map(|chain_spec| Self { chain_spec }) | ||
} | ||
|
||
/// Parse json file into a `ChainSpec` | ||
pub fn from_json_file(path: PathBuf) -> Result<Self, String> { | ||
GenericChainSpec::from_json_file(path).map(|chain_spec| Self { chain_spec }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.