moonbeam_service/lazy_loading/
state_overrides.rs1use crate::chain_spec::generate_accounts;
18use moonbeam_core_primitives::{AccountId, Balance};
19use pallet_parachain_staking::{Bond, CandidateMetadata, CollatorSnapshot, Delegations};
20use parity_scale_codec::Encode;
21use serde::Deserialize;
22use sp_core::{blake2_128, twox_64};
23use std::io::Read;
24use std::path::PathBuf;
25
26#[derive(Deserialize, Debug, Clone)]
27pub struct StateEntryConcrete {
28 pub(crate) pallet: String,
29 pub(crate) storage: String,
30 #[serde(
31 skip_serializing_if = "Option::is_none",
32 deserialize_with = "serde_hex::deserialize_as_option",
33 default
34 )]
35 pub(crate) key: Option<Vec<u8>>,
36 #[serde(deserialize_with = "serde_hex::deserialize")]
37 pub(crate) value: Vec<u8>,
38}
39
40#[derive(Deserialize, Debug, Clone)]
41pub struct StateEntryRaw {
42 #[serde(deserialize_with = "serde_hex::deserialize")]
43 pub(crate) key: Vec<u8>,
44 #[serde(deserialize_with = "serde_hex::deserialize")]
45 pub(crate) value: Vec<u8>,
46}
47
48#[derive(Deserialize, Debug, Clone)]
49#[serde(untagged)]
50pub enum StateEntry {
51 Concrete(StateEntryConcrete),
52 Raw(StateEntryRaw),
53}
54
55pub fn base_state_overrides(runtime_code: Option<PathBuf>) -> Vec<StateEntry> {
57 use hex_literal::hex;
58 let alith_address = hex!("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac");
59 let alith_pub = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d");
60 let alith_staking_bond: Balance = 1_000_000_000_000_000_000;
61 let mut overrides = vec![
62 StateEntry::Concrete(StateEntryConcrete {
65 pallet: "ParachainSystem".to_string(),
66 storage: "PendingValidationCode".to_string(),
67 key: None,
68 value: Vec::new(),
69 }),
70 StateEntry::Concrete(StateEntryConcrete {
72 pallet: "ParachainSystem".to_string(),
73 storage: "LastRelayChainBlockNumber".to_string(),
74 key: None,
75 value: 0u32.encode(),
76 }),
77 StateEntry::Concrete(StateEntryConcrete {
78 pallet: "AuthorMapping".to_string(),
79 storage: "NimbusLookup".to_string(),
80 key: Some(
81 [
82 &blake2_128(alith_address.as_slice()),
83 alith_address.as_slice(),
84 ]
85 .concat(),
86 ),
87 value: alith_pub.to_vec(),
88 }),
89 StateEntry::Concrete(StateEntryConcrete {
90 pallet: "AuthorMapping".to_string(),
91 storage: "MappingWithDeposit".to_string(),
92 key: Some([&blake2_128(alith_pub.as_slice()), alith_pub.as_slice()].concat()),
93 value: (alith_address, alith_staking_bond, alith_pub).encode(),
94 }),
95 StateEntry::Concrete(StateEntryConcrete {
97 pallet: "ParachainStaking".to_string(),
98 storage: "TotalSelected".to_string(),
99 key: None,
100 value: 1u32.encode(),
101 }),
102 StateEntry::Concrete(StateEntryConcrete {
104 pallet: "ParachainStaking".to_string(),
105 storage: "CandidateInfo".to_string(),
106 key: Some(
107 [&twox_64(alith_address.as_slice()), alith_address.as_slice()]
108 .concat()
109 .to_vec(),
110 ),
111 value: CandidateMetadata::new(alith_staking_bond).encode(),
112 }),
113 StateEntry::Concrete(StateEntryConcrete {
114 pallet: "ParachainStaking".to_string(),
115 storage: "TopDelegations".to_string(),
116 key: Some(
117 [&twox_64(alith_address.as_slice()), alith_address.as_slice()]
118 .concat()
119 .to_vec(),
120 ),
121 value: Delegations::<AccountId, Balance> {
122 delegations: Default::default(),
123 total: Default::default(),
124 }
125 .encode(),
126 }),
127 StateEntry::Concrete(StateEntryConcrete {
128 pallet: "ParachainStaking".to_string(),
129 storage: "CandidatePool".to_string(),
130 key: None,
131 value: {
132 let bond = Bond::<AccountId, Balance> {
133 owner: AccountId::from(alith_address),
134 amount: alith_staking_bond,
135 };
136
137 vec![bond].encode()
138 },
139 }),
140 StateEntry::Concrete(StateEntryConcrete {
142 pallet: "ParachainStaking".to_string(),
143 storage: "SelectedCandidates".to_string(),
144 key: None,
145 value: vec![alith_address].encode(),
146 }),
147 StateEntry::Concrete(StateEntryConcrete {
148 pallet: "ParachainStaking".to_string(),
149 storage: "AtStake".to_string(),
150 key: {
151 let round: u32 = 1;
152 Some(
153 [
154 &twox_64(&round.encode()),
155 round.encode().as_slice(),
156 &twox_64(alith_address.as_slice()),
157 alith_address.as_slice(),
158 ]
159 .concat()
160 .to_vec(),
161 )
162 },
163 value: {
164 CollatorSnapshot::<AccountId, Balance> {
165 bond: alith_staking_bond.clone(),
166 delegations: Default::default(),
167 total: alith_staking_bond,
168 }
169 .encode()
170 },
171 }),
172 StateEntry::Concrete(StateEntryConcrete {
174 pallet: "AsyncBacking".to_string(),
175 storage: "SlotInfo".to_string(),
176 key: None,
177 value: (1u64, 1u32).encode(),
178 }),
179 ];
180
181 let test_mnemonic =
183 "bottom drive obey lake curtain smoke basket hold race lonely fit walk".to_string();
184 for address in generate_accounts(test_mnemonic, 6) {
186 overrides.push(StateEntry::Concrete(StateEntryConcrete {
187 pallet: "System".to_string(),
188 storage: "Account".to_string(),
189 key: Some(
190 [blake2_128(&address.0).as_slice(), address.0.as_slice()]
191 .concat()
192 .to_vec(),
193 ),
194 value: frame_system::AccountInfo {
195 nonce: 0u32,
196 consumers: 0,
197 providers: 1,
198 sufficients: 0,
199 data: pallet_balances::AccountData::<Balance> {
200 free: Balance::MAX,
201 reserved: Default::default(),
202 frozen: Default::default(),
203 flags: Default::default(),
204 },
205 }
206 .encode(),
207 }))
208 }
209
210 if let Some(path) = runtime_code {
211 let mut reader = std::fs::File::open(path.clone())
212 .expect(format!("Could not open file {:?}", path).as_str());
213 let mut data = vec![];
214 reader
215 .read_to_end(&mut data)
216 .expect("Runtime code override invalid.");
217
218 overrides.push(StateEntry::Raw(StateEntryRaw {
219 key: sp_core::storage::well_known_keys::CODE.to_vec(),
220 value: data.to_vec(),
221 }));
222 }
223
224 overrides
225}
226
227pub fn read(path: PathBuf) -> Result<Vec<StateEntry>, String> {
228 let reader = std::fs::File::open(path).expect("Can open file");
229 let state = serde_json::from_reader(reader).expect("Can parse state overrides JSON");
230
231 Ok(state)
232}
233
234mod serde_hex {
235 use hex::FromHex;
236 use serde::{Deserialize, Deserializer};
237
238 fn sanitize(data: &str) -> &str {
239 if let Some(stripped_data) = data.strip_prefix("0x") {
240 stripped_data
241 } else {
242 data
243 }
244 }
245
246 pub fn deserialize_as_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
247 where
248 D: Deserializer<'de>,
249 T: FromHex,
250 <T as FromHex>::Error: std::fmt::Display + std::fmt::Debug,
251 {
252 Option::<String>::deserialize(deserializer).map(|value| {
253 value.map(|data| FromHex::from_hex(sanitize(data.as_str())).expect("Invalid option"))
254 })
255 }
256
257 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
258 where
259 D: Deserializer<'de>,
260 T: FromHex,
261 <T as FromHex>::Error: std::fmt::Display + std::fmt::Debug,
262 {
263 String::deserialize(deserializer).map(|data| {
264 FromHex::from_hex(sanitize(data.as_str())).expect("Invalid hex encoded string")
265 })
266 }
267}