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::AggregateMessageOrigin;
20
use frame_support::{
21
	construct_runtime, parameter_types,
22
	traits::{Everything, OnFinalize, OnInitialize},
23
	weights::Weight,
24
};
25
use frame_system::{pallet_prelude::BlockNumberFor, EnsureSigned};
26
use pallet_evm::{EnsureAddressNever, EnsureAddressRoot, FrameSystemAccountProvider};
27
use precompile_utils::{precompile_set::*, testing::MockAccount};
28
use sp_core::{ConstU32, H256, U256};
29
use sp_io;
30
use sp_runtime::traits::BlockNumberProvider;
31
use sp_runtime::{
32
	traits::{BlakeTwo256, IdentityLookup},
33
	BuildStorage, Perbill,
34
};
35

            
36
pub type AccountId = MockAccount;
37
pub type Balance = u128;
38

            
39
type Block = frame_system::mocking::MockBlockU32<Runtime>;
40
pub type BlockNumber = BlockNumberFor<Runtime>;
41

            
42
// Configure a mock runtime to test the pallet.
43
construct_runtime!(
44
	pub enum Runtime	{
45
		System: frame_system,
46
		Balances: pallet_balances,
47
		Evm: pallet_evm,
48
		Timestamp: pallet_timestamp,
49
		ParachainSystem: cumulus_pallet_parachain_system,
50
		Crowdloan: pallet_crowdloan_rewards,
51
		MessageQueue: pallet_message_queue,
52
	}
53
);
54

            
55
parameter_types! {
56
	pub ParachainId: cumulus_primitives_core::ParaId = 100.into();
57
	pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
58
}
59

            
60
impl cumulus_pallet_parachain_system::Config for Runtime {
61
	type SelfParaId = ParachainId;
62
	type RuntimeEvent = RuntimeEvent;
63
	type OnSystemEvent = ();
64
	type OutboundXcmpMessageSource = ();
65
	type XcmpMessageHandler = ();
66
	type ReservedXcmpWeight = ();
67
	type DmpQueue = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
68
	type ReservedDmpWeight = ();
69
	type CheckAssociatedRelayNumber = cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
70
	type ConsensusHook = cumulus_pallet_parachain_system::ExpectParentIncluded;
71
	type WeightInfo = cumulus_pallet_parachain_system::weights::SubstrateWeight<Runtime>;
72
	type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector<Runtime>;
73
	type RelayParentOffset = ConstU32<0>;
74
}
75

            
76
parameter_types! {
77
	pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
78
	pub const MessageQueueHeapSize: u32 = 65_536;
79
	pub const MessageQueueMaxStale: u32 = 16;
80
}
81

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

            
96
parameter_types! {
97
	pub const BlockHashCount: u32 = 250;
98
	pub const SS58Prefix: u8 = 42;
99
}
100
impl frame_system::Config for Runtime {
101
	type BaseCallFilter = Everything;
102
	type DbWeight = ();
103
	type RuntimeOrigin = RuntimeOrigin;
104
	type RuntimeTask = RuntimeTask;
105
	type Nonce = u64;
106
	type Block = Block;
107
	type RuntimeCall = RuntimeCall;
108
	type Hash = H256;
109
	type Hashing = BlakeTwo256;
110
	type AccountId = AccountId;
111
	type Lookup = IdentityLookup<Self::AccountId>;
112
	type RuntimeEvent = RuntimeEvent;
113
	type BlockHashCount = BlockHashCount;
114
	type Version = ();
115
	type PalletInfo = PalletInfo;
116
	type AccountData = pallet_balances::AccountData<Balance>;
117
	type OnNewAccount = ();
118
	type OnKilledAccount = ();
119
	type SystemWeightInfo = ();
120
	type BlockWeights = ();
121
	type BlockLength = ();
122
	type SS58Prefix = SS58Prefix;
123
	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
124
	type MaxConsumers = frame_support::traits::ConstU32<16>;
125
	type SingleBlockMigrations = ();
126
	type MultiBlockMigrator = ();
127
	type PreInherents = ();
128
	type PostInherents = ();
129
	type PostTransactions = ();
130
	type ExtensionsWeightInfo = ();
131
}
132
pub struct MockVestingBlockNumberProvider;
133
impl BlockNumberProvider for MockVestingBlockNumberProvider {
134
	type BlockNumber = u32;
135

            
136
1
	fn current_block_number() -> Self::BlockNumber {
137
1
		System::block_number()
138
1
	}
139
}
140

            
141
parameter_types! {
142
	pub const ExistentialDeposit: u128 = 1;
143
}
144
impl pallet_balances::Config for Runtime {
145
	type MaxReserves = ();
146
	type ReserveIdentifier = ();
147
	type MaxLocks = ();
148
	type Balance = Balance;
149
	type RuntimeEvent = RuntimeEvent;
150
	type DustRemoval = ();
151
	type ExistentialDeposit = ExistentialDeposit;
152
	type AccountStore = System;
153
	type WeightInfo = ();
154
	type RuntimeHoldReason = ();
155
	type FreezeIdentifier = ();
156
	type MaxFreezes = ();
157
	type RuntimeFreezeReason = ();
158
	type DoneSlashHandler = ();
159
}
160

            
161
pub type Precompiles<R> =
162
	PrecompileSetBuilder<R, (PrecompileAt<AddressU64<1>, CrowdloanRewardsPrecompile<R>>,)>;
163

            
164
pub type PCall = CrowdloanRewardsPrecompileCall<Runtime>;
165

            
166
const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
167
/// Block storage limit in bytes. Set to 40 KB.
168
const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024;
169

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

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

            
211
parameter_types! {
212
	pub const MinimumPeriod: u64 = 5;
213
}
214
impl pallet_timestamp::Config for Runtime {
215
	type Moment = u64;
216
	type OnTimestampSet = ();
217
	type MinimumPeriod = MinimumPeriod;
218
	type WeightInfo = ();
219
}
220

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

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

            
242
	type VestingBlockNumber = u32;
243
	type VestingBlockProvider = MockVestingBlockNumberProvider;
244
	type WeightInfo = ();
245
}
246
pub(crate) struct ExtBuilder {
247
	// endowed accounts with balances
248
	balances: Vec<(AccountId, Balance)>,
249
	crowdloan_pot: Balance,
250
}
251

            
252
impl Default for ExtBuilder {
253
9
	fn default() -> ExtBuilder {
254
9
		ExtBuilder {
255
9
			balances: vec![],
256
9
			crowdloan_pot: 0u32.into(),
257
9
		}
258
9
	}
259
}
260

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

            
275
9
		let mut balances = self.balances;
276
9
		if self.crowdloan_pot > 0 {
277
5
			balances.push((Crowdloan::account_id(), self.crowdloan_pot));
278
5
		}
279

            
280
9
		pallet_balances::GenesisConfig::<Runtime> {
281
9
			balances,
282
9
			dev_accounts: Default::default(),
283
9
		}
284
9
		.assimilate_storage(&mut t)
285
9
		.expect("Pallet balances storage can be assimilated");
286

            
287
9
		pallet_crowdloan_rewards::GenesisConfig::<Runtime> {
288
9
			funded_accounts: vec![],
289
9
			init_vesting_block: 1u32,
290
9
			end_vesting_block: 100u32,
291
9
		}
292
9
		.assimilate_storage(&mut t)
293
9
		.expect("Crowdloan Rewards storage can be assimilated");
294

            
295
9
		let mut ext = sp_io::TestExternalities::new(t);
296
9
		ext.execute_with(|| System::set_block_number(1));
297
9
		ext
298
9
	}
299
}
300

            
301
7
pub(crate) fn roll_to(n: BlockNumber) {
302
20
	while System::block_number() < n {
303
13
		Crowdloan::on_finalize(System::block_number());
304
13
		Balances::on_finalize(System::block_number());
305
13
		System::on_finalize(System::block_number());
306
13
		System::set_block_number(System::block_number() + 1);
307
13
		System::on_initialize(System::block_number());
308
13
		Balances::on_initialize(System::block_number());
309
13
		Crowdloan::on_initialize(System::block_number());
310
13
	}
311
7
}
312

            
313
2
pub(crate) fn events() -> Vec<RuntimeEvent> {
314
2
	System::events()
315
2
		.into_iter()
316
2
		.map(|r| r.event)
317
2
		.collect::<Vec<_>>()
318
2
}