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
16pub struct BlockBuilder<T>(std::marker::PhantomData<T>);
18
19impl<
20 T: pallet_balances::Config
21 + pallet_timestamp::Config<Moment = u64>
22 + pallet_revive::Config,
23> BlockBuilder<T>
24{
25 pub fn new_ext(
27 balances: Vec<(T::AccountId, <T as pallet_balances::Config>::Balance)>,
28 ) -> TestExternalities {
29 let mut storage = frame_system::GenesisConfig::<T>::default()
30 .build_storage()
31 .unwrap();
32
33 pallet_balances::GenesisConfig::<T> {
34 balances,
35 dev_accounts: None,
36 }
37 .assimilate_storage(&mut storage)
38 .unwrap();
39
40 let mut ext = TestExternalities::new(storage);
41
42 ext.execute_with(|| {
43 Self::initialize_block(BlockNumberFor::<T>::one(), Default::default())
44 });
45 ext
46 }
47
48 pub fn initialize_block(
50 height: frame_system::pallet_prelude::BlockNumberFor<T>,
51 parent_hash: <T as frame_system::Config>::Hash,
52 ) {
53 frame_system::Pallet::<T>::reset_events();
54 frame_system::Pallet::<T>::initialize(&height, &parent_hash, &Default::default());
55 pallet_balances::Pallet::<T>::on_initialize(height);
56 pallet_timestamp::Pallet::<T>::set_timestamp(
57 SystemTime::now()
58 .duration_since(SystemTime::UNIX_EPOCH)
59 .expect("Time went backwards")
60 .as_secs(),
61 );
62 pallet_timestamp::Pallet::<T>::on_initialize(height);
63 pallet_revive::Pallet::<T>::on_initialize(height);
64 frame_system::Pallet::<T>::note_finished_initialize();
65 }
66
67 pub fn finalize_block(
69 height: frame_system::pallet_prelude::BlockNumberFor<T>,
70 ) -> <T as frame_system::Config>::Hash {
71 pallet_revive::Pallet::<T>::on_finalize(height);
72 use sp_core::Get;
73 let minimum_period = <T as pallet_timestamp::Config>::MinimumPeriod::get();
74 let now = pallet_timestamp::Pallet::<T>::get()
75 .checked_add(minimum_period)
76 .unwrap();
77 pallet_timestamp::Pallet::<T>::set_timestamp(now);
78 pallet_timestamp::Pallet::<T>::on_finalize(height);
79 pallet_balances::Pallet::<T>::on_finalize(height);
80 frame_system::Pallet::<T>::finalize().hash()
81 }
82}
83
84#[macro_export]
88macro_rules! create_sandbox {
89 ($name:ident) => {
90 $crate::paste::paste! {
91 $crate::create_sandbox!($name, [<$name Runtime>], (), {});
92 }
93 };
94 ($name:ident, $debug: ty) => {
95 $crate::paste::paste! {
96 $crate::create_sandbox!($name, [<$name Runtime>], $debug, {});
97 }
98 };
99 ($name:ident, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
100 $crate::paste::paste! {
101 $crate::create_sandbox!($name, [<$name Runtime>], $debug, {
102 $(
103 $pallet_name : $pallet,
104 )*
105 });
106 }
107 };
108 ($sandbox:ident, $runtime:ident, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
109
110mod construct_runtime {
112
113 use $crate::frame_support::{
115 construct_runtime,
116 derive_impl,
117 parameter_types,
118 sp_runtime::{
119 traits::Convert,
120 AccountId32, Perbill,
121 FixedU128,
122 },
123 traits::{ConstBool, ConstU8, ConstU128, ConstU32, ConstU64, Currency},
124 weights::{Weight, IdentityFee},
125 };
126
127 use $crate::pallet_transaction_payment::{FungibleAdapter};
128
129 use $crate::Snapshot;
130
131 pub type Balance = u128;
132
133 construct_runtime!(
135 pub enum $runtime {
136 System: $crate::frame_system,
137 Balances: $crate::pallet_balances,
138 Timestamp: $crate::pallet_timestamp,
139 Revive: $crate::pallet_revive,
140 TransactionPayment: $crate::pallet_transaction_payment,
141 $(
142 $pallet_name: $pallet,
143 )*
144 }
145 );
146
147 #[derive_impl($crate::frame_system::config_preludes::SolochainDefaultConfig as $crate::frame_system::DefaultConfig)]
148 impl $crate::frame_system::Config for $runtime {
149 type Block = $crate::frame_system::mocking::MockBlockU32<$runtime>;
150 type Version = ();
151 type BlockHashCount = ConstU32<250>;
152 type AccountData = $crate::pallet_balances::AccountData<<$runtime as $crate::pallet_balances::Config>::Balance>;
153 }
154
155 impl $crate::pallet_balances::Config for $runtime {
156 type RuntimeEvent = RuntimeEvent;
157 type WeightInfo = ();
158 type Balance = Balance;
159 type DustRemoval = ();
160 type ExistentialDeposit = ConstU128<1>;
161 type AccountStore = System;
162 type ReserveIdentifier = [u8; 8];
163 type FreezeIdentifier = ();
164 type MaxLocks = ();
165 type MaxReserves = ();
166 type MaxFreezes = ();
167 type RuntimeHoldReason = RuntimeHoldReason;
168 type RuntimeFreezeReason = RuntimeFreezeReason;
169 type DoneSlashHandler = ();
170 }
171
172 impl $crate::pallet_timestamp::Config for $runtime {
173 type Moment = u64;
174 type OnTimestampSet = ();
175 type MinimumPeriod = ConstU64<1>;
176 type WeightInfo = ();
177 }
178
179 impl $crate::pallet_transaction_payment::Config for $runtime {
180 type RuntimeEvent = RuntimeEvent;
181 type OnChargeTransaction = FungibleAdapter<Balances, ()>;
182 type OperationalFeeMultiplier = ConstU8<5>;
183 type WeightToFee = $crate::pallet_revive::evm::fees::BlockRatioFee<1, 1, Self>;
184 type LengthToFee = IdentityFee<Balance>;
185 type FeeMultiplierUpdate = ();
186 type WeightInfo = $crate::pallet_transaction_payment::weights::SubstrateWeight<$runtime>;
187 }
188
189 type BalanceOf = <Balances as Currency<AccountId32>>::Balance;
191 impl Convert<Weight, BalanceOf> for $runtime {
192 fn convert(w: Weight) -> BalanceOf {
193 w.ref_time().into()
194 }
195 }
196
197 const UNIT: Balance = 1_000_000_000_000;
199 const MILLIUNIT: Balance = 1_000_000_000;
200
201 const fn deposit(items: u32, bytes: u32) -> Balance {
202 (items as Balance * UNIT + (bytes as Balance) * (5 * MILLIUNIT / 100)) / 10
203 }
204
205 parameter_types! {
206 pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
207 pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(1,2);
208 pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
209 }
210
211 impl $crate::pallet_revive::Config for $runtime {
212 type AddressMapper = $crate::pallet_revive::AccountId32Mapper<Self>;
213 type ChainId = ConstU64<1>;
214 type NativeToEthRatio = ConstU32<100_000_000>;
215 type Time = Timestamp;
216 type Balance = Balance;
217 type Currency = Balances;
218 type RuntimeEvent = RuntimeEvent;
219 type RuntimeCall = RuntimeCall;
220 type RuntimeOrigin = RuntimeOrigin;
221 type DepositPerItem = ConstU128<1>;
222 type DepositPerChildTrieItem = DepositPerChildTrieItem;
223 type DepositPerByte = ConstU128<1>;
224 type WeightInfo = ();
225 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
226 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
227 type UnsafeUnstableInterface = ConstBool<true>;
228 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
229 type RuntimeHoldReason = RuntimeHoldReason;
230 type UploadOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
231 type InstantiateOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
232 type FindAuthor = ();
233 type Precompiles = (
234 );
239 type AllowEVMBytecode = ConstBool<false>;
240 type FeeInfo = ();
241 type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
242 type DebugEnabled = ConstBool<false>;
243 }
244
245 pub const INITIAL_BALANCE: u128 = 1_000_000_000_000_000;
247 pub const DEFAULT_ACCOUNT: AccountId32 = AccountId32::new([1u8; 32]);
248
249 pub struct $sandbox {
250 ext: $crate::TestExternalities,
251 }
252
253 impl ::std::default::Default for $sandbox {
254 fn default() -> Self {
255 let ext = $crate::macros::BlockBuilder::<$runtime>::new_ext(vec![(
256 DEFAULT_ACCOUNT,
257 INITIAL_BALANCE,
258 )]);
259 Self { ext }
260 }
261 }
262
263 impl $crate::Sandbox for $sandbox {
265 type Runtime = $runtime;
266
267 fn execute_with<T>(&mut self, execute: impl FnOnce() -> T) -> T {
268 self.ext.execute_with(execute)
269 }
270
271 fn dry_run<T>(&mut self, action: impl FnOnce(&mut Self) -> T) -> T {
272 let backend_backup = self.ext.as_backend();
274 let result = action(self);
277 self.ext.commit_all().expect("Failed to commit changes");
278
279 self.ext.backend = backend_backup;
281 result
282 }
283
284 fn register_extension<E: ::core::any::Any + $crate::Extension>(&mut self, ext: E) {
285 self.ext.register_extension(ext);
286 }
287
288 fn initialize_block(
289 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
290 parent_hash: <Self::Runtime as $crate::frame_system::Config>::Hash,
291 ) {
292 $crate::macros::BlockBuilder::<Self::Runtime>::initialize_block(height, parent_hash)
293 }
294
295 fn finalize_block(
296 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
297 ) -> <Self::Runtime as $crate::frame_system::Config>::Hash {
298 $crate::macros::BlockBuilder::<Self::Runtime>::finalize_block(height)
299 }
300
301 fn default_actor() -> $crate::AccountIdFor<Self::Runtime> {
302 DEFAULT_ACCOUNT
303 }
304
305 fn get_metadata() -> $crate::RuntimeMetadataPrefixed {
306 Self::Runtime::metadata()
307 }
308
309 fn convert_account_to_origin(
310 account: $crate::AccountIdFor<Self::Runtime>,
311 ) -> <<Self::Runtime as $crate::frame_system::Config>::RuntimeCall as $crate::frame_support::sp_runtime::traits::Dispatchable>::RuntimeOrigin {
312 Some(account).into()
313 }
314
315 fn take_snapshot(&mut self) -> Snapshot {
316 let mut backend = self.ext.as_backend().clone();
317 let raw_key_values = backend
318 .backend_storage_mut()
319 .drain()
320 .into_iter()
321 .filter(|(_, (_, r))| *r > 0)
322 .collect::<Vec<(Vec<u8>, (Vec<u8>, i32))>>();
323 let root = backend.root().to_owned();
324 Snapshot {
325 storage: raw_key_values,
326 storage_root: root,
327 }
328 }
329
330 fn restore_snapshot(&mut self, snapshot: Snapshot) {
331 self.ext = $crate::TestExternalities::from_raw_snapshot(
332 snapshot.storage,
333 snapshot.storage_root,
334 Default::default(),
335 );
336 }
337 }
338}
339
340pub use construct_runtime::{
342 $sandbox, $runtime, Balances, Revive, PalletInfo, RuntimeCall, RuntimeEvent, RuntimeHoldReason,
343 RuntimeOrigin, System, Timestamp,
344};
345 };
346}
347
348create_sandbox!(DefaultSandbox);