1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// This file is part of Substrate.

// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// 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/>.

//! Substrate chain configurations.
//!
//! This crate contains structs and utilities to declare
//! a runtime-specific configuration file (a.k.a chain spec).
//!
//! Basic chain spec type containing all required parameters is
//! [`GenericChainSpec`]. It can be extended with
//! additional options that contain configuration specific to your chain.
//! Usually the extension is going to be an amalgamate of types exposed
//! by Substrate core modules. To allow the core modules to retrieve
//! their configuration from your extension you should use `ChainSpecExtension`
//! macro exposed by this crate.
//!
//! ```rust
//! use std::collections::HashMap;
//! use sc_chain_spec::{GenericChainSpec, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
//! pub struct MyExtension {
//! 		pub known_blocks: HashMap<u64, String>,
//! }
//!
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
//! ```
//!
//! Some parameters may require different values depending on the
//! current blockchain height (a.k.a. forks). You can use `ChainSpecGroup`
//! macro and provided [`Forks`](./struct.Forks.html) structure to put
//! such parameters to your chain spec.
//! This will allow to override a single parameter starting at specific
//! block number.
//!
//! ```rust
//! use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec};
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
//! pub struct ClientParams {
//! 	max_block_size: usize,
//! 	max_extrinsic_size: usize,
//! }
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
//! pub struct PoolParams {
//! 	max_transaction_size: usize,
//! }
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
//! pub struct Extension {
//! 	pub client: ClientParams,
//! 	pub pool: PoolParams,
//! }
//!
//! pub type BlockNumber = u64;
//!
//! /// A chain spec supporting forkable `ClientParams`.
//! pub type MyChainSpec1<G> = GenericChainSpec<G, Forks<BlockNumber, ClientParams>>;
//!
//! /// A chain spec supporting forkable `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
//! with block numbers (i.e. is forkable), and another set that is not subject to changes.
//! This is also possible by declaring an extension that contains `Forks` within it.
//!
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct ClientParams {
//! 	max_block_size: usize,
//! 	max_extrinsic_size: usize,
//! }
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
//! pub struct PoolParams {
//! 	max_transaction_size: usize,
//! }
//!
//! #[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
//! pub struct Extension {
//! 	pub client: ClientParams,
//! 	#[forks]
//! 	pub pool: Forks<u64, PoolParams>,
//! }
//!
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
//! ```
//!
//! # Substrate chain specification format
//!
//! The Substrate chain specification is a `json` file that describes the basics of a chain. Most
//! importantly it lays out the genesis storage which leads to the genesis hash. The default
//! Substrate chain specification format is the following:
//!
//! ```json
//! // The human readable name of the chain.
//! "name": "Flaming Fir",
//! // The id of the chain.
//! "id": "flamingfir9",
//! // The chain type of this chain.
//! // Possible values are `Live`, `Development`, `Local`.
//! "chainType": "Live",
//! // A list of multi addresses that belong to boot nodes of the chain.
//! "bootNodes": [
//!   "/dns/0.flamingfir.paritytech.net/tcp/30333/p2p/12D3KooWLK2gMLhWsYJzjW3q35zAs9FDDVqfqVfVuskiGZGRSMvR",
//! ],
//! // Optional list of "multi address, verbosity" of telemetry endpoints.
//! // The verbosity goes from `0` to `9`. With `0` being the mode with the lowest verbosity.
//! "telemetryEndpoints": [
//!   [
//!     "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F",
//!     0
//!   ]
//! ],
//! // Optional networking protocol id that identifies the chain.
//! "protocolId": "fir9",
//! // Optional fork id. Should most likely be left empty.
//! // Can be used to signal a fork on the network level when two chains have the
//! // same genesis hash.
//! "forkId": "random_fork",
//! // Custom properties.
//! "properties": {
//!   "tokenDecimals": 15,
//!   "tokenSymbol": "FIR"
//! },
//! // Deprecated field. Should be ignored.
//! "consensusEngine": null,
//! // The genesis declaration of the chain.
//! //
//! // `runtime`, `raw`, `stateRootHash` denote the type of the genesis declaration.
//! //
//! // These declarations are in the following formats:
//! // - `runtime` is a `json` object that can be parsed by a compatible `GenesisConfig`. This
//! //  `GenesisConfig` is declared by a runtime and opaque to the node.
//! // - `raw` is a `json` object with two fields `top` and `children_default`. Each of these
//! //   fields is a map of `key => value`. These key/value pairs represent the genesis storage.
//! // - `stateRootHash` is a single hex encoded hash that represents the genesis hash. The hash
//! //   type depends on the hash used by the chain.
//! //
//! "genesis": { "runtime": {} },
//! /// Optional map of `block_number` to `wasm_code`.
//! ///
//! /// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the
//! /// given block number until the `spec_version` on-chain changes. The given `wasm_code` should
//! /// be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug
//! /// that can not be fixed with a runtime upgrade, if for example the runtime is constantly
//! /// panicking. Introducing new runtime apis isn't supported, because the node
//! /// will read the runtime version from the on-chain wasm code. Use this functionality only when
//! /// there is no other way around it and only patch the problematic bug, the rest should be done
//! /// with a on-chain runtime upgrade.
//! "codeSubstitutes": [],
//! ```
//!
//! The chain spec can be extended with other fields that are opaque to the default chain spec.
//! Specific node implementations will need to be able to deserialize these extensions.

mod chain_spec;
mod extension;

pub use chain_spec::{ChainSpec as GenericChainSpec, NoExtension};
pub use extension::{
	get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group,
};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};

use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints;
use serde::{de::DeserializeOwned, Serialize};
use sp_core::storage::Storage;
use sp_runtime::BuildStorage;

/// The type of a chain.
///
/// This can be used by tools to determine the type of a chain for displaying
/// additional information or enabling additional features.
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
pub enum ChainType {
	/// A development chain that runs mainly on one node.
	Development,
	/// A local chain that runs locally on multiple nodes for testing purposes.
	Local,
	/// A live chain.
	Live,
	/// Some custom chain type.
	Custom(String),
}

impl Default for ChainType {
	fn default() -> Self {
		Self::Live
	}
}

/// Arbitrary properties defined in chain spec as a JSON object
pub type Properties = serde_json::map::Map<String, serde_json::Value>;

/// 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 of a chain specification.
pub trait ChainSpec: BuildStorage + Send + Sync {
	/// Spec name.
	fn name(&self) -> &str;
	/// Spec id.
	fn id(&self) -> &str;
	/// Type of the chain.
	fn chain_type(&self) -> ChainType;
	/// A list of bootnode addresses.
	fn boot_nodes(&self) -> &[MultiaddrWithPeerId];
	/// Telemetry endpoints (if any)
	fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>;
	/// Network protocol id.
	fn protocol_id(&self) -> Option<&str>;
	/// Optional network fork identifier. `None` by default.
	fn fork_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 the defined chain spec extensions.
	fn extensions(&self) -> &dyn GetExtension;
	/// Returns a mutable reference to the defined chain spec extensions.
	fn extensions_mut(&mut self) -> &mut dyn GetExtension;
	/// Add a bootnode to the list.
	fn add_boot_node(&mut self, addr: MultiaddrWithPeerId);
	/// 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;
	/// Returns a cloned `Box<dyn ChainSpec>`.
	fn cloned_box(&self) -> Box<dyn ChainSpec>;
	/// Set the storage that should be used by this chain spec.
	///
	/// This will be used as storage at genesis.
	fn set_storage(&mut self, storage: Storage);
	/// Returns code substitutes that should be used for the on chain wasm.
	fn code_substitutes(&self) -> std::collections::BTreeMap<String, Vec<u8>>;
}

impl std::fmt::Debug for dyn ChainSpec {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		write!(f, "ChainSpec(name = {:?}, id = {:?})", self.name(), self.id())
	}
}