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
//! Testing utilities.
18

            
19
use super::*;
20

            
21
use frame_support::{
22
	construct_runtime, parameter_types,
23
	traits::{AsEnsureOriginWithArg, Everything},
24
	weights::Weight,
25
};
26

            
27
use frame_system::{EnsureNever, EnsureRoot};
28
use pallet_evm::{EnsureAddressNever, EnsureAddressRoot};
29
use precompile_utils::{
30
	mock_account,
31
	precompile_set::*,
32
	testing::{AddressInPrefixedSet, MockAccount},
33
};
34
use sp_core::H256;
35
use sp_runtime::{
36
	traits::{BlakeTwo256, ConstU32, IdentityLookup},
37
	BuildStorage,
38
};
39

            
40
pub type AccountId = MockAccount;
41
pub type AssetId = u128;
42
pub type Balance = u128;
43
pub type Block = frame_system::mocking::MockBlockU32<Runtime>;
44

            
45
/// The foreign asset precompile address prefix. Addresses that match against this prefix will
46
/// be routed to Erc20AssetsPrecompileSet being marked as foreign
47
pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: u32 = 0xffffffff;
48

            
49
parameter_types! {
50
	pub ForeignAssetPrefix: &'static [u8] = &[0xff, 0xff, 0xff, 0xff];
51
}
52

            
53
78
mock_account!(ForeignAssetId(AssetId), |value: ForeignAssetId| {
54
78
	AddressInPrefixedSet(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, value.0).into()
55
78
});
56

            
57
// Implement the trait, where we convert AccountId to AssetID
58
impl AccountIdAssetIdConversion<AccountId, AssetId> for Runtime {
59
	/// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF
60
	/// and by taking the lowest 128 bits as the assetId
61
174
	fn account_to_asset_id(account: AccountId) -> Option<(Vec<u8>, AssetId)> {
62
174
		if account.has_prefix_u32(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX) {
63
174
			return Some((
64
174
				FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX
65
174
					.to_be_bytes()
66
174
					.to_vec(),
67
174
				account.without_prefix(),
68
174
			));
69
		}
70
		None
71
174
	}
72

            
73
	// Not used for now
74
	fn asset_id_to_account(_prefix: &[u8], asset_id: AssetId) -> AccountId {
75
		ForeignAssetId(asset_id).into()
76
	}
77
}
78

            
79
parameter_types! {
80
	pub const BlockHashCount: u32 = 250;
81
	pub const SS58Prefix: u8 = 42;
82
}
83

            
84
impl frame_system::Config for Runtime {
85
	type BaseCallFilter = Everything;
86
	type DbWeight = ();
87
	type RuntimeOrigin = RuntimeOrigin;
88
	type RuntimeTask = RuntimeTask;
89
	type Nonce = u64;
90
	type Block = Block;
91
	type RuntimeCall = RuntimeCall;
92
	type Hash = H256;
93
	type Hashing = BlakeTwo256;
94
	type AccountId = AccountId;
95
	type Lookup = IdentityLookup<Self::AccountId>;
96
	type RuntimeEvent = RuntimeEvent;
97
	type BlockHashCount = BlockHashCount;
98
	type Version = ();
99
	type PalletInfo = PalletInfo;
100
	type AccountData = pallet_balances::AccountData<Balance>;
101
	type OnNewAccount = ();
102
	type OnKilledAccount = ();
103
	type SystemWeightInfo = ();
104
	type BlockWeights = ();
105
	type BlockLength = ();
106
	type SS58Prefix = SS58Prefix;
107
	type OnSetCode = ();
108
	type MaxConsumers = frame_support::traits::ConstU32<16>;
109
	type SingleBlockMigrations = ();
110
	type MultiBlockMigrator = ();
111
	type PreInherents = ();
112
	type PostInherents = ();
113
	type PostTransactions = ();
114
}
115

            
116
parameter_types! {
117
	pub const MinimumPeriod: u64 = 5;
118
}
119

            
120
impl pallet_timestamp::Config for Runtime {
121
	type Moment = u64;
122
	type OnTimestampSet = ();
123
	type MinimumPeriod = MinimumPeriod;
124
	type WeightInfo = ();
125
}
126

            
127
parameter_types! {
128
	pub const ExistentialDeposit: u128 = 0;
129
}
130

            
131
impl pallet_balances::Config for Runtime {
132
	type MaxReserves = ();
133
	type ReserveIdentifier = ();
134
	type MaxLocks = ();
135
	type Balance = Balance;
136
	type RuntimeEvent = RuntimeEvent;
137
	type DustRemoval = ();
138
	type ExistentialDeposit = ExistentialDeposit;
139
	type AccountStore = System;
140
	type WeightInfo = ();
141
	type RuntimeHoldReason = ();
142
	type FreezeIdentifier = ();
143
	type MaxFreezes = ();
144
	type RuntimeFreezeReason = ();
145
}
146

            
147
pub type Precompiles<R> = PrecompileSetBuilder<
148
	R,
149
	(
150
		PrecompileSetStartingWith<
151
			ForeignAssetPrefix,
152
			Erc20AssetsPrecompileSet<R, pallet_assets::Instance1>,
153
		>,
154
	),
155
>;
156

            
157
pub type ForeignPCall = Erc20AssetsPrecompileSetCall<Runtime, pallet_assets::Instance1>;
158

            
159
const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
160
/// Block Storage Limit in bytes. Set to 40KB.
161
const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024;
162

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

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

            
202
type ForeignAssetInstance = pallet_assets::Instance1;
203

            
204
// Required for runtime benchmarks
205
pallet_assets::runtime_benchmarks_enabled! {
206
	pub struct BenchmarkHelper;
207
	impl<AssetIdParameter> pallet_assets::BenchmarkHelper<AssetIdParameter> for BenchmarkHelper
208
	where
209
		AssetIdParameter: From<u128>,
210
	{
211
		fn create_asset_id_parameter(id: u32) -> AssetIdParameter {
212
			(id as u128).into()
213
		}
214
	}
215
}
216

            
217
// These parameters dont matter much as this will only be called by root with the forced arguments
218
// No deposit is substracted with those methods
219
parameter_types! {
220
	pub const AssetDeposit: Balance = 0;
221
	pub const ApprovalDeposit: Balance = 0;
222
	pub const AssetsStringLimit: u32 = 50;
223
	pub const MetadataDepositBase: Balance = 0;
224
	pub const MetadataDepositPerByte: Balance = 0;
225
	pub const AssetAccountDeposit: Balance = 0;
226
}
227

            
228
impl pallet_assets::Config<ForeignAssetInstance> for Runtime {
229
	type RuntimeEvent = RuntimeEvent;
230
	type Balance = Balance;
231
	type AssetId = AssetId;
232
	type Currency = Balances;
233
	type ForceOrigin = EnsureRoot<AccountId>;
234
	type AssetDeposit = AssetDeposit;
235
	type MetadataDepositBase = MetadataDepositBase;
236
	type MetadataDepositPerByte = MetadataDepositPerByte;
237
	type ApprovalDeposit = ApprovalDeposit;
238
	type StringLimit = AssetsStringLimit;
239
	type Freezer = ();
240
	type Extra = ();
241
	type AssetAccountDeposit = AssetAccountDeposit;
242
	type WeightInfo = pallet_assets::weights::SubstrateWeight<Runtime>;
243
	type RemoveItemsLimit = ConstU32<656>;
244
	type AssetIdParameter = AssetId;
245
	type CreateOrigin = AsEnsureOriginWithArg<EnsureNever<AccountId>>;
246
	type CallbackHandle = ();
247
	pallet_assets::runtime_benchmarks_enabled! {
248
		type BenchmarkHelper = BenchmarkHelper;
249
	}
250
}
251

            
252
// Configure a mock runtime to test the pallet.
253
1533
construct_runtime!(
254
	pub enum Runtime
255
	{
256
		System: frame_system,
257
		Balances: pallet_balances,
258
		ForeignAssets: pallet_assets::<Instance1>,
259
		Evm: pallet_evm,
260
		Timestamp: pallet_timestamp,
261
	}
262
2951
);
263

            
264
pub(crate) struct ExtBuilder {
265
	// endowed accounts with balances
266
	balances: Vec<(AccountId, Balance)>,
267
}
268

            
269
impl Default for ExtBuilder {
270
29
	fn default() -> ExtBuilder {
271
29
		ExtBuilder { balances: vec![] }
272
29
	}
273
}
274

            
275
impl ExtBuilder {
276
27
	pub(crate) fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self {
277
27
		self.balances = balances;
278
27
		self
279
27
	}
280

            
281
29
	pub(crate) fn build(self) -> sp_io::TestExternalities {
282
29
		let mut t = frame_system::GenesisConfig::<Runtime>::default()
283
29
			.build_storage()
284
29
			.expect("Frame system builds valid default genesis config");
285
29

            
286
29
		pallet_balances::GenesisConfig::<Runtime> {
287
29
			balances: self.balances,
288
29
		}
289
29
		.assimilate_storage(&mut t)
290
29
		.expect("Pallet balances storage can be assimilated");
291
29

            
292
29
		let mut ext = sp_io::TestExternalities::new(t);
293
29
		ext.execute_with(|| System::set_block_number(1));
294
29
		ext
295
29
	}
296
}