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::{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
65
construct_runtime!(
44
65
	pub enum Runtime	{
45
65
		System: frame_system,
46
65
		Balances: pallet_balances,
47
65
		Evm: pallet_evm,
48
65
		Timestamp: pallet_timestamp,
49
65
		ParachainSystem: cumulus_pallet_parachain_system,
50
65
		Crowdloan: pallet_crowdloan_rewards,
51
65
		MessageQueue: pallet_message_queue,
52
65
	}
53
65
);
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
}
74

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

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

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

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

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

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

            
163
pub type PCall = CrowdloanRewardsPrecompileCall<Runtime>;
164

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

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

            
184
impl pallet_evm::Config for Runtime {
185
	type FeeCalculator = ();
186
	type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
187
	type WeightPerGas = WeightPerGas;
188
	type CallOrigin = EnsureAddressRoot<AccountId>;
189
	type WithdrawOrigin = EnsureAddressNever<AccountId>;
190
	type AddressMapping = AccountId;
191
	type Currency = Balances;
192
	type RuntimeEvent = RuntimeEvent;
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 RuntimeEvent = RuntimeEvent;
232
	type Initialized = TestInitialized;
233
	type InitializationPayment = TestInitializationPayment;
234
	type MaxInitContributors = TestMaxInitContributors;
235
	type MinimumReward = TestMinimumReward;
236
	type RewardCurrency = Balances;
237
	type RelayChainAccountId = [u8; 32];
238
	type RewardAddressAssociateOrigin = EnsureSigned<Self::AccountId>;
239
	type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold;
240
	type RewardAddressChangeOrigin = EnsureSigned<Self::AccountId>;
241
	type SignatureNetworkIdentifier = TestSignatureNetworkIdentifier;
242

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

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

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

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

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

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

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

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

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