domain_block_builder/
genesis_block_builder.rs

1//! Custom genesis block builder to inject correct genesis block.
2
3use hexlit::hex;
4use sc_chain_spec::{construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock};
5use sc_client_api::{Backend, BlockImportOperation};
6use sc_executor::RuntimeVersionOf;
7use sp_api::ProvideRuntimeApi;
8use sp_blockchain::HeaderBackend;
9use sp_core::storage::Storage;
10use sp_core::H256;
11use sp_domains::{DomainId, DomainsApi};
12use sp_runtime::traits::{Block as BlockT, HashingFor};
13use sp_runtime::BuildStorage;
14use std::marker::PhantomData;
15use std::sync::Arc;
16
17/// Custom genesis block builder to inject correct genesis block for Domains.
18pub struct CustomGenesisBlockBuilder<CClient, CBlock: BlockT, Block: BlockT, B, E> {
19    domain_id: DomainId,
20    consensus_client: Arc<CClient>,
21    genesis_storage: Storage,
22    commit_genesis_state: bool,
23    backend: Arc<B>,
24    executor: E,
25    _data: PhantomData<(CBlock, Block)>,
26}
27
28impl<CClient, CBlock, Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf>
29    CustomGenesisBlockBuilder<CClient, CBlock, Block, B, E>
30where
31    Block: BlockT,
32    B: Backend<Block>,
33    E: RuntimeVersionOf,
34    CBlock: BlockT,
35{
36    /// Constructs a new instance of Genesis block builder
37    pub fn new(
38        domain_id: DomainId,
39        consensus_client: Arc<CClient>,
40        build_genesis_storage: &dyn BuildStorage,
41        commit_genesis_state: bool,
42        backend: Arc<B>,
43        executor: E,
44    ) -> sp_blockchain::Result<Self> {
45        let genesis_storage = build_genesis_storage
46            .build_storage()
47            .map_err(sp_blockchain::Error::Storage)?;
48        Ok(Self {
49            domain_id,
50            consensus_client,
51            genesis_storage,
52            commit_genesis_state,
53            backend,
54            executor,
55            _data: Default::default(),
56        })
57    }
58}
59
60impl<CClient, CBlock, Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf>
61    BuildGenesisBlock<Block> for CustomGenesisBlockBuilder<CClient, CBlock, Block, B, E>
62where
63    Block: BlockT,
64    Block::Hash: From<H256>,
65    B: Backend<Block>,
66    E: RuntimeVersionOf,
67    CBlock: BlockT,
68    CBlock::Hash: From<H256>,
69    CClient: ProvideRuntimeApi<CBlock> + HeaderBackend<CBlock>,
70    CClient::Api: DomainsApi<CBlock, Block::Header>,
71{
72    type BlockImportOperation = <B as Backend<Block>>::BlockImportOperation;
73
74    fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> {
75        let Self {
76            domain_id,
77            consensus_client,
78            genesis_storage,
79            commit_genesis_state,
80            backend,
81            executor,
82            _data,
83        } = self;
84
85        let maybe_expected_state_root = {
86            let runtime_api = consensus_client.runtime_api();
87            let consensus_best_hash = consensus_client.info().best_hash;
88
89            match runtime_api.genesis_state_root(consensus_best_hash, domain_id)? {
90                Some(hash) => Some(hash.into()),
91                None => {
92                    // TODO: remove this once the taurus runtime is upgraded
93                    // if network is taurus, then we may not have it on runtime before runtime is
94                    // upgraded, so instead return the known domain-0's state root.
95                    if consensus_client.info().genesis_hash
96                        == H256::from(hex!(
97                            "0x295aeafca762a304d92ee1505548695091f6082d3f0aa4d092ac3cd6397a6c5e"
98                        ))
99                        .into()
100                        && domain_id == DomainId::new(0)
101                    {
102                        Some(
103                            H256::from(hex!(
104                            "0x530eae1878202aa0ab5997eadf2b7245ee78f44a35ab25ff84151fab489aa334"
105                        ))
106                            .into(),
107                        )
108                    } else {
109                        None
110                    }
111                }
112            }
113        };
114
115        let genesis_state_version =
116            resolve_state_version_from_wasm::<_, HashingFor<Block>>(&genesis_storage, &executor)?;
117        let mut op = backend.begin_operation()?;
118        let state_root =
119            op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?;
120
121        let genesis_block = if let Some(expected_state_root) = maybe_expected_state_root
122            && expected_state_root != state_root
123        {
124            construct_genesis_block::<Block>(expected_state_root, genesis_state_version)
125        } else {
126            construct_genesis_block::<Block>(state_root, genesis_state_version)
127        };
128
129        Ok((genesis_block, op))
130    }
131}