subcoin_service/
genesis_block_builder.rs

1use sc_client_api::BlockImportOperation;
2use sc_client_api::backend::Backend;
3use sc_executor::RuntimeVersionOf;
4use sc_service::BuildGenesisBlock;
5use sp_core::Encode;
6use sp_core::storage::Storage;
7use sp_runtime::BuildStorage;
8use sp_runtime::traits::{Block as BlockT, HashingFor, Header as HeaderT};
9use std::marker::PhantomData;
10use std::sync::Arc;
11
12/// Subcoin genesis block builder.
13///
14/// The genesis state is handled within the pallet-bitcoin, the genesis block data is generated
15/// from the corresponding Bitcoin genesis block.
16pub struct GenesisBlockBuilder<Block: BlockT, B, E, TransactionAdapter> {
17    network: bitcoin::Network,
18    genesis_storage: Storage,
19    commit_genesis_state: bool,
20    backend: Arc<B>,
21    executor: E,
22    _phantom: PhantomData<(Block, TransactionAdapter)>,
23}
24
25impl<Block: BlockT, B, E: Clone, TransactionAdapter> Clone
26    for GenesisBlockBuilder<Block, B, E, TransactionAdapter>
27{
28    fn clone(&self) -> Self {
29        Self {
30            network: self.network,
31            genesis_storage: self.genesis_storage.clone(),
32            commit_genesis_state: self.commit_genesis_state,
33            backend: self.backend.clone(),
34            executor: self.executor.clone(),
35            _phantom: Default::default(),
36        }
37    }
38}
39
40impl<Block, B, E, TransactionAdapter> GenesisBlockBuilder<Block, B, E, TransactionAdapter>
41where
42    Block: BlockT,
43    B: Backend<Block>,
44    E: RuntimeVersionOf,
45    TransactionAdapter: subcoin_primitives::BitcoinTransactionAdapter<Block>,
46{
47    /// Constructs a new instance of [`GenesisBlockBuilder`].
48    pub fn new(
49        network: bitcoin::Network,
50        build_genesis_storage: &dyn BuildStorage,
51        commit_genesis_state: bool,
52        backend: Arc<B>,
53        executor: E,
54    ) -> sp_blockchain::Result<Self> {
55        let genesis_storage = build_genesis_storage
56            .build_storage()
57            .map_err(sp_blockchain::Error::Storage)?;
58        Ok(Self {
59            network,
60            genesis_storage,
61            commit_genesis_state,
62            backend,
63            executor,
64            _phantom: Default::default(),
65        })
66    }
67}
68
69fn substrate_genesis_block<Block, TransactionAdapter>(
70    network: bitcoin::Network,
71    state_root: Block::Hash,
72) -> Block
73where
74    Block: BlockT,
75    TransactionAdapter: subcoin_primitives::BitcoinTransactionAdapter<Block>,
76{
77    let block = bitcoin::constants::genesis_block(network);
78
79    let extrinsics = block
80        .txdata
81        .clone()
82        .into_iter()
83        .map(TransactionAdapter::bitcoin_transaction_into_extrinsic)
84        .collect::<Vec<_>>();
85
86    let extrinsics_root = frame_system::extrinsics_data_root::<HashingFor<Block>>(
87        extrinsics.iter().map(|xt| xt.encode()).collect(),
88        sp_core::storage::StateVersion::try_from(subcoin_runtime::VERSION.system_version)
89            .expect("Runtime system version config must be valid; qed"),
90    );
91
92    let digest = subcoin_primitives::substrate_header_digest(&block.header);
93
94    let header = <<Block as BlockT>::Header as HeaderT>::new(
95        0u32.into(),
96        extrinsics_root,
97        state_root,
98        Default::default(),
99        digest,
100    );
101
102    Block::new(header, extrinsics)
103}
104
105impl<Block, B, E, TransactionAdapter> BuildGenesisBlock<Block>
106    for GenesisBlockBuilder<Block, B, E, TransactionAdapter>
107where
108    Block: BlockT,
109    B: Backend<Block>,
110    E: RuntimeVersionOf,
111    TransactionAdapter: subcoin_primitives::BitcoinTransactionAdapter<Block>,
112{
113    type BlockImportOperation = <B as Backend<Block>>::BlockImportOperation;
114
115    fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> {
116        let Self {
117            network,
118            genesis_storage,
119            commit_genesis_state,
120            backend,
121            executor,
122            _phantom,
123        } = self;
124
125        let genesis_state_version = sc_service::resolve_state_version_from_wasm::<
126            _,
127            HashingFor<Block>,
128        >(&genesis_storage, &executor)?;
129
130        let mut op = backend.begin_operation()?;
131        let state_root =
132            op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?;
133
134        let genesis_block =
135            substrate_genesis_block::<Block, TransactionAdapter>(network, state_root);
136
137        Ok((genesis_block, op))
138    }
139}