1use std::time::SystemTime;
2
3use frame_support::{
4 sp_runtime::{
5 traits::{
6 Header,
7 One,
8 },
9 BuildStorage,
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(balances: Vec<(T::AccountId, T::Balance)>) -> TestExternalities {
27 let mut storage = frame_system::GenesisConfig::<T>::default()
28 .build_storage()
29 .unwrap();
30
31 pallet_balances::GenesisConfig::<T> {
32 balances,
33 dev_accounts: None,
34 }
35 .assimilate_storage(&mut storage)
36 .unwrap();
37
38 let mut ext = TestExternalities::new(storage);
39
40 ext.execute_with(|| {
41 Self::initialize_block(BlockNumberFor::<T>::one(), Default::default())
42 });
43 ext
44 }
45
46 pub fn initialize_block(
48 height: frame_system::pallet_prelude::BlockNumberFor<T>,
49 parent_hash: <T as frame_system::Config>::Hash,
50 ) {
51 frame_system::Pallet::<T>::reset_events();
52 frame_system::Pallet::<T>::initialize(&height, &parent_hash, &Default::default());
53 pallet_balances::Pallet::<T>::on_initialize(height);
54 pallet_timestamp::Pallet::<T>::set_timestamp(
55 SystemTime::now()
56 .duration_since(SystemTime::UNIX_EPOCH)
57 .expect("Time went backwards")
58 .as_secs(),
59 );
60 pallet_timestamp::Pallet::<T>::on_initialize(height);
61 pallet_revive::Pallet::<T>::on_initialize(height);
62 frame_system::Pallet::<T>::note_finished_initialize();
63 }
64
65 pub fn finalize_block(
67 height: frame_system::pallet_prelude::BlockNumberFor<T>,
68 ) -> <T as frame_system::Config>::Hash {
69 pallet_revive::Pallet::<T>::on_finalize(height);
70 use sp_core::Get;
71 let minimum_period = <T as pallet_timestamp::Config>::MinimumPeriod::get();
72 let now = pallet_timestamp::Pallet::<T>::get()
73 .checked_add(minimum_period)
74 .unwrap();
75 pallet_timestamp::Pallet::<T>::set_timestamp(now);
76 pallet_timestamp::Pallet::<T>::on_finalize(height);
77 pallet_balances::Pallet::<T>::on_finalize(height);
78 frame_system::Pallet::<T>::finalize().hash()
79 }
80}
81
82#[macro_export]
87macro_rules! create_sandbox {
88 ($name:ident) => {
89 $crate::paste::paste! {
90 $crate::create_sandbox!($name, [<$name Runtime>], (), (), {});
91 }
92 };
93 ($name:ident, $chain_extension: ty, $debug: ty) => {
94 $crate::paste::paste! {
95 $crate::create_sandbox!($name, [<$name Runtime>], $chain_extension, $debug, {});
96 }
97 };
98 ($name:ident, $chain_extension: ty, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
99 $crate::paste::paste! {
100 $crate::create_sandbox!($name, [<$name Runtime>], $chain_extension, $debug, {
101 $(
102 $pallet_name : $pallet,
103 )*
104 });
105 }
106 };
107 ($sandbox:ident, $runtime:ident, $chain_extension: ty, $debug: ty, { $( $pallet_name:tt : $pallet:ident ),* $(,)? }) => {
108
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 },
122 traits::{ConstBool, ConstU128, ConstU32, ConstU64, Currency},
123 weights::Weight,
124 };
125
126 use $crate::Snapshot;
127
128 construct_runtime!(
130 pub enum $runtime {
131 System: $crate::frame_system,
132 Balances: $crate::pallet_balances,
133 Timestamp: $crate::pallet_timestamp,
134 Revive: $crate::pallet_revive,
135 $(
136 $pallet_name: $pallet,
137 )*
138 }
139 );
140
141 #[derive_impl($crate::frame_system::config_preludes::SolochainDefaultConfig as $crate::frame_system::DefaultConfig)]
143 impl $crate::frame_system::Config for $runtime {
144 type Block = $crate::frame_system::mocking::MockBlockU32<$runtime>;
145 type Version = ();
146 type BlockHashCount = ConstU32<250>;
147 type AccountData = $crate::pallet_balances::AccountData<<$runtime as $crate::pallet_balances::Config>::Balance>;
148 }
149
150 impl $crate::pallet_balances::Config for $runtime {
152 type RuntimeEvent = RuntimeEvent;
153 type WeightInfo = ();
154 type Balance = u128;
155 type DustRemoval = ();
156 type ExistentialDeposit = ConstU128<1>;
157 type AccountStore = System;
158 type ReserveIdentifier = [u8; 8];
159 type FreezeIdentifier = ();
160 type MaxLocks = ();
161 type MaxReserves = ();
162 type MaxFreezes = ();
163 type RuntimeHoldReason = RuntimeHoldReason;
164 type RuntimeFreezeReason = RuntimeFreezeReason;
165 type DoneSlashHandler = ();
166 }
167
168 impl $crate::pallet_timestamp::Config for $runtime {
170 type Moment = u64;
171 type OnTimestampSet = ();
172 type MinimumPeriod = ConstU64<1>;
173 type WeightInfo = ();
174 }
175
176 type BalanceOf = <Balances as Currency<AccountId32>>::Balance;
178 impl Convert<Weight, BalanceOf> for $runtime {
179 fn convert(w: Weight) -> BalanceOf {
180 w.ref_time().into()
181 }
182 }
183
184 parameter_types! {
185 pub DeletionWeightLimit: Weight = Weight::zero();
187 pub DefaultDepositLimit: BalanceOf = 10_000_000;
188 pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
189 pub MaxDelegateDependencies: u32 = 32;
190 }
191
192 impl $crate::pallet_revive::Config for $runtime {
193 type AddressMapper = $crate::pallet_revive::AccountId32Mapper<Self>;
194 type ChainId = ConstU64<1>; type NativeToEthRatio = ConstU32<100_000_000>;
196 type Time = Timestamp;
197 type Currency = Balances;
198 type RuntimeEvent = RuntimeEvent;
199 type RuntimeCall = RuntimeCall;
200 type DepositPerItem = ConstU128<1>;
201 type DepositPerByte = ConstU128<1>;
202 type WeightPrice = Self;
203 type WeightInfo = ();
204 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
207 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
208 type UnsafeUnstableInterface = ConstBool<true>;
209 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
210 type RuntimeHoldReason = RuntimeHoldReason;
211 type UploadOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
212 type InstantiateOrigin = $crate::frame_system::EnsureSigned<Self::AccountId>;
213 type EthGasEncoder = ();
214 type FindAuthor = ();
215 type Precompiles = (
216 );
221 }
222
223 pub const INITIAL_BALANCE: u128 = 1_000_000_000_000_000;
227 pub const DEFAULT_ACCOUNT: AccountId32 = AccountId32::new([1u8; 32]);
228
229 pub struct $sandbox {
230 ext: $crate::TestExternalities,
231 }
232
233 impl ::std::default::Default for $sandbox {
234 fn default() -> Self {
235 let ext = $crate::macros::BlockBuilder::<$runtime>::new_ext(vec![(
236 DEFAULT_ACCOUNT,
237 INITIAL_BALANCE,
238 )]);
239 Self { ext }
240 }
241 }
242
243 impl $crate::Sandbox for $sandbox {
244 type Runtime = $runtime;
245
246 fn execute_with<T>(&mut self, execute: impl FnOnce() -> T) -> T {
247 self.ext.execute_with(execute)
248 }
249
250 fn dry_run<T>(&mut self, action: impl FnOnce(&mut Self) -> T) -> T {
251 let backend_backup = self.ext.as_backend();
253 let result = action(self);
256 self.ext.commit_all().expect("Failed to commit changes");
257
258 self.ext.backend = backend_backup;
260 result
261 }
262
263 fn register_extension<E: ::core::any::Any + $crate::Extension>(&mut self, ext: E) {
264 self.ext.register_extension(ext);
265 }
266
267 fn initialize_block(
268 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
269 parent_hash: <Self::Runtime as $crate::frame_system::Config>::Hash,
270 ) {
271 $crate::macros::BlockBuilder::<Self::Runtime>::initialize_block(height, parent_hash)
272 }
273
274 fn finalize_block(
275 height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Runtime>,
276 ) -> <Self::Runtime as $crate::frame_system::Config>::Hash {
277 $crate::macros::BlockBuilder::<Self::Runtime>::finalize_block(height)
278 }
279
280 fn default_actor() -> $crate::AccountIdFor<Self::Runtime> {
281 DEFAULT_ACCOUNT
282 }
283
284 fn get_metadata() -> $crate::RuntimeMetadataPrefixed {
285 Self::Runtime::metadata()
286 }
287
288 fn convert_account_to_origin(
289 account: $crate::AccountIdFor<Self::Runtime>,
290 ) -> <<Self::Runtime as $crate::frame_system::Config>::RuntimeCall as $crate::frame_support::sp_runtime::traits::Dispatchable>::RuntimeOrigin {
291 Some(account).into()
292 }
293
294 fn take_snapshot(&mut self) -> Snapshot {
295 let mut backend = self.ext.as_backend().clone();
296 let raw_key_values = backend
297 .backend_storage_mut()
298 .drain()
299 .into_iter()
300 .filter(|(_, (_, r))| *r > 0)
301 .collect::<Vec<(Vec<u8>, (Vec<u8>, i32))>>();
302 let root = backend.root().to_owned();
303 Snapshot {
304 storage: raw_key_values,
305 storage_root: root,
306 }
307 }
308
309 fn restore_snapshot(&mut self, snapshot: Snapshot) {
310 self.ext = $crate::TestExternalities::from_raw_snapshot(
311 snapshot.storage,
312 snapshot.storage_root,
313 Default::default(),
314 );
315 }
316 }
317}
318
319pub use construct_runtime::{
321 $sandbox, $runtime, Balances, Revive, PalletInfo, RuntimeCall, RuntimeEvent, RuntimeHoldReason,
322 RuntimeOrigin, System, Timestamp,
323};
324 };
325}
326
327create_sandbox!(DefaultSandbox);