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::chain_spec::generate_accounts;
18
use moonbeam_core_primitives::Balance;
19
use parity_scale_codec::Encode;
20
use serde::Deserialize;
21
use sp_core::blake2_128;
22
use std::io::Read;
23
use std::path::PathBuf;
24

            
25
#[derive(Deserialize, Debug, Clone)]
26
pub struct StateEntryConcrete {
27
	pub(crate) pallet: String,
28
	pub(crate) storage: String,
29
	#[serde(
30
		skip_serializing_if = "Option::is_none",
31
		deserialize_with = "serde_hex::deserialize_as_option",
32
		default
33
	)]
34
	pub(crate) key: Option<Vec<u8>>,
35
	#[serde(deserialize_with = "serde_hex::deserialize")]
36
	pub(crate) value: Vec<u8>,
37
}
38

            
39
#[derive(Deserialize, Debug, Clone)]
40
pub struct StateEntryRaw {
41
	#[serde(deserialize_with = "serde_hex::deserialize")]
42
	pub(crate) key: Vec<u8>,
43
	#[serde(deserialize_with = "serde_hex::deserialize")]
44
	pub(crate) value: Vec<u8>,
45
}
46

            
47
#[derive(Deserialize, Debug, Clone)]
48
#[serde(untagged)]
49
pub enum StateEntry {
50
	Concrete(StateEntryConcrete),
51
	Raw(StateEntryRaw),
52
}
53

            
54
/// Mandatory state overrides that most exist when starting a node in lazy loading mode.
55
pub fn base_state_overrides(runtime_code: Option<PathBuf>) -> Vec<StateEntry> {
56
	let mut overrides = vec![
57
		StateEntry::Concrete(
58
			StateEntryConcrete {
59
				pallet: "AuthorMapping".to_string(),
60
				storage: "NimbusLookup".to_string(),
61
				key: Some(hex_literal::hex!("9dfefc73f89d24437a9c2dce5572808af24ff3a9cf04c71dbc94d0b566f7a27b94566cac").to_vec()), // editorconfig-checker-disable-line
62
				value: hex_literal::hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d").to_vec() // editorconfig-checker-disable-line
63
			}
64
		),
65
		StateEntry::Concrete(
66
			StateEntryConcrete {
67
				pallet: "AuthorMapping".to_string(),
68
				storage: "MappingWithDeposit".to_string(),
69
				key: Some(hex_literal::hex!("de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d").to_vec()), // editorconfig-checker-disable-line
70
				value: hex_literal::hex!("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac000010632d5ec76b0500000000000000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d").to_vec() // editorconfig-checker-disable-line
71
			}
72
		),
73
		// Set candidate pool
74
		StateEntry::Concrete(
75
			StateEntryConcrete {
76
				pallet: "ParachainStaking".to_string(),
77
				storage: "CandidatePool".to_string(),
78
				key: None,
79
				value: hex_literal::hex!("04f24ff3a9cf04c71dbc94d0b566f7a27b94566cac0000a0dec5adc9353600000000000000").to_vec() // editorconfig-checker-disable-line
80
			}
81
		),
82
		// Set Alith as selected candidate
83
		StateEntry::Concrete(
84
			StateEntryConcrete {
85
				pallet: "ParachainStaking".to_string(),
86
				storage: "SelectedCandidates".to_string(),
87
				key: None,
88
				value: hex_literal::hex!("04f24ff3a9cf04c71dbc94d0b566f7a27b94566cac").to_vec()
89
			}
90
		),
91
		// AtStake
92
		StateEntry::Concrete(
93
			StateEntryConcrete {
94
				pallet: "ParachainStaking".to_string(),
95
				storage: "AtStake".to_string(),
96
				key: Some(hex_literal::hex!("5153cb1f00942ff4010000004a6bb7c01d316509f24ff3a9cf04c71dbc94d0b566f7a27b94566cac").to_vec()), // editorconfig-checker-disable-line
97
				value: hex_literal::hex!("0000a0dec5adc9353600000000000000000000a0dec5adc9353600000000000000").to_vec() // editorconfig-checker-disable-line
98
			}
99
		),
100
		// Reset SlotInfo
101
		StateEntry::Concrete(
102
			StateEntryConcrete {
103
				pallet: "AsyncBacking".to_string(),
104
				storage: "SlotInfo".to_string(),
105
				key: None,
106
				value: (1u64, 1u32).encode()
107
			}
108
		),
109
		// Reset LastRelayChainBlockNumber
110
		StateEntry::Concrete(
111
			StateEntryConcrete {
112
				pallet: "ParachainSystem".to_string(),
113
				storage: "LastRelayChainBlockNumber".to_string(),
114
				key: None,
115
				value: 0u32.encode()
116
			}
117
		),
118
	];
119

            
120
	// Default mnemonic if none was provided
121
	let test_mnemonic =
122
		"bottom drive obey lake curtain smoke basket hold race lonely fit walk".to_string();
123
	// Prefund the standard dev accounts
124
	for address in generate_accounts(test_mnemonic, 6) {
125
		overrides.push(StateEntry::Concrete(StateEntryConcrete {
126
			pallet: "System".to_string(),
127
			storage: "Account".to_string(),
128
			key: Some(
129
				[blake2_128(&address.0).as_slice(), address.0.as_slice()]
130
					.concat()
131
					.to_vec(),
132
			),
133
			value: frame_system::AccountInfo {
134
				nonce: 0u32,
135
				consumers: 0,
136
				providers: 1,
137
				sufficients: 0,
138
				data: pallet_balances::AccountData::<Balance> {
139
					free: Balance::MAX,
140
					reserved: Default::default(),
141
					frozen: Default::default(),
142
					flags: Default::default(),
143
				},
144
			}
145
			.encode(),
146
		}))
147
	}
148

            
149
	if let Some(path) = runtime_code {
150
		let mut reader = std::fs::File::open(path.clone())
151
			.expect(format!("Could not open file {:?}", path).as_str());
152
		let mut data = vec![];
153
		reader
154
			.read_to_end(&mut data)
155
			.expect("Runtime code override invalid.");
156

            
157
		overrides.push(StateEntry::Raw(StateEntryRaw {
158
			key: sp_core::storage::well_known_keys::CODE.to_vec(),
159
			value: data.to_vec(),
160
		}));
161
	}
162

            
163
	overrides
164
}
165

            
166
pub fn read(path: PathBuf) -> Result<Vec<StateEntry>, String> {
167
	let reader = std::fs::File::open(path).expect("Can open file");
168
	let state = serde_json::from_reader(reader).expect("Can parse state overrides JSON");
169

            
170
	Ok(state)
171
}
172

            
173
mod serde_hex {
174
	use hex::FromHex;
175
	use serde::{Deserialize, Deserializer};
176

            
177
	fn sanitize(data: &str) -> &str {
178
		if data.starts_with("0x") {
179
			&data[2..]
180
		} else {
181
			data
182
		}
183
	}
184

            
185
	pub fn deserialize_as_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
186
	where
187
		D: Deserializer<'de>,
188
		T: FromHex,
189
		<T as FromHex>::Error: std::fmt::Display + std::fmt::Debug,
190
	{
191
		Option::<String>::deserialize(deserializer).map(|value| {
192
			value.map(|data| FromHex::from_hex(sanitize(data.as_str())).expect("Invalid option"))
193
		})
194
	}
195

            
196
	pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
197
	where
198
		D: Deserializer<'de>,
199
		T: FromHex,
200
		<T as FromHex>::Error: std::fmt::Display + std::fmt::Debug,
201
	{
202
		String::deserialize(deserializer).map(|data| {
203
			FromHex::from_hex(sanitize(data.as_str())).expect("Invalid hex encoded string")
204
		})
205
	}
206
}