referrerpolicy=no-referrer-when-downgrade

sc_chain_spec/
genesis_block.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Tool for creating the genesis block.
20
21use std::{marker::PhantomData, sync::Arc};
22
23use codec::Encode;
24use sc_client_api::{backend::Backend, BlockImportOperation};
25use sc_executor::RuntimeVersionOf;
26use sp_core::storage::{well_known_keys, StateVersion, Storage};
27use sp_runtime::{
28	traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero},
29	BuildStorage,
30};
31
32/// Return the state version given the genesis storage and executor.
33pub fn resolve_state_version_from_wasm<E, H>(
34	storage: &Storage,
35	executor: &E,
36) -> sp_blockchain::Result<StateVersion>
37where
38	E: RuntimeVersionOf,
39	H: HashT,
40{
41	if let Some(wasm) = storage.top.get(well_known_keys::CODE) {
42		let mut ext = sp_state_machine::BasicExternalities::new_empty(); // just to read runtime version.
43
44		let code_fetcher = sp_core::traits::WrappedRuntimeCode(wasm.as_slice().into());
45		let runtime_code = sp_core::traits::RuntimeCode {
46			code_fetcher: &code_fetcher,
47			heap_pages: None,
48			hash: <H as HashT>::hash(wasm).encode(),
49		};
50		let runtime_version = RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code)
51			.map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()))?;
52		Ok(runtime_version.state_version())
53	} else {
54		Err(sp_blockchain::Error::VersionInvalid(
55			"Runtime missing from initial storage, could not read state version.".to_string(),
56		))
57	}
58}
59
60/// Create a genesis block, given the initial storage.
61pub fn construct_genesis_block<Block: BlockT>(
62	state_root: Block::Hash,
63	state_version: StateVersion,
64) -> Block {
65	let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
66		Vec::new(),
67		state_version,
68	);
69
70	Block::new(
71		<<Block as BlockT>::Header as HeaderT>::new(
72			Zero::zero(),
73			extrinsics_root,
74			state_root,
75			Default::default(),
76			Default::default(),
77		),
78		Default::default(),
79	)
80}
81
82/// Trait for building the genesis block.
83pub trait BuildGenesisBlock<Block: BlockT> {
84	/// The import operation used to import the genesis block into the backend.
85	type BlockImportOperation;
86
87	/// Returns the built genesis block along with the block import operation
88	/// after setting the genesis storage.
89	fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)>;
90}
91
92/// Default genesis block builder in Substrate.
93pub struct GenesisBlockBuilder<Block: BlockT, B, E> {
94	genesis_storage: Storage,
95	commit_genesis_state: bool,
96	backend: Arc<B>,
97	executor: E,
98	_phantom: PhantomData<Block>,
99}
100
101impl<Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf> GenesisBlockBuilder<Block, B, E> {
102	/// Constructs a new instance of [`GenesisBlockBuilder`].
103	pub fn new(
104		build_genesis_storage: &dyn BuildStorage,
105		commit_genesis_state: bool,
106		backend: Arc<B>,
107		executor: E,
108	) -> sp_blockchain::Result<Self> {
109		let genesis_storage =
110			build_genesis_storage.build_storage().map_err(sp_blockchain::Error::Storage)?;
111		Self::new_with_storage(genesis_storage, commit_genesis_state, backend, executor)
112	}
113
114	/// Constructs a new instance of [`GenesisBlockBuilder`] using provided storage.
115	pub fn new_with_storage(
116		genesis_storage: Storage,
117		commit_genesis_state: bool,
118		backend: Arc<B>,
119		executor: E,
120	) -> sp_blockchain::Result<Self> {
121		Ok(Self {
122			genesis_storage,
123			commit_genesis_state,
124			backend,
125			executor,
126			_phantom: PhantomData::<Block>,
127		})
128	}
129}
130
131impl<Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf> BuildGenesisBlock<Block>
132	for GenesisBlockBuilder<Block, B, E>
133{
134	type BlockImportOperation = <B as Backend<Block>>::BlockImportOperation;
135
136	fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> {
137		let Self { genesis_storage, commit_genesis_state, backend, executor, _phantom } = self;
138
139		let genesis_state_version =
140			resolve_state_version_from_wasm::<_, HashingFor<Block>>(&genesis_storage, &executor)?;
141		let mut op = backend.begin_operation()?;
142		let state_root =
143			op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?;
144		let genesis_block = construct_genesis_block::<Block>(state_root, genesis_state_version);
145
146		Ok((genesis_block, op))
147	}
148}