sc_chain_spec/
lib.rs

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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
// This file is part of Substrate.

// Copyright (C) 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/>.

//! This crate includes structs and utilities for defining configuration files (known as chain
//! specification) for both runtime and node.
//!
//! # Intro: Chain Specification
//!
//! The chain specification comprises parameters and settings that define the properties and an
//! initial state of a chain. Users typically interact with the JSON representation of the chain
//! spec. Internally, the chain spec is embodied by the [`GenericChainSpec`] struct, and specific
//! properties can be accessed using the [`ChainSpec`] trait.
//!
//! In summary, although not restricted to, the primary role of the chain spec is to provide a list
//! of well-known boot nodes for the blockchain network and the means for initializing the genesis
//! storage. This initialization is necessary for creating a genesis block upon which subsequent
//! blocks are built. When the node is launched for the first time, it reads the chain spec,
//! initializes the genesis block, and establishes connections with the boot nodes.
//!
//! The JSON chain spec is divided into two main logical sections:
//! - one section details general chain properties,
//! - second explicitly or indirectly defines the genesis storage, which, in turn, determines the
//!   genesis hash of the chain,
//!
//! The chain specification consists of the following fields:
//!
//! <table>
//!   <thead>
//!     <tr>
//!       <th>Chain spec key</th>
//!       <th>Description</th>
//!     </tr>
//!   </thead>
//!   <tbody>
//!     <tr>
//!       <td>name</td>
//!       <td>The human readable name of the chain.</td>
//!     </tr>
//!     <tr>
//!       <td>id</td>
//!       <td>The id of the chain.</td>
//!     </tr>
//!     <tr>
//!       <td>chainType</td>
//!       <td>The chain type of this chain
//!           (refer to
//!            <a href="enum.ChainType.html" title="enum sc_chain_spec::ChainType">
//!              <code>ChainType</code>
//!            </a>).
//!       </td>
//!     </tr>
//!     <tr>
//!       <td>bootNodes</td>
//!       <td>A list of
//!       <a href="https://github.com/multiformats/multiaddr">multi addresses</a>
//!       that belong to boot nodes of the chain.</td>
//!     </tr>
//!     <tr>
//!       <td>telemetryEndpoints</td>
//!       <td>Optional list of <code>multi address, verbosity</code> of telemetry endpoints. The
//! verbosity goes from 0 to 9. With 0 being the mode with the lowest verbosity.</td>
//!     </tr>
//!     <tr>
//!       <td>protocolId</td>
//!       <td>Optional networking protocol id that identifies the chain.</td>
//!     </tr>
//!     <tr>
//!       <td>forkId</td>
//!       <td>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.</td>
//!     </tr>
//!     <tr>
//!       <td>properties</td>
//!       <td>Custom properties. Shall be provided in the form of
//! <code>key</code>-<code>value</code> json object.
//!     </td>
//!     </tr>
//!     <tr>
//!       <td>consensusEngine</td>
//!       <td>Deprecated field. Should be ignored.</td>
//!     </tr>
//!     <tr>
//!       <td>codeSubstitutes</td>
//!       <td>Optional map of <code>block_number</code> to <code>wasm_code</code>. More details in
//! material to follow.</td>
//!     </tr>
//!     <tr>
//!       <td>genesis</td>
//!       <td>Defines the initial state of the runtime. More details in material to follow.</td>
//!     </tr>
//!   </tbody>
//! </table>
//!
//! # `genesis`: Initial Runtime State
//!
//! All nodes in the network must build subsequent blocks upon exactly the same genesis block.
//!
//! The information configured in the `genesis` section of a chain specification is used to build
//! the genesis storage, which is essential for creating the genesis block, since the block header
//! includes the storage root hash.
//!
//! The `genesis` key of the chain specification definition describes the
//! initial state of the runtime. For example, it may contain:
//! - an initial list of funded accounts,
//! - the administrative account that controls the sudo key,
//! - an initial authorities set for consensus, etc.
//!
//! As the compiled WASM blob of the runtime code is stored in the chain's state, the initial
//! runtime must also be provided within the chain specification.
//!
//! # `chain-spec` formats
//!
//! In essence, the most important formats of genesis initial state in chain specification files
//! are:
//!
//! <table>
//!   <thead>
//!     <tr>
//!       <th>Format</th>
//!       <th>Description</th>
//!     </tr>
//!   </thead>
//!   <tbody>
//!     <tr>
//!       <td>
//! 		<code>full config</code>
//!       </td>
//!       <td>A JSON object that provides an explicit and comprehensive representation of the
//! <code>RuntimeGenesisConfig</code> struct, which is generated by <a
//! href="../frame_support_procedural/macro.construct_runtime.html"
//! ><code>polkadot_sdk_frame::runtime::prelude::construct_runtime</code></a> macro (<a
//! href="../substrate_test_runtime/struct.RuntimeGenesisConfig.html#"
//! >example of generated struct</a>). Must contain *all* the keys of
//! the genesis config, no defaults will be used.
//!
//! This format explicitly provides the code of the runtime.
//! </td></tr>
//!     <tr>
//!       <td>
//! 		<code>patch</code>
//!       </td>
//!       <td>A JSON object that offers a partial representation of the
//!       <code>RuntimeGenesisConfig</code> provided by the runtime. It contains a patch, which is
//! essentially a list of key-value pairs to customize in the default runtime's
//! <code>RuntimeGenesisConfig</code>: `full = default + patch`. Please note that `default`
//! `RuntimeGenesisConfig` may not be functional.
//! This format explicitly provides the code of the runtime.
//! </td></tr>
//!     <tr>
//!       <td>
//! 		<code>raw</code>
//!       </td>
//!       <td>A JSON object with two fields: <code>top</code> and <code>children_default</code>.
//! Each field is a map of <code>key => value</code> pairs representing entries in a genesis storage
//! trie. The runtime code is one of such entries.</td>
//!     </tr>
//!   </tbody>
//! </table>
//!
//! The main purpose of the `RuntimeGenesisConfig` patch is to:
//! - minimize the maintenance effort when RuntimeGenesisConfig is changed in the future (e.g. new
//!   pallets added to the runtime or pallet's genesis config changed),
//! - increase the readability - it only contains the relevant fields,
//! - allow to apply numerous changes in distinct domains (e.g. for zombienet).
//!
//! For production or long-lasting blockchains, using the `raw` format in the chain specification is
//! recommended. Only the `raw` format guarantees that storage root hash will remain unchanged when
//! the `RuntimeGenesisConfig` format changes due to software upgrade.
//!
//! JSON examples in the [following section](#json-chain-specification-example) illustrate the `raw`
//! `patch` and full genesis fields.
//!
//! # From Initial State to Raw Genesis.
//!
//! To generate a raw genesis storage from the JSON representation of the runtime genesis config,
//! the node needs to interact with the runtime.
//!
//! This interaction involves passing the runtime genesis config JSON blob to the runtime using the
//! [`sp_genesis_builder::GenesisBuilder::build_state`] function. During this operation, the
//! runtime converts the JSON representation of the genesis config into [`sp_io::storage`] items. It
//! is a crucial step for computing the storage root hash, which is a key component in determining
//! the genesis hash.
//!
//! Consequently, the runtime must support the [`sp_genesis_builder::GenesisBuilder`] API to
//! utilize either `patch` or `full` formats.
//!
//! This entire process is encapsulated within the implementation of the [`BuildStorage`] trait,
//! which can be accessed through the [`ChainSpec::as_storage_builder`] method. There is an
//! intermediate internal helper that facilitates this interaction,
//! [`GenesisConfigBuilderRuntimeCaller`], which serves as a straightforward wrapper for
//! [`sc_executor::WasmExecutor`].
//!
//! In case of `raw` genesis state the node does not interact with the runtime regarding the
//! computation of initial state.
//!
//! The plain and `raw` chain specification JSON blobs can be found in
//! [JSON examples](#json-chain-specification-example) section.
//!
//! # Optional Code Mapping
//!
//! 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 cannot 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 an on-chain runtime upgrade.
//!
//! # Building a Chain Specification
//!
//! The [`ChainSpecBuilder`] should be used to create an instance of a chain specification. Its API
//! allows configuration of all fields of the chain spec. To generate a JSON representation of the
//! specification, use [`ChainSpec::as_json`].
//!
//! The sample code to generate a chain spec is as follows:
#![doc = docify::embed!("src/chain_spec.rs", build_chain_spec_with_patch_works)]
//! # JSON chain specification example
//!
//! The following are the plain and `raw` versions of the chain specification JSON files, resulting
//! from executing of the above [example](#building-a-chain-specification):
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_patch.json")]
//! ```
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_patch_raw.json")]
//! ```
//! The following example shows the plain full config version of chain spec:
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_config.json")]
//! ```
//! The [`ChainSpec`] trait represents the API to access values defined in the JSON chain specification.
//!
//!
//! # Custom Chain Spec Extensions
//!
//! The basic chain spec type containing all required parameters is [`GenericChainSpec`]. It can be
//! extended with additional options containing configuration specific to your chain. Usually, the
//! extension will be a combination 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 = GenericChainSpec<MyExtension>;
//! ```
//! Some parameters may require different values depending on the current blockchain height (a.k.a.
//! forks). You can use the [`ChainSpecGroup`](macro@ChainSpecGroup) macro and the provided [`Forks`]
//! structure to add such parameters to your chain spec. This will allow overriding a single
//! parameter starting at a 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 = GenericChainSpec<Forks<BlockNumber, ClientParams>>;
//!
//! /// A chain spec supporting forkable `Extension`.
//! pub type MyChainSpec2 = GenericChainSpec<Forks<BlockNumber, Extension>>;
//! ```
//! It's also possible to have a set of parameters that are allowed to change with block numbers
//! (i.e., they are forkable), and another set that is not subject to changes. This can also be
//! achieved 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 = GenericChainSpec<Extension>;
//! ```
//! 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;
mod genesis_block;
mod genesis_config_builder;
pub mod json_patch;

pub use self::{
	chain_spec::{
		set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec,
		ChainSpec as GenericChainSpec, ChainSpecBuilder, NoExtension,
	},
	extension::{get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group},
	genesis_block::{
		construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock,
		GenesisBlockBuilder,
	},
	genesis_config_builder::{
		GenesisConfigBuilderRuntimeCaller, DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET,
	},
	json_patch::merge as json_merge,
};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};

use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints;
use sp_core::storage::Storage;
use sp_runtime::BuildStorage;

/// The type of chain.
///
/// This can be used by tools to determine the type of chain for displaying
/// additional information or enabling additional features.
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
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.
	#[cfg_attr(feature = "clap", clap(skip))]
	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>;

/// 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 loosely-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())
	}
}