1use std::time::SystemTime;
2
3use frame_support::{
4 sp_runtime::{
5 BuildStorage,
6 traits::{
7 Header,
8 One,
9 },
10 },
11 traits::Hooks,
12};
13use frame_system::pallet_prelude::BlockNumberFor;
14use sp_io::TestExternalities;
15
16#[macro_export]
37macro_rules! assert_ok {
38 ($result:expr) => {{
39 let result = $result;
40 if result.dry_run.did_revert() {
41 panic!(
42 "Expected call to succeed but it reverted.\nError: {:?}",
43 result.extract_error()
44 );
45 }
46 result
47 }};
48 ($result:expr, $($msg:tt)+) => {{
49 let result = $result;
50 if result.dry_run.did_revert() {
51 panic!(
52 "{}\nExpected call to succeed but it reverted.\nError: {:?}",
53 format_args!($($msg)+),
54 result.extract_error()
55 );
56 }
57 result
58 }};
59}
60
61#[macro_export]
84macro_rules! assert_noop {
85 ($result:expr, $expected_error:expr) => {{
86 let result = $result;
87 if !result.dry_run.did_revert() {
88 panic!(
89 "Expected call to revert with '{}' but it succeeded",
90 $expected_error
91 );
92 }
93
94 let actual_error = result.extract_error();
95 if actual_error != Some($expected_error.to_string()) {
96 panic!(
97 "Expected error '{}' but got {:?}",
98 $expected_error,
99 actual_error
100 );
101 }
102
103 result
104 }};
105 ($result:expr, $expected_error:expr, $($msg:tt)+) => {{
106 let result = $result;
107 if !result.dry_run.did_revert() {
108 panic!(
109 "{}\nExpected call to revert with '{}' but it succeeded",
110 format_args!($($msg)+),
111 $expected_error
112 );
113 }
114
115 let actual_error = result.extract_error();
116 if actual_error != Some($expected_error.to_string()) {
117 panic!(
118 "{}\nExpected error '{}' but got {:?}",
119 format_args!($($msg)+),
120 $expected_error,
121 actual_error
122 );
123 }
124
125 result
126 }};
127}
128
129#[macro_export]
138macro_rules! assert_last_event {
139 ($client:expr, $event:expr $(,)?) => {
140 $crate::client::assert_last_contract_event_inner($client, $event)
141 };
142}
143
144pub struct BlockBuilder<T>(std::marker::PhantomData<T>);
146
147impl<
148 T: pallet_balances::Config
149 + pallet_timestamp::Config<Moment = u64>
150 + pallet_revive::Config,
151> BlockBuilder<T>
152{
153 pub fn new_ext(
155 balances: Vec<(T::AccountId, <T as pallet_balances::Config>::Balance)>,
156 ) -> TestExternalities {
157 let mut storage = frame_system::GenesisConfig::<T>::default()
158 .build_storage()
159 .unwrap();
160
161 pallet_balances::GenesisConfig::<T> {
162 balances,
163 dev_accounts: None,
164 }
165 .assimilate_storage(&mut storage)
166 .unwrap();
167
168 let mut ext = TestExternalities::new(storage);
169
170 ext.execute_with(|| {
171 Self::initialize_block(BlockNumberFor::<T>::one(), Default::default())
172 });
173 ext
174 }
175
176 pub fn initialize_block(
178 height: frame_system::pallet_prelude::BlockNumberFor<T>,
179 parent_hash: <T as frame_system::Config>::Hash,
180 ) {
181 frame_system::Pallet::<T>::reset_events();
182 frame_system::Pallet::<T>::initialize(&height, &parent_hash, &Default::default());
183 pallet_balances::Pallet::<T>::on_initialize(height);
184 pallet_timestamp::Pallet::<T>::set_timestamp(
185 SystemTime::now()
186 .duration_since(SystemTime::UNIX_EPOCH)
187 .expect("Time went backwards")
188 .as_secs(),
189 );
190 pallet_timestamp::Pallet::<T>::on_initialize(height);
191 pallet_revive::Pallet::<T>::on_initialize(height);
192 frame_system::Pallet::<T>::note_finished_initialize();
193 }
194
195 pub fn finalize_block(
197 height: frame_system::pallet_prelude::BlockNumberFor<T>,
198 ) -> <T as frame_system::Config>::Hash {
199 pallet_revive::Pallet::<T>::on_finalize(height);
200 use sp_core::Get;
201 let minimum_period = <T as pallet_timestamp::Config>::MinimumPeriod::get();
202 let now = pallet_timestamp::Pallet::<T>::get()
203 .checked_add(minimum_period)
204 .unwrap();
205 pallet_timestamp::Pallet::<T>::set_timestamp(now);
206 pallet_timestamp::Pallet::<T>::on_finalize(height);
207 pallet_balances::Pallet::<T>::on_finalize(height);
208 frame_system::Pallet::<T>::finalize().hash()
209 }
210}
211
212#[macro_export]
216macro_rules! create_sandbox {
217 ($name:ident) => {
218 $crate::paste::paste! {
219 $crate::create_sandbox!($name, [<$name Runtime>], (), {});
220 }
221 };
222 ($name:ident, $debug: ty) => {
223 $crate::paste::paste! {
224 $crate::create_sandbox!($name, [<$name Runtime>], $debug, {});
225 }
226 };
227 ($name:ident, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
228 $crate::paste::paste! {
229 $crate::create_sandbox!($name, [<$name Runtime>], $debug, {
230 $(
231 $pallet_name : $pallet,
232 )*
233 });
234 }
235 };
236 ($sandbox:ident, $runtime:ident, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
237
238mod construct_runtime {
240
241 use $crate::frame_support::{
243 construct_runtime,
244 derive_impl,
245 parameter_types,
246 sp_runtime::{
247 traits::Convert,
248 AccountId32, Perbill,
249 FixedU128,
250 },
251 traits::{ConstBool, ConstU8, ConstU128, ConstU32, ConstU64, Currency},
252 weights::{Weight, IdentityFee},
253 };
254
255 use $crate::pallet_transaction_payment::{FungibleAdapter};
256
257 use $crate::Snapshot;
258
259 pub type Balance = u128;
260
261 construct_runtime!(
263 pub enum $runtime {
264 System: $crate::frame_system,
265 Balances: $crate::pallet_balances,
266 Timestamp: $crate::pallet_timestamp,
267 Assets: $crate::pallet_assets::<Instance1>,
268 Revive: $crate::pallet_revive,
269 TransactionPayment: $crate::pallet_transaction_payment,
270 $(
271 $pallet_name: $pallet,
272 )*
273 }
274 );
275
276 #[derive_impl($crate::frame_system::config_preludes::SolochainDefaultConfig as $crate::frame_system::DefaultConfig)]
277 impl $crate::frame_system::Config for $runtime {
278 type Block = $crate::frame_system::mocking::MockBlockU32<$runtime>;
279 type Version = ();
280 type BlockHashCount = ConstU32<250>;
281 type AccountData = $crate::pallet_balances::AccountData<<$runtime as $crate::pallet_balances::Config>::Balance>;
282 }
283
284 impl $crate::pallet_balances::Config for $runtime {
285 type RuntimeEvent = RuntimeEvent;
286 type WeightInfo = ();
287 type Balance = Balance;
288 type DustRemoval = ();
289 type ExistentialDeposit = ConstU128<1>;
290 type AccountStore = System;
291 type ReserveIdentifier = [u8; 8];
292 type FreezeIdentifier = ();
293 type MaxLocks = ();
294 type MaxReserves = ();
295 type MaxFreezes = ();
296 type RuntimeHoldReason = RuntimeHoldReason;
297 type RuntimeFreezeReason = RuntimeFreezeReason;
298 type DoneSlashHandler = ();
299 }
300
301 impl $crate::pallet_timestamp::Config for $runtime {
302 type Moment = u64;
303 type OnTimestampSet = ();
304 type MinimumPeriod = ConstU64<1>;
305 type WeightInfo = ();
306 }
307
308 pub type TrustBackedAssetsInstance = $crate::pallet_assets::Instance1;
310 pub type AssetIdForTrustBackedAssets = u32;
311
312 impl $crate::pallet_assets::Config<TrustBackedAssetsInstance> for $runtime {
313 type RuntimeEvent = RuntimeEvent;
314 type Balance = Balance;
315 type AssetId = AssetIdForTrustBackedAssets;
316 type AssetIdParameter = $crate::scale::Compact<AssetIdForTrustBackedAssets>;
317 type Currency = Balances;
318 type CreateOrigin = $crate::frame_support::traits::AsEnsureOriginWithArg<$crate::frame_system::EnsureSigned<AccountId32>>;
319 type ForceOrigin = $crate::frame_system::EnsureRoot<AccountId32>;
320 type AssetDeposit = ConstU128<1>;
321 type AssetAccountDeposit = ConstU128<1>;
322 type MetadataDepositBase = ConstU128<1>;
323 type MetadataDepositPerByte = ConstU128<1>;
324 type ApprovalDeposit = ConstU128<1>;
325 type StringLimit = ConstU32<50>;
326 type Freezer = ();
327 type Holder = ();
328 type Extra = ();
329 type WeightInfo = ();
330 type CallbackHandle = $crate::pallet_assets::AutoIncAssetId<$runtime, TrustBackedAssetsInstance>;
331 type RemoveItemsLimit = ConstU32<1000>;
332 }
333
334 impl $crate::pallet_transaction_payment::Config for $runtime {
335 type RuntimeEvent = RuntimeEvent;
336 type OnChargeTransaction = FungibleAdapter<Balances, ()>;
337 type OperationalFeeMultiplier = ConstU8<5>;
338 type WeightToFee = $crate::pallet_revive::evm::fees::BlockRatioFee<1, 1, Self>;
339 type LengthToFee = IdentityFee<Balance>;
340 type FeeMultiplierUpdate = ();
341 type WeightInfo = $crate::pallet_transaction_payment::weights::SubstrateWeight<$runtime>;
342 }
343
344 type BalanceOf = <Balances as Currency<AccountId32>>::Balance;
346 impl Convert<Weight, BalanceOf> for $runtime {
347 fn convert(w: Weight) -> BalanceOf {
348 w.ref_time().into()
349 }
350 }
351
352 const UNIT: Balance = 1_000_000_000_000;
354 const MILLIUNIT: Balance = 1_000_000_000;
355
356 const fn deposit(items: u32, bytes: u32) -> Balance {
357 (items as Balance * UNIT + (bytes as Balance) * (5 * MILLIUNIT / 100)) / 10
358 }
359
360 parameter_types! {
361 pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
362 pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(1,2);
363 pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
364 }
365
366 impl $crate::pallet_revive::Config for $runtime {
367 type AddressMapper = $crate::pallet_revive::AccountId32Mapper<Self>;
368 type ChainId = ConstU64<1>;
369 type NativeToEthRatio = ConstU32<100_000_000>;
370 type Time = Timestamp;
371 type Balance = Balance;
372 type Currency = Balances;
373 type RuntimeEvent = RuntimeEvent;
374 type RuntimeCall = RuntimeCall;
375 type RuntimeOrigin = RuntimeOrigin;
376 type DepositPerItem = ConstU128<1>;
377 type DepositPerChildTrieItem = DepositPerChildTrieItem;
378 type DepositPerByte = ConstU128<1>;
379 type WeightInfo = ();
380 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
381 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
382 type UnsafeUnstableInterface = ConstBool<true>;
383 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
384 type RuntimeHoldReason = RuntimeHoldReason;
385 type UploadOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
386 type InstantiateOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
387 type FindAuthor = ();
388 type Precompiles = (
389 $crate::pallet_assets_precompiles::ERC20<Self, $crate::pallet_assets_precompiles::InlineIdConfig<{ 0x0120 }>, TrustBackedAssetsInstance>,
390 );
392 type AllowEVMBytecode = ConstBool<false>;
393 type FeeInfo = ();
394 type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
395 type DebugEnabled = ConstBool<false>;
396 }
397
398 pub const INITIAL_BALANCE: u128 = 1_000_000_000_000_000;
400 pub const DEFAULT_ACCOUNT: AccountId32 = AccountId32::new([1u8; 32]);
401
402 pub struct $sandbox {
403 ext: $crate::TestExternalities,
404 }
405
406 impl ::std::default::Default for $sandbox {
407 fn default() -> Self {
408 let ext = $crate::macros::BlockBuilder::<$runtime>::new_ext(vec![(
409 DEFAULT_ACCOUNT,
410 INITIAL_BALANCE,
411 )]);
412 Self { ext }
413 }
414 }
415
416 impl $crate::Sandbox for $sandbox {
418 type Runtime = $runtime;
419
420 fn execute_with<T>(&mut self, execute: impl FnOnce() -> T) -> T {
421 self.ext.execute_with(execute)
422 }
423
424 fn dry_run<T>(&mut self, action: impl FnOnce(&mut Self) -> T) -> T {
425 let backend_backup = self.ext.as_backend();
427 let result = action(self);
430 self.ext.commit_all().expect("Failed to commit changes");
431
432 self.ext.backend = backend_backup;
434 result
435 }
436
437 fn register_extension<E: ::core::any::Any + $crate::Extension>(&mut self, ext: E) {
438 self.ext.register_extension(ext);
439 }
440
441 fn initialize_block(
442 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
443 parent_hash: <Self::Runtime as $crate::frame_system::Config>::Hash,
444 ) {
445 $crate::macros::BlockBuilder::<Self::Runtime>::initialize_block(height, parent_hash)
446 }
447
448 fn finalize_block(
449 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
450 ) -> <Self::Runtime as $crate::frame_system::Config>::Hash {
451 $crate::macros::BlockBuilder::<Self::Runtime>::finalize_block(height)
452 }
453
454 fn default_actor() -> $crate::AccountIdFor<Self::Runtime> {
455 DEFAULT_ACCOUNT
456 }
457
458 fn get_metadata() -> $crate::RuntimeMetadataPrefixed {
459 Self::Runtime::metadata()
460 }
461
462 fn convert_account_to_origin(
463 account: $crate::AccountIdFor<Self::Runtime>,
464 ) -> <<Self::Runtime as $crate::frame_system::Config>::RuntimeCall as $crate::frame_support::sp_runtime::traits::Dispatchable>::RuntimeOrigin {
465 Some(account).into()
466 }
467
468 fn take_snapshot(&mut self) -> Snapshot {
469 let mut backend = self.ext.as_backend().clone();
470 let raw_key_values = backend
471 .backend_storage_mut()
472 .drain()
473 .into_iter()
474 .filter(|(_, (_, r))| *r > 0)
475 .collect::<Vec<(Vec<u8>, (Vec<u8>, i32))>>();
476 let root = backend.root().to_owned();
477 Snapshot {
478 storage: raw_key_values,
479 storage_root: root,
480 }
481 }
482
483 fn restore_snapshot(&mut self, snapshot: Snapshot) {
484 self.ext = $crate::TestExternalities::from_raw_snapshot(
485 snapshot.storage,
486 snapshot.storage_root,
487 Default::default(),
488 );
489 }
490 }
491}
492
493pub use construct_runtime::{
495 $sandbox, $runtime, Assets, AssetIdForTrustBackedAssets, Balances, Revive, PalletInfo,
496 RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, System, Timestamp,
497 TrustBackedAssetsInstance,
498};
499 };
500}
501
502create_sandbox!(DefaultSandbox);