Skip to content

Commit 005c2a2

Browse files
authored
Merge pull request #532 from subspace/sc-subspace-chain-specs
Introduce `sc-subspace-chain-specs` crate
2 parents e28a77e + 4f03bc3 commit 005c2a2

File tree

12 files changed

+388
-313
lines changed

12 files changed

+388
-313
lines changed

.github/workflows/rust.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ env:
1515
CARGO_INCREMENTAL: 0
1616
CARGO_TERM_COLOR: always
1717
# Build smaller artifacts to avoid running out of space in CI
18-
RUSTFLAGS: -C strip=debuginfo -C opt-level=s
18+
# TODO: Try to remove once https://github.com/paritytech/substrate/issues/11538 is resolved
19+
RUSTFLAGS: -C strip=symbols -C opt-level=s
1920

2021
jobs:
2122
cargo-fmt:

Cargo.lock

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "sc-subspace-chain-specs"
3+
description = "Chain specification data structures tailored for Subspace"
4+
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
5+
version = "0.1.0"
6+
authors = ["Nazar Mokrynskyi <[email protected]>"]
7+
edition = "2021"
8+
include = [
9+
"/src",
10+
"/Cargo.toml",
11+
"/README.md",
12+
]
13+
14+
[dependencies]
15+
sc-chain-spec = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
16+
sc-service = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd", features = ["wasmtime"] }
17+
sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
18+
serde = "1.0.137"
19+
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
20+
sp-runtime = { version = "6.0.0", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (C) 2021 Subspace Labs, Inc.
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
//! Chain specification data structures tailored for Subspace.
18+
19+
mod utils;
20+
21+
use crate::utils::SerializableChainSpec;
22+
use sc_chain_spec::{ChainSpecExtension, RuntimeGenesis};
23+
use serde::{Deserialize, Serialize};
24+
25+
/// The extensions for the [`ConsensusChainSpec`].
26+
#[derive(Serialize, Deserialize, ChainSpecExtension)]
27+
#[serde(deny_unknown_fields, rename_all = "camelCase")]
28+
#[serde(bound = "")]
29+
pub struct ChainSpecExtensions<ExecutionGenesisConfig>
30+
where
31+
ExecutionGenesisConfig: RuntimeGenesis + 'static,
32+
{
33+
/// Chain spec of execution chain.
34+
pub execution_chain_spec: ExecutionChainSpec<ExecutionGenesisConfig>,
35+
}
36+
37+
impl<ExecutionGenesisConfig> Clone for ChainSpecExtensions<ExecutionGenesisConfig>
38+
where
39+
ExecutionGenesisConfig: RuntimeGenesis + 'static,
40+
{
41+
fn clone(&self) -> Self {
42+
Self {
43+
execution_chain_spec: self.execution_chain_spec.clone(),
44+
}
45+
}
46+
}
47+
48+
/// Specialized `ChainSpec` for the consensus runtime.
49+
pub type ConsensusChainSpec<GenesisConfig, ExecutionGenesisConfig> =
50+
SerializableChainSpec<GenesisConfig, ChainSpecExtensions<ExecutionGenesisConfig>>;
51+
52+
/// Specialized `ChainSpec` for the execution runtime.
53+
pub type ExecutionChainSpec<ExecutionGenesisConfig> = SerializableChainSpec<ExecutionGenesisConfig>;
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
use sc_chain_spec::{
2+
ChainSpec, ChainType, GenericChainSpec, GetExtension, NoExtension, RuntimeGenesis,
3+
};
4+
use sc_service::config::MultiaddrWithPeerId;
5+
use sc_service::Properties;
6+
use sc_telemetry::TelemetryEndpoints;
7+
use serde::de::Visitor;
8+
use serde::ser::Error as _;
9+
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
10+
use sp_core::storage::Storage;
11+
use sp_runtime::BuildStorage;
12+
use std::borrow::Cow;
13+
use std::collections::BTreeMap;
14+
use std::fmt;
15+
use std::marker::PhantomData;
16+
use std::path::PathBuf;
17+
18+
pub struct SerializableChainSpec<GenesisConfig, Extensions = NoExtension> {
19+
chain_spec: GenericChainSpec<GenesisConfig, Extensions>,
20+
}
21+
22+
impl<GenesisConfig, Extensions> Clone for SerializableChainSpec<GenesisConfig, Extensions>
23+
where
24+
Extensions: Clone,
25+
{
26+
fn clone(&self) -> Self {
27+
Self {
28+
chain_spec: self.chain_spec.clone(),
29+
}
30+
}
31+
}
32+
33+
impl<GenesisConfig, Extensions> Serialize for SerializableChainSpec<GenesisConfig, Extensions>
34+
where
35+
GenesisConfig: RuntimeGenesis + 'static,
36+
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static,
37+
{
38+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39+
where
40+
S: Serializer,
41+
{
42+
serializer.serialize_str(&self.as_json(true).map_err(S::Error::custom)?)
43+
}
44+
}
45+
46+
impl<'de, GenesisConfig, Extensions> Deserialize<'de>
47+
for SerializableChainSpec<GenesisConfig, Extensions>
48+
where
49+
Extensions: de::DeserializeOwned,
50+
{
51+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
52+
where
53+
D: Deserializer<'de>,
54+
{
55+
struct StringVisitor<GenesisConfig, Extensions> {
56+
_phantom_data: PhantomData<(GenesisConfig, Extensions)>,
57+
}
58+
59+
impl<'de, GenesisConfig, Extensions> Visitor<'de> for StringVisitor<GenesisConfig, Extensions>
60+
where
61+
Extensions: de::DeserializeOwned,
62+
{
63+
type Value = SerializableChainSpec<GenesisConfig, Extensions>;
64+
65+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
66+
formatter.write_str("ExecutionChainSpec")
67+
}
68+
69+
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
70+
where
71+
E: de::Error,
72+
{
73+
self.visit_string(value.to_string())
74+
}
75+
76+
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
77+
where
78+
E: de::Error,
79+
{
80+
Self::Value::from_json_bytes(value.into_bytes()).map_err(E::custom)
81+
}
82+
}
83+
deserializer.deserialize_string(StringVisitor {
84+
_phantom_data: PhantomData::default(),
85+
})
86+
}
87+
}
88+
89+
impl<GenesisConfig, Extensions> BuildStorage for SerializableChainSpec<GenesisConfig, Extensions>
90+
where
91+
GenesisConfig: RuntimeGenesis,
92+
{
93+
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
94+
self.chain_spec.assimilate_storage(storage)
95+
}
96+
}
97+
98+
impl<GenesisConfig, Extensions> ChainSpec for SerializableChainSpec<GenesisConfig, Extensions>
99+
where
100+
GenesisConfig: RuntimeGenesis + 'static,
101+
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static,
102+
{
103+
fn name(&self) -> &str {
104+
self.chain_spec.name()
105+
}
106+
107+
fn id(&self) -> &str {
108+
self.chain_spec.id()
109+
}
110+
111+
fn chain_type(&self) -> ChainType {
112+
ChainSpec::chain_type(&self.chain_spec)
113+
}
114+
115+
fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
116+
self.chain_spec.boot_nodes()
117+
}
118+
119+
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> {
120+
self.chain_spec.telemetry_endpoints()
121+
}
122+
123+
fn protocol_id(&self) -> Option<&str> {
124+
self.chain_spec.protocol_id()
125+
}
126+
127+
fn fork_id(&self) -> Option<&str> {
128+
self.chain_spec.fork_id()
129+
}
130+
131+
fn properties(&self) -> Properties {
132+
self.chain_spec.properties()
133+
}
134+
135+
fn extensions(&self) -> &dyn GetExtension {
136+
self.chain_spec.extensions()
137+
}
138+
139+
fn extensions_mut(&mut self) -> &mut dyn GetExtension {
140+
self.chain_spec.extensions_mut()
141+
}
142+
143+
fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) {
144+
self.chain_spec.add_boot_node(addr)
145+
}
146+
147+
fn as_json(&self, raw: bool) -> Result<String, String> {
148+
self.chain_spec.as_json(raw)
149+
}
150+
151+
fn as_storage_builder(&self) -> &dyn BuildStorage {
152+
self.chain_spec.as_storage_builder()
153+
}
154+
155+
fn cloned_box(&self) -> Box<dyn ChainSpec> {
156+
self.chain_spec.cloned_box()
157+
}
158+
159+
fn set_storage(&mut self, storage: Storage) {
160+
self.chain_spec.set_storage(storage)
161+
}
162+
163+
fn code_substitutes(&self) -> BTreeMap<String, Vec<u8>> {
164+
self.chain_spec.code_substitutes()
165+
}
166+
}
167+
168+
impl<GenesisConfig, Extensions> SerializableChainSpec<GenesisConfig, Extensions>
169+
where
170+
GenesisConfig: RuntimeGenesis + 'static,
171+
Extensions: GetExtension + Serialize + Clone + Send + Sync + 'static,
172+
{
173+
/// A list of bootnode addresses.
174+
pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
175+
self.chain_spec.boot_nodes()
176+
}
177+
178+
/// Spec name.
179+
pub fn name(&self) -> &str {
180+
self.chain_spec.name()
181+
}
182+
183+
/// Spec id.
184+
pub fn id(&self) -> &str {
185+
self.chain_spec.id()
186+
}
187+
188+
/// Telemetry endpoints (if any)
189+
pub fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints> {
190+
self.chain_spec.telemetry_endpoints()
191+
}
192+
193+
/// Network protocol id.
194+
pub fn protocol_id(&self) -> Option<&str> {
195+
self.chain_spec.protocol_id()
196+
}
197+
198+
/// Optional network fork identifier.
199+
pub fn fork_id(&self) -> Option<&str> {
200+
self.chain_spec.fork_id()
201+
}
202+
203+
/// Additional loosly-typed properties of the chain.
204+
///
205+
/// Returns an empty JSON object if 'properties' not defined in config
206+
pub fn properties(&self) -> Properties {
207+
self.chain_spec.properties()
208+
}
209+
210+
/// Add a bootnode to the list.
211+
pub fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) {
212+
self.chain_spec.add_boot_node(addr)
213+
}
214+
215+
/// Returns a reference to the defined chain spec extensions.
216+
pub fn extensions(&self) -> &Extensions {
217+
self.chain_spec.extensions()
218+
}
219+
220+
/// Returns a mutable reference to the defined chain spec extensions.
221+
pub fn extensions_mut(&mut self) -> &mut Extensions {
222+
self.chain_spec.extensions_mut()
223+
}
224+
225+
/// Create hardcoded spec.
226+
#[allow(clippy::too_many_arguments)]
227+
pub fn from_genesis<F: Fn() -> GenesisConfig + 'static + Send + Sync>(
228+
name: &str,
229+
id: &str,
230+
chain_type: ChainType,
231+
constructor: F,
232+
boot_nodes: Vec<MultiaddrWithPeerId>,
233+
telemetry_endpoints: Option<TelemetryEndpoints>,
234+
protocol_id: Option<&str>,
235+
fork_id: Option<&str>,
236+
properties: Option<Properties>,
237+
extensions: Extensions,
238+
) -> Self {
239+
Self {
240+
chain_spec: GenericChainSpec::from_genesis(
241+
name,
242+
id,
243+
chain_type,
244+
constructor,
245+
boot_nodes,
246+
telemetry_endpoints,
247+
protocol_id,
248+
fork_id,
249+
properties,
250+
extensions,
251+
),
252+
}
253+
}
254+
}
255+
256+
impl<GenesisConfig, Extensions> SerializableChainSpec<GenesisConfig, Extensions>
257+
where
258+
Extensions: de::DeserializeOwned,
259+
{
260+
/// Parse json content into a `ChainSpec`
261+
pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> {
262+
GenericChainSpec::from_json_bytes(json).map(|chain_spec| Self { chain_spec })
263+
}
264+
265+
/// Parse json file into a `ChainSpec`
266+
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
267+
GenericChainSpec::from_json_file(path).map(|chain_spec| Self { chain_spec })
268+
}
269+
}

crates/subspace-node/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ frame-support = { version = "4.0.0-dev", git = "https://github.com/paritytech/su
2929
futures = "0.3.21"
3030
log = "0.4.17"
3131
parity-scale-codec = "3.1.2"
32-
sc-chain-spec = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
3332
sc-cli = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd", features = ["wasmtime"] }
3433
sc-client-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
3534
sc-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }
35+
sc-subspace-chain-specs = { version = "0.1.0", path = "../sc-subspace-chain-specs" }
3636
sc-executor = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd", features = ["wasmtime"] }
3737
sc-service = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd", features = ["wasmtime"] }
3838
sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", rev = "24bea4c3cba7479e2cf2976a21e8111dfda6b1cd" }

0 commit comments

Comments
 (0)