1
// Copyright 2019-2025 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
//! Test utilities
18
use super::*;
19
use cumulus_primitives_core::{
20
	relay_chain::BlockNumber as RelayChainBlockNumber, AggregateMessageOrigin,
21
	PersistedValidationData,
22
};
23
use cumulus_primitives_parachain_inherent::ParachainInherentData;
24
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
25
use frame_support::{
26
	construct_runtime,
27
	inherent::{InherentData, ProvideInherent},
28
	parameter_types,
29
	traits::{Everything, OnFinalize, OnInitialize, UnfilteredDispatchable},
30
	weights::Weight,
31
};
32
use frame_system::{pallet_prelude::BlockNumberFor, EnsureSigned, RawOrigin};
33
use pallet_evm::{EnsureAddressNever, EnsureAddressRoot, FrameSystemAccountProvider};
34
use precompile_utils::{precompile_set::*, testing::MockAccount};
35
use sp_core::{H256, U256};
36
use sp_io;
37
use sp_runtime::{
38
	traits::{BlakeTwo256, IdentityLookup},
39
	BuildStorage, Perbill,
40
};
41

            
42
pub type AccountId = MockAccount;
43
pub type Balance = u128;
44

            
45
type Block = frame_system::mocking::MockBlockU32<Runtime>;
46
pub type BlockNumber = BlockNumberFor<Runtime>;
47

            
48
// Configure a mock runtime to test the pallet.
49
1617
construct_runtime!(
50
163
	pub enum Runtime	{
51
163
		System: frame_system,
52
163
		Balances: pallet_balances,
53
163
		Evm: pallet_evm,
54
163
		Timestamp: pallet_timestamp,
55
163
		ParachainSystem: cumulus_pallet_parachain_system,
56
163
		Crowdloan: pallet_crowdloan_rewards,
57
163
		MessageQueue: pallet_message_queue,
58
163
	}
59
1643
);
60

            
61
parameter_types! {
62
	pub ParachainId: cumulus_primitives_core::ParaId = 100.into();
63
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
64
}
65

            
66
impl cumulus_pallet_parachain_system::Config for Runtime {
67
	type SelfParaId = ParachainId;
68
	type RuntimeEvent = RuntimeEvent;
69
	type OnSystemEvent = ();
70
	type OutboundXcmpMessageSource = ();
71
	type XcmpMessageHandler = ();
72
	type ReservedXcmpWeight = ();
73
	type DmpQueue = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
74
	type ReservedDmpWeight = ();
75
	type CheckAssociatedRelayNumber = cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
76
	type ConsensusHook = cumulus_pallet_parachain_system::ExpectParentIncluded;
77
	type WeightInfo = cumulus_pallet_parachain_system::weights::SubstrateWeight<Runtime>;
78
	type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector<Runtime>;
79
}
80

            
81
parameter_types! {
82
	pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
83
	pub const MessageQueueHeapSize: u32 = 65_536;
84
	pub const MessageQueueMaxStale: u32 = 16;
85
}
86

            
87
impl pallet_message_queue::Config for Runtime {
88
	type RuntimeEvent = RuntimeEvent;
89
	type Size = u32;
90
	type HeapSize = MessageQueueHeapSize;
91
	type MaxStale = MessageQueueMaxStale;
92
	type ServiceWeight = MessageQueueServiceWeight;
93
	type MessageProcessor =
94
		pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
95
	type QueueChangeHandler = ();
96
	type WeightInfo = ();
97
	type QueuePausedQuery = ();
98
	type IdleMaxServiceWeight = MessageQueueServiceWeight;
99
}
100

            
101
parameter_types! {
102
	pub const BlockHashCount: u32 = 250;
103
	pub const SS58Prefix: u8 = 42;
104
}
105
impl frame_system::Config for Runtime {
106
	type BaseCallFilter = Everything;
107
	type DbWeight = ();
108
	type RuntimeOrigin = RuntimeOrigin;
109
	type RuntimeTask = RuntimeTask;
110
	type Nonce = u64;
111
	type Block = Block;
112
	type RuntimeCall = RuntimeCall;
113
	type Hash = H256;
114
	type Hashing = BlakeTwo256;
115
	type AccountId = AccountId;
116
	type Lookup = IdentityLookup<Self::AccountId>;
117
	type RuntimeEvent = RuntimeEvent;
118
	type BlockHashCount = BlockHashCount;
119
	type Version = ();
120
	type PalletInfo = PalletInfo;
121
	type AccountData = pallet_balances::AccountData<Balance>;
122
	type OnNewAccount = ();
123
	type OnKilledAccount = ();
124
	type SystemWeightInfo = ();
125
	type BlockWeights = ();
126
	type BlockLength = ();
127
	type SS58Prefix = SS58Prefix;
128
	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
129
	type MaxConsumers = frame_support::traits::ConstU32<16>;
130
	type SingleBlockMigrations = ();
131
	type MultiBlockMigrator = ();
132
	type PreInherents = ();
133
	type PostInherents = ();
134
	type PostTransactions = ();
135
	type ExtensionsWeightInfo = ();
136
}
137
parameter_types! {
138
	pub const ExistentialDeposit: u128 = 0;
139
}
140
impl pallet_balances::Config for Runtime {
141
	type MaxReserves = ();
142
	type ReserveIdentifier = ();
143
	type MaxLocks = ();
144
	type Balance = Balance;
145
	type RuntimeEvent = RuntimeEvent;
146
	type DustRemoval = ();
147
	type ExistentialDeposit = ExistentialDeposit;
148
	type AccountStore = System;
149
	type WeightInfo = ();
150
	type RuntimeHoldReason = ();
151
	type FreezeIdentifier = ();
152
	type MaxFreezes = ();
153
	type RuntimeFreezeReason = ();
154
	type DoneSlashHandler = ();
155
}
156

            
157
pub type Precompiles<R> =
158
	PrecompileSetBuilder<R, (PrecompileAt<AddressU64<1>, CrowdloanRewardsPrecompile<R>>,)>;
159

            
160
pub type PCall = CrowdloanRewardsPrecompileCall<Runtime>;
161

            
162
const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
163
/// Block storage limit in bytes. Set to 40 KB.
164
const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024;
165

            
166
parameter_types! {
167
	pub BlockGasLimit: U256 = U256::from(u64::MAX);
168
	pub PrecompilesValue: Precompiles<Runtime> = Precompiles::new();
169
	pub const WeightPerGas: Weight = Weight::from_parts(1, 0);
170
	pub GasLimitPovSizeRatio: u64 = {
171
		let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64();
172
		block_gas_limit.saturating_div(MAX_POV_SIZE)
173
	};
174
	pub GasLimitStorageGrowthRatio: u64 = {
175
		let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64();
176
		block_gas_limit.saturating_div(BLOCK_STORAGE_LIMIT)
177
	};
178
	pub SuicideQuickClearLimit: u32 = 0;
179
}
180

            
181
impl pallet_evm::Config for Runtime {
182
	type FeeCalculator = ();
183
	type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
184
	type WeightPerGas = WeightPerGas;
185
	type CallOrigin = EnsureAddressRoot<AccountId>;
186
	type WithdrawOrigin = EnsureAddressNever<AccountId>;
187
	type AddressMapping = AccountId;
188
	type Currency = Balances;
189
	type RuntimeEvent = RuntimeEvent;
190
	type Runner = pallet_evm::runner::stack::Runner<Self>;
191
	type PrecompilesValue = PrecompilesValue;
192
	type PrecompilesType = Precompiles<Self>;
193
	type ChainId = ();
194
	type OnChargeTransaction = ();
195
	type BlockGasLimit = BlockGasLimit;
196
	type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping<Self>;
197
	type FindAuthor = ();
198
	type OnCreate = ();
199
	type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
200
	type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
201
	type Timestamp = Timestamp;
202
	type WeightInfo = pallet_evm::weights::SubstrateWeight<Runtime>;
203
	type AccountProvider = FrameSystemAccountProvider<Runtime>;
204
}
205

            
206
parameter_types! {
207
	pub const MinimumPeriod: u64 = 5;
208
}
209
impl pallet_timestamp::Config for Runtime {
210
	type Moment = u64;
211
	type OnTimestampSet = ();
212
	type MinimumPeriod = MinimumPeriod;
213
	type WeightInfo = ();
214
}
215

            
216
parameter_types! {
217
	pub const TestMaxInitContributors: u32 = 8;
218
	pub const TestMinimumReward: u128 = 0;
219
	pub const TestInitialized: bool = false;
220
	pub const TestInitializationPayment: Perbill = Perbill::from_percent(20);
221
	pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100);
222
	pub const TestSignatureNetworkIdentifier: &'static [u8] = b"test-";
223
}
224

            
225
impl pallet_crowdloan_rewards::Config for Runtime {
226
	type RuntimeEvent = RuntimeEvent;
227
	type Initialized = TestInitialized;
228
	type InitializationPayment = TestInitializationPayment;
229
	type MaxInitContributors = TestMaxInitContributors;
230
	type MinimumReward = TestMinimumReward;
231
	type RewardCurrency = Balances;
232
	type RelayChainAccountId = [u8; 32];
233
	type RewardAddressAssociateOrigin = EnsureSigned<Self::AccountId>;
234
	type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold;
235
	type RewardAddressChangeOrigin = EnsureSigned<Self::AccountId>;
236
	type SignatureNetworkIdentifier = TestSignatureNetworkIdentifier;
237

            
238
	type VestingBlockNumber = cumulus_primitives_core::relay_chain::BlockNumber;
239
	type VestingBlockProvider = cumulus_pallet_parachain_system::RelaychainDataProvider<Self>;
240
	type WeightInfo = ();
241
}
242
pub(crate) struct ExtBuilder {
243
	// endowed accounts with balances
244
	balances: Vec<(AccountId, Balance)>,
245
	crowdloan_pot: Balance,
246
}
247

            
248
impl Default for ExtBuilder {
249
9
	fn default() -> ExtBuilder {
250
9
		ExtBuilder {
251
9
			balances: vec![],
252
9
			crowdloan_pot: 0u32.into(),
253
9
		}
254
9
	}
255
}
256

            
257
impl ExtBuilder {
258
6
	pub(crate) fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self {
259
6
		self.balances = balances;
260
6
		self
261
6
	}
262
5
	pub(crate) fn with_crowdloan_pot(mut self, pot: Balance) -> Self {
263
5
		self.crowdloan_pot = pot;
264
5
		self
265
5
	}
266
9
	pub(crate) fn build(self) -> sp_io::TestExternalities {
267
9
		let mut t = frame_system::GenesisConfig::<Runtime>::default()
268
9
			.build_storage()
269
9
			.expect("Frame system builds valid default genesis config");
270
9

            
271
9
		pallet_balances::GenesisConfig::<Runtime> {
272
9
			balances: self.balances,
273
9
		}
274
9
		.assimilate_storage(&mut t)
275
9
		.expect("Pallet balances storage can be assimilated");
276
9

            
277
9
		pallet_crowdloan_rewards::GenesisConfig::<Runtime> {
278
9
			funded_amount: self.crowdloan_pot,
279
9
		}
280
9
		.assimilate_storage(&mut t)
281
9
		.expect("Crowdloan Rewards storage can be assimilated");
282
9

            
283
9
		let mut ext = sp_io::TestExternalities::new(t);
284
9
		ext.execute_with(|| System::set_block_number(1));
285
9
		ext
286
9
	}
287
}
288

            
289
//TODO Add pallets here if necessary
290
7
pub(crate) fn roll_to(n: BlockNumber) {
291
20
	while System::block_number() < n {
292
13
		// Relay chain Stuff. I might actually set this to a number different than N
293
13
		let sproof_builder = RelayStateSproofBuilder::default();
294
13
		let (relay_parent_storage_root, relay_chain_state) =
295
13
			sproof_builder.into_state_root_and_proof();
296
13
		let vfp = PersistedValidationData {
297
13
			relay_parent_number: (System::block_number() + 1) as RelayChainBlockNumber,
298
13
			relay_parent_storage_root,
299
13
			..Default::default()
300
13
		};
301
13
		let inherent_data = {
302
13
			let mut inherent_data = InherentData::default();
303
13
			let system_inherent_data = ParachainInherentData {
304
13
				validation_data: vfp.clone(),
305
13
				relay_chain_state,
306
13
				downward_messages: Default::default(),
307
13
				horizontal_messages: Default::default(),
308
13
			};
309
13
			inherent_data
310
13
				.put_data(
311
13
					cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
312
13
					&system_inherent_data,
313
13
				)
314
13
				.expect("failed to put VFP inherent");
315
13
			inherent_data
316
13
		};
317
13

            
318
13
		ParachainSystem::on_initialize(System::block_number());
319
13
		ParachainSystem::create_inherent(&inherent_data)
320
13
			.expect("got an inherent")
321
13
			.dispatch_bypass_filter(RawOrigin::None.into())
322
13
			.expect("dispatch succeeded");
323
13
		ParachainSystem::on_finalize(System::block_number());
324
13

            
325
13
		Balances::on_finalize(System::block_number());
326
13
		System::on_finalize(System::block_number());
327
13
		System::set_block_number(System::block_number() + 1);
328
13
		System::on_initialize(System::block_number());
329
13
		Balances::on_initialize(System::block_number());
330
13
	}
331
7
}
332

            
333
2
pub(crate) fn events() -> Vec<RuntimeEvent> {
334
2
	System::events()
335
2
		.into_iter()
336
17
		.map(|r| r.event)
337
2
		.collect::<Vec<_>>()
338
2
}