1
// Copyright 2019-2022 PureStake Inc.
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
#![allow(dead_code)]
18

            
19
use cumulus_primitives_parachain_inherent::ParachainInherentData;
20
use fp_evm::GenesisAccount;
21
use frame_support::{
22
	assert_ok,
23
	traits::{OnFinalize, OnInitialize},
24
};
25
pub use moonbeam_runtime::{
26
	asset_config::AssetRegistrarMetadata, currency::GLMR, xcm_config::AssetType, AccountId,
27
	AssetId, AssetManager, AsyncBacking, AuthorInherent, Balance, Ethereum, InflationInfo,
28
	ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter,
29
	UncheckedExtrinsic, HOURS,
30
};
31
use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID};
32
use polkadot_parachain::primitives::HeadData;
33
use sp_consensus_slots::Slot;
34
use sp_core::{Encode, H160};
35
use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent};
36

            
37
use std::collections::BTreeMap;
38

            
39
use fp_rpc::ConvertTransaction;
40

            
41
10
pub fn existential_deposit() -> u128 {
42
10
	<Runtime as pallet_balances::Config>::ExistentialDeposit::get()
43
10
}
44

            
45
// A valid signed Alice transfer.
46
pub const VALID_ETH_TX: &str =
47
	"02f869820501808085e8d4a51000825208943cd0a705a2dc65e5b1e1205896baa2be8a07c6e00180c\
48
	001a061087911e877a5802142a89a40d231d50913db399eb50839bb2d04e612b22ec8a01aa313efdf2\
49
	793bea76da6813bda611444af16a6207a8cfef2d9c8aa8f8012f7";
50

            
51
// An invalid signed Alice transfer with a gas limit artifically set to 0.
52
pub const INVALID_ETH_TX: &str =
53
	"f8628085174876e800809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ba011110796057\
54
	0e2d49fcc2afbc582e1abd3eeb027242b92abcebcec7cdefab63ea001732f6fac84acdd5b096554230\
55
	75003e7f07430652c3d6722e18f50b3d34e29";
56

            
57
3
pub fn rpc_run_to_block(n: u32) {
58
6
	while System::block_number() < n {
59
3
		Ethereum::on_finalize(System::block_number());
60
3
		System::set_block_number(System::block_number() + 1);
61
3
		Ethereum::on_initialize(System::block_number());
62
3
	}
63
3
}
64

            
65
/// Utility function that advances the chain to the desired block number.
66
/// If an author is provided, that author information is injected to all the blocks in the meantime.
67
8
pub fn run_to_block(n: u32, author: Option<NimbusId>) {
68
8
	// Finalize the first block
69
8
	Ethereum::on_finalize(System::block_number());
70
16208
	while System::block_number() < n {
71
		// Set the new block number and author
72
16200
		match author {
73
16200
			Some(ref author) => {
74
16200
				let pre_digest = Digest {
75
16200
					logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())],
76
16200
				};
77
16200
				System::reset_events();
78
16200
				System::initialize(
79
16200
					&(System::block_number() + 1),
80
16200
					&System::parent_hash(),
81
16200
					&pre_digest,
82
16200
				);
83
16200
			}
84
			None => {
85
				System::set_block_number(System::block_number() + 1);
86
			}
87
		}
88

            
89
16200
		increase_last_relay_slot_number(1);
90
16200

            
91
16200
		// Initialize the new block
92
16200
		AuthorInherent::on_initialize(System::block_number());
93
16200
		ParachainStaking::on_initialize(System::block_number());
94
16200
		Ethereum::on_initialize(System::block_number());
95
16200

            
96
16200
		// Finalize the block
97
16200
		Ethereum::on_finalize(System::block_number());
98
16200
		ParachainStaking::on_finalize(System::block_number());
99
	}
100
8
}
101

            
102
3
pub fn last_event() -> RuntimeEvent {
103
3
	System::events().pop().expect("Event expected").event
104
3
}
105

            
106
// Helper function to give a simple evm context suitable for tests.
107
// We can remove this once https://github.com/rust-blockchain/evm/pull/35
108
// is in our dependency graph.
109
pub fn evm_test_context() -> fp_evm::Context {
110
	fp_evm::Context {
111
		address: Default::default(),
112
		caller: Default::default(),
113
		apparent_value: From::from(0),
114
	}
115
}
116

            
117
// Test struct with the purpose of initializing xcm assets
118
#[derive(Clone)]
119
pub struct XcmAssetInitialization {
120
	pub asset_type: AssetType,
121
	pub metadata: AssetRegistrarMetadata,
122
	pub balances: Vec<(AccountId, Balance)>,
123
	pub is_sufficient: bool,
124
}
125

            
126
pub struct ExtBuilder {
127
	// endowed accounts with balances
128
	balances: Vec<(AccountId, Balance)>,
129
	// [collator, amount]
130
	collators: Vec<(AccountId, Balance)>,
131
	// [delegator, collator, nomination_amount]
132
	delegations: Vec<(AccountId, AccountId, Balance, Percent)>,
133
	// per-round inflation config
134
	inflation: InflationInfo<Balance>,
135
	// AuthorId -> AccountId mappings
136
	mappings: Vec<(NimbusId, AccountId)>,
137
	// Crowdloan fund
138
	crowdloan_fund: Balance,
139
	// Chain id
140
	chain_id: u64,
141
	// EVM genesis accounts
142
	evm_accounts: BTreeMap<H160, GenesisAccount>,
143
	// [assettype, metadata, Vec<Account, Balance,>, is_sufficient]
144
	xcm_assets: Vec<XcmAssetInitialization>,
145
	safe_xcm_version: Option<u32>,
146
}
147

            
148
impl Default for ExtBuilder {
149
61
	fn default() -> ExtBuilder {
150
61
		ExtBuilder {
151
61
			balances: vec![],
152
61
			delegations: vec![],
153
61
			collators: vec![],
154
61
			inflation: InflationInfo {
155
61
				expect: Range {
156
61
					min: 100_000 * GLMR,
157
61
					ideal: 200_000 * GLMR,
158
61
					max: 500_000 * GLMR,
159
61
				},
160
61
				// not used
161
61
				annual: Range {
162
61
					min: Perbill::from_percent(50),
163
61
					ideal: Perbill::from_percent(50),
164
61
					max: Perbill::from_percent(50),
165
61
				},
166
61
				// unrealistically high parameterization, only for testing
167
61
				round: Range {
168
61
					min: Perbill::from_percent(5),
169
61
					ideal: Perbill::from_percent(5),
170
61
					max: Perbill::from_percent(5),
171
61
				},
172
61
			},
173
61
			mappings: vec![],
174
61
			crowdloan_fund: 0,
175
61
			chain_id: CHAIN_ID,
176
61
			evm_accounts: BTreeMap::new(),
177
61
			xcm_assets: vec![],
178
61
			safe_xcm_version: None,
179
61
		}
180
61
	}
181
}
182

            
183
impl ExtBuilder {
184
2
	pub fn with_evm_accounts(mut self, accounts: BTreeMap<H160, GenesisAccount>) -> Self {
185
2
		self.evm_accounts = accounts;
186
2
		self
187
2
	}
188

            
189
42
	pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self {
190
42
		self.balances = balances;
191
42
		self
192
42
	}
193

            
194
17
	pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self {
195
17
		self.collators = collators;
196
17
		self
197
17
	}
198

            
199
7
	pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self {
200
7
		self.delegations = delegations
201
7
			.into_iter()
202
8
			.map(|d| (d.0, d.1, d.2, Percent::zero()))
203
7
			.collect();
204
7
		self
205
7
	}
206

            
207
6
	pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self {
208
6
		self.crowdloan_fund = crowdloan_fund;
209
6
		self
210
6
	}
211

            
212
16
	pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self {
213
16
		self.mappings = mappings;
214
16
		self
215
16
	}
216

            
217
8
	pub fn with_xcm_assets(mut self, xcm_assets: Vec<XcmAssetInitialization>) -> Self {
218
8
		self.xcm_assets = xcm_assets;
219
8
		self
220
8
	}
221

            
222
7
	pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self {
223
7
		self.safe_xcm_version = Some(safe_xcm_version);
224
7
		self
225
7
	}
226

            
227
	#[allow(dead_code)]
228
	pub fn with_inflation(mut self, inflation: InflationInfo<Balance>) -> Self {
229
		self.inflation = inflation;
230
		self
231
	}
232

            
233
61
	pub fn build(self) -> sp_io::TestExternalities {
234
61
		let mut t = frame_system::GenesisConfig::<Runtime>::default()
235
61
			.build_storage()
236
61
			.unwrap();
237
61

            
238
61
		pallet_balances::GenesisConfig::<Runtime> {
239
61
			balances: self.balances,
240
61
		}
241
61
		.assimilate_storage(&mut t)
242
61
		.unwrap();
243
61

            
244
61
		pallet_parachain_staking::GenesisConfig::<Runtime> {
245
61
			candidates: self.collators,
246
61
			delegations: self.delegations,
247
61
			inflation_config: self.inflation,
248
61
			collator_commission: Perbill::from_percent(20),
249
61
			parachain_bond_reserve_percent: Percent::from_percent(30),
250
61
			blocks_per_round: 6 * HOURS,
251
61
			num_selected_candidates: 8,
252
61
		}
253
61
		.assimilate_storage(&mut t)
254
61
		.unwrap();
255
61

            
256
61
		pallet_crowdloan_rewards::GenesisConfig::<Runtime> {
257
61
			funded_amount: self.crowdloan_fund,
258
61
		}
259
61
		.assimilate_storage(&mut t)
260
61
		.unwrap();
261
61

            
262
61
		pallet_author_mapping::GenesisConfig::<Runtime> {
263
61
			mappings: self.mappings,
264
61
		}
265
61
		.assimilate_storage(&mut t)
266
61
		.unwrap();
267
61

            
268
61
		let genesis_config = pallet_evm_chain_id::GenesisConfig::<Runtime> {
269
61
			chain_id: self.chain_id,
270
61
			..Default::default()
271
61
		};
272
61
		genesis_config.assimilate_storage(&mut t).unwrap();
273
61

            
274
61
		let genesis_config = pallet_evm::GenesisConfig::<Runtime> {
275
61
			accounts: self.evm_accounts,
276
61
			..Default::default()
277
61
		};
278
61
		genesis_config.assimilate_storage(&mut t).unwrap();
279
61

            
280
61
		let genesis_config = pallet_ethereum::GenesisConfig::<Runtime> {
281
61
			..Default::default()
282
61
		};
283
61
		genesis_config.assimilate_storage(&mut t).unwrap();
284
61

            
285
61
		let genesis_config = pallet_xcm::GenesisConfig::<Runtime> {
286
61
			safe_xcm_version: self.safe_xcm_version,
287
61
			..Default::default()
288
61
		};
289
61
		genesis_config.assimilate_storage(&mut t).unwrap();
290
61

            
291
61
		let mut ext = sp_io::TestExternalities::new(t);
292
61
		let xcm_assets = self.xcm_assets.clone();
293
61
		ext.execute_with(|| {
294
			// If any xcm assets specified, we register them here
295
69
			for xcm_asset_initialization in xcm_assets {
296
8
				let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into();
297
8
				AssetManager::register_foreign_asset(
298
8
					root_origin(),
299
8
					xcm_asset_initialization.asset_type,
300
8
					xcm_asset_initialization.metadata,
301
8
					1,
302
8
					xcm_asset_initialization.is_sufficient,
303
8
				)
304
8
				.unwrap();
305
16
				for (account, balance) in xcm_asset_initialization.balances {
306
8
					moonbeam_runtime::Assets::mint(
307
8
						origin_of(AssetManager::account_id()),
308
8
						asset_id.into(),
309
8
						account,
310
8
						balance,
311
8
					)
312
8
					.unwrap();
313
8
				}
314
			}
315
61
			System::set_block_number(1);
316
61
		});
317
61
		ext
318
61
	}
319
}
320

            
321
pub const CHAIN_ID: u64 = 1281;
322
pub const ALICE: [u8; 20] = [4u8; 20];
323
pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32];
324
pub const BOB: [u8; 20] = [5u8; 20];
325
pub const CHARLIE: [u8; 20] = [6u8; 20];
326
pub const DAVE: [u8; 20] = [7u8; 20];
327
pub const EVM_CONTRACT: [u8; 20] = [8u8; 20];
328

            
329
28
pub fn origin_of(account_id: AccountId) -> <Runtime as frame_system::Config>::RuntimeOrigin {
330
28
	<Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id)
331
28
}
332

            
333
11
pub fn inherent_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
334
11
	<Runtime as frame_system::Config>::RuntimeOrigin::none()
335
11
}
336

            
337
21
pub fn root_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
338
21
	<Runtime as frame_system::Config>::RuntimeOrigin::root()
339
21
}
340

            
341
/// Mock the inherent that sets validation data in ParachainSystem, which
342
/// contains the `relay_chain_block_number`, which is used in `author-filter` as a
343
/// source of randomness to filter valid authors at each block.
344
11
pub fn set_parachain_inherent_data() {
345
11
	use cumulus_primitives_core::PersistedValidationData;
346
11
	use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
347
11

            
348
11
	let mut relay_sproof = RelayStateSproofBuilder::default();
349
11
	relay_sproof.para_id = 100u32.into();
350
11
	relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3]));
351
11

            
352
11
	let additional_key_values = vec![(
353
11
		moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(),
354
11
		sp_timestamp::Timestamp::default().encode(),
355
11
	)];
356
11

            
357
11
	relay_sproof.additional_key_values = additional_key_values;
358
11

            
359
11
	let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof();
360
11

            
361
11
	let vfp = PersistedValidationData {
362
11
		relay_parent_number: 1u32,
363
11
		relay_parent_storage_root,
364
11
		..Default::default()
365
11
	};
366
11
	let parachain_inherent_data = ParachainInherentData {
367
11
		validation_data: vfp,
368
11
		relay_chain_state: relay_chain_state,
369
11
		downward_messages: Default::default(),
370
11
		horizontal_messages: Default::default(),
371
11
	};
372
11
	assert_ok!(RuntimeCall::ParachainSystem(
373
11
		cumulus_pallet_parachain_system::Call::<Runtime>::set_validation_data {
374
11
			data: parachain_inherent_data
375
11
		}
376
11
	)
377
11
	.dispatch(inherent_origin()));
378
11
}
379

            
380
7
pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic {
381
7
	let converter = TransactionConverter;
382
7
	converter.convert_transaction(ethereum_transaction(raw_hex_tx))
383
7
}
384

            
385
9
pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction {
386
9
	let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes.");
387
9
	let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]);
388
9
	assert!(transaction.is_ok());
389
9
	transaction.unwrap()
390
9
}
391

            
392
16202
pub fn increase_last_relay_slot_number(amount: u64) {
393
16202
	let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0);
394
16202
	frame_support::storage::unhashed::put(
395
16202
		&frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"),
396
16202
		&((Slot::from(last_relay_slot + amount), 0)),
397
16202
	);
398
16202
}