1
// Copyright 2024 Moonbeam foundation
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use crate::lazy_loading;
18
use crate::lazy_loading::backend::RPC;
19
use cumulus_primitives_core::BlockT;
20
use parity_scale_codec::Encode;
21
use sc_client_api::{Backend, BlockImportOperation, NewBlockState};
22
use sp_core::{twox_128, twox_64, H256};
23
use sp_runtime::traits::{Header, One};
24
use sp_runtime::Saturating;
25
use sp_storage::{StateVersion, Storage, StorageKey};
26
use std::sync::Arc;
27

            
28
pub fn produce_genesis_block<TBl: BlockT + sp_runtime::DeserializeOwned>(
29
	backend: Arc<lazy_loading::backend::Backend<TBl>>,
30
) -> sp_blockchain::Result<()> {
31
	let mut op = backend.begin_operation()?;
32
	op.before_fork = true;
33

            
34
	let genesis_block_hash: TBl::Hash = backend
35
		.rpc_client
36
		.block_hash::<TBl>(Some(0))
37
		.unwrap()
38
		.expect("Not able to obtain genesis block hash");
39

            
40
	let genesis_block = backend
41
		.rpc_client
42
		.block::<TBl, _>(Some(genesis_block_hash))
43
		.unwrap()
44
		.unwrap()
45
		.block;
46

            
47
	let _ = op.set_block_data(
48
		genesis_block.header().clone(),
49
		Some(genesis_block.extrinsics().to_vec()),
50
		None,
51
		None,
52
		NewBlockState::Final,
53
	);
54

            
55
	backend.commit_operation(op)
56
}
57

            
58
pub fn produce_first_block<Block: BlockT + sp_runtime::DeserializeOwned>(
59
	backend: Arc<lazy_loading::backend::Backend<Block>>,
60
	fork_checkpoint: Block,
61
	mut state_overrides: Vec<(Vec<u8>, Vec<u8>)>,
62
) -> sp_blockchain::Result<()> {
63
	let mut op = backend.begin_operation()?;
64

            
65
	let header = fork_checkpoint.header().clone();
66
	let next_block_number = header.number().saturating_add(One::one());
67

            
68
	let header: Block::Header = Block::Header::new(
69
		next_block_number,
70
		Default::default(),
71
		Default::default(),
72
		header.hash(),
73
		Default::default(),
74
	);
75

            
76
	// IMPORTANT: Add first block after the fork to frame_system::BlockHash
77
	// This is required by CheckMortality/CheckEra in SignedExtension
78
	let key = [
79
		&twox_128(b"System"),
80
		&twox_128(b"BlockHash"),
81
		twox_64(&next_block_number.encode()).as_slice(),
82
		&next_block_number.encode(),
83
	]
84
	.concat();
85
	state_overrides.push((key, header.hash().encode()));
86

            
87
	let _ = op.reset_storage(
88
		Storage {
89
			top: state_overrides.into_iter().collect(),
90
			children_default: Default::default(),
91
		},
92
		StateVersion::V0,
93
	)?;
94

            
95
	// Create empty first block
96
	let _ = op.set_block_data(
97
		header.clone(),
98
		Some(Default::default()),
99
		None,
100
		None,
101
		NewBlockState::Final,
102
	);
103

            
104
	backend.commit_operation(op)
105
}
106

            
107
pub fn get_parachain_id(rpc_client: Arc<RPC>) -> Option<u32> {
108
	let key = [twox_128(b"ParachainInfo"), twox_128(b"ParachainId")].concat();
109
	let result = rpc_client.storage::<H256>(StorageKey(key), None);
110

            
111
	result
112
		.map(|o| {
113
			o.and_then(|data| {
114
				<u32 as parity_scale_codec::Decode>::decode(&mut data.0.as_slice()).ok()
115
			})
116
		})
117
		.ok()
118
		.flatten()
119
}