1#![doc = include_str!("../README.md")]
19#![allow(rustdoc::private_intra_doc_links)]
20#![cfg_attr(not(feature = "std"), no_std)]
21#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")]
22
23extern crate alloc;
24
25mod address;
26mod benchmarking;
27mod call_builder;
28mod exec;
29mod gas;
30mod impl_fungibles;
31mod limits;
32mod primitives;
33mod storage;
34#[cfg(test)]
35mod tests;
36mod transient_storage;
37mod wasm;
38
39pub mod evm;
40pub mod precompiles;
41pub mod test_utils;
42pub mod tracing;
43pub mod weights;
44
45use crate::{
46 evm::{
47 runtime::GAS_PRICE, CallTracer, GasEncoder, GenericTransaction, Trace, Tracer, TracerType,
48 TYPE_EIP1559,
49 },
50 exec::{AccountIdOf, ExecError, Executable, Key, Stack as ExecStack},
51 gas::GasMeter,
52 storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
53 wasm::{CodeInfo, RuntimeCosts, WasmBlob},
54};
55use alloc::{boxed::Box, format, vec};
56use codec::{Codec, Decode, Encode};
57use environmental::*;
58use frame_support::{
59 dispatch::{
60 DispatchErrorWithPostInfo, DispatchResultWithPostInfo, GetDispatchInfo, Pays,
61 PostDispatchInfo, RawOrigin,
62 },
63 ensure,
64 pallet_prelude::DispatchClass,
65 traits::{
66 fungible::{Inspect, Mutate, MutateHold},
67 tokens::{Fortitude::Polite, Preservation::Preserve},
68 ConstU32, ConstU64, EnsureOrigin, Get, IsType, OriginTrait, Time,
69 },
70 weights::WeightMeter,
71 BoundedVec, RuntimeDebugNoBound,
72};
73use frame_system::{
74 ensure_signed,
75 pallet_prelude::{BlockNumberFor, OriginFor},
76 Pallet as System,
77};
78use scale_info::TypeInfo;
79use sp_runtime::{
80 traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating, Zero},
81 AccountId32, DispatchError,
82};
83
84pub use crate::{
85 address::{
86 create1, create2, is_eth_derived, AccountId32Mapper, AddressMapper, TestAccountMapper,
87 },
88 exec::{MomentOf, Origin},
89 pallet::*,
90};
91pub use codec;
92pub use frame_support::{self, dispatch::DispatchInfo, weights::Weight};
93pub use frame_system::{self, limits::BlockWeights};
94pub use pallet_transaction_payment;
95pub use primitives::*;
96pub use sp_core::{H160, H256, U256};
97pub use sp_runtime;
98pub use weights::WeightInfo;
99
100#[cfg(doc)]
101pub use crate::wasm::SyscallDoc;
102
103pub type BalanceOf<T> =
104 <<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
105type TrieId = BoundedVec<u8, ConstU32<128>>;
106type CodeVec = BoundedVec<u8, ConstU32<{ limits::code::BLOB_BYTES }>>;
107type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
108
109const SENTINEL: u32 = u32::MAX;
116
117const LOG_TARGET: &str = "runtime::revive";
123
124#[frame_support::pallet]
125pub mod pallet {
126 use super::*;
127 use frame_support::{pallet_prelude::*, traits::FindAuthor};
128 use frame_system::pallet_prelude::*;
129 use sp_core::U256;
130 use sp_runtime::Perbill;
131
132 pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
134
135 #[pallet::pallet]
136 #[pallet::storage_version(STORAGE_VERSION)]
137 pub struct Pallet<T>(_);
138
139 #[pallet::config(with_default)]
140 pub trait Config: frame_system::Config {
141 type Time: Time;
143
144 #[pallet::no_default]
146 type Currency: Inspect<Self::AccountId>
147 + Mutate<Self::AccountId>
148 + MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>;
149
150 #[pallet::no_default_bounds]
152 #[allow(deprecated)]
153 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
154
155 #[pallet::no_default_bounds]
157 type RuntimeCall: Parameter
158 + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
159 + GetDispatchInfo;
160
161 #[pallet::no_default_bounds]
163 type RuntimeHoldReason: From<HoldReason>;
164
165 #[pallet::no_default_bounds]
168 type WeightPrice: Convert<Weight, BalanceOf<Self>>;
169
170 type WeightInfo: WeightInfo;
173
174 #[pallet::no_default_bounds]
178 #[allow(private_bounds)]
179 type Precompiles: precompiles::Precompiles<Self>;
180
181 type FindAuthor: FindAuthor<Self::AccountId>;
183
184 #[pallet::constant]
190 #[pallet::no_default_bounds]
191 type DepositPerByte: Get<BalanceOf<Self>>;
192
193 #[pallet::constant]
199 #[pallet::no_default_bounds]
200 type DepositPerItem: Get<BalanceOf<Self>>;
201
202 #[pallet::constant]
206 type CodeHashLockupDepositPercent: Get<Perbill>;
207
208 #[pallet::no_default]
210 type AddressMapper: AddressMapper<Self>;
211
212 #[pallet::constant]
222 type UnsafeUnstableInterface: Get<bool>;
223
224 #[pallet::no_default_bounds]
229 type UploadOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
230
231 #[pallet::no_default_bounds]
242 type InstantiateOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
243
244 type RuntimeMemory: Get<u32>;
249
250 type PVFMemory: Get<u32>;
258
259 #[pallet::constant]
264 type ChainId: Get<u64>;
265
266 #[pallet::constant]
268 type NativeToEthRatio: Get<u32>;
269
270 #[pallet::no_default_bounds]
273 type EthGasEncoder: GasEncoder<BalanceOf<Self>>;
274 }
275
276 pub mod config_preludes {
278 use super::*;
279 use frame_support::{
280 derive_impl,
281 traits::{ConstBool, ConstU32},
282 };
283 use frame_system::EnsureSigned;
284 use sp_core::parameter_types;
285
286 type Balance = u64;
287 const UNITS: Balance = 10_000_000_000;
288 const CENTS: Balance = UNITS / 100;
289
290 pub const fn deposit(items: u32, bytes: u32) -> Balance {
291 items as Balance * 1 * CENTS + (bytes as Balance) * 1 * CENTS
292 }
293
294 parameter_types! {
295 pub const DepositPerItem: Balance = deposit(1, 0);
296 pub const DepositPerByte: Balance = deposit(0, 1);
297 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
298 }
299
300 pub struct TestDefaultConfig;
302
303 impl Time for TestDefaultConfig {
304 type Moment = u64;
305 fn now() -> Self::Moment {
306 0u64
307 }
308 }
309
310 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
311 fn convert(w: Weight) -> T {
312 w.ref_time().into()
313 }
314 }
315
316 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
317 impl frame_system::DefaultConfig for TestDefaultConfig {}
318
319 #[frame_support::register_default_impl(TestDefaultConfig)]
320 impl DefaultConfig for TestDefaultConfig {
321 #[inject_runtime_type]
322 type RuntimeEvent = ();
323
324 #[inject_runtime_type]
325 type RuntimeHoldReason = ();
326
327 #[inject_runtime_type]
328 type RuntimeCall = ();
329 type Precompiles = ();
330 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
331 type DepositPerByte = DepositPerByte;
332 type DepositPerItem = DepositPerItem;
333 type Time = Self;
334 type UnsafeUnstableInterface = ConstBool<true>;
335 type UploadOrigin = EnsureSigned<Self::AccountId>;
336 type InstantiateOrigin = EnsureSigned<Self::AccountId>;
337 type WeightInfo = ();
338 type WeightPrice = Self;
339 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
340 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
341 type ChainId = ConstU64<42>;
342 type NativeToEthRatio = ConstU32<1>;
343 type EthGasEncoder = ();
344 type FindAuthor = ();
345 }
346 }
347
348 #[pallet::event]
349 pub enum Event<T: Config> {
350 ContractEmitted {
352 contract: H160,
354 data: Vec<u8>,
357 topics: Vec<H256>,
360 },
361 }
362
363 #[pallet::error]
364 #[repr(u8)]
365 pub enum Error<T> {
366 InvalidSchedule = 0x01,
368 InvalidCallFlags = 0x02,
370 OutOfGas = 0x03,
372 TransferFailed = 0x04,
375 MaxCallDepthReached = 0x05,
378 ContractNotFound = 0x06,
380 CodeNotFound = 0x07,
382 CodeInfoNotFound = 0x08,
384 OutOfBounds = 0x09,
386 DecodingFailed = 0x0A,
388 ContractTrapped = 0x0B,
390 ValueTooLarge = 0x0C,
392 TerminatedWhileReentrant = 0x0D,
395 InputForwarded = 0x0E,
397 TooManyTopics = 0x0F,
399 DuplicateContract = 0x12,
401 TerminatedInConstructor = 0x13,
405 ReentranceDenied = 0x14,
407 ReenteredPallet = 0x15,
409 StateChangeDenied = 0x16,
411 StorageDepositNotEnoughFunds = 0x17,
413 StorageDepositLimitExhausted = 0x18,
415 CodeInUse = 0x19,
417 ContractReverted = 0x1A,
422 CodeRejected = 0x1B,
427 BlobTooLarge = 0x1C,
429 StaticMemoryTooLarge = 0x1D,
432 BasicBlockTooLarge = 0x1E,
434 InvalidInstruction = 0x1F,
436 MaxDelegateDependenciesReached = 0x20,
438 DelegateDependencyNotFound = 0x21,
440 DelegateDependencyAlreadyExists = 0x22,
442 CannotAddSelfAsDelegateDependency = 0x23,
444 OutOfTransientStorage = 0x24,
446 InvalidSyscall = 0x25,
448 InvalidStorageFlags = 0x26,
450 ExecutionFailed = 0x27,
452 BalanceConversionFailed = 0x28,
454 DecimalPrecisionLoss = 0x29,
456 InvalidImmutableAccess = 0x2A,
459 AccountUnmapped = 0x2B,
463 AccountAlreadyMapped = 0x2C,
465 InvalidGenericTransaction = 0x2D,
467 RefcountOverOrUnderflow = 0x2E,
469 UnsupportedPrecompileAddress = 0x2F,
471 }
472
473 #[pallet::composite_enum]
475 pub enum HoldReason {
476 CodeUploadDepositReserve,
478 StorageDepositReserve,
480 AddressMapping,
482 }
483
484 #[pallet::storage]
486 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, CodeVec>;
487
488 #[pallet::storage]
490 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
491
492 #[pallet::storage]
494 pub(crate) type ContractInfoOf<T: Config> = StorageMap<_, Identity, H160, ContractInfo<T>>;
495
496 #[pallet::storage]
498 pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
499
500 #[pallet::storage]
505 pub(crate) type DeletionQueue<T: Config> = StorageMap<_, Twox64Concat, u32, TrieId>;
506
507 #[pallet::storage]
510 pub(crate) type DeletionQueueCounter<T: Config> =
511 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
512
513 #[pallet::storage]
520 pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
521
522 #[pallet::genesis_config]
523 #[derive(frame_support::DefaultNoBound)]
524 pub struct GenesisConfig<T: Config> {
525 pub mapped_accounts: Vec<T::AccountId>,
527 }
528
529 #[pallet::genesis_build]
530 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
531 fn build(&self) {
532 for id in &self.mapped_accounts {
533 if let Err(err) = T::AddressMapper::map(id) {
534 log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
535 }
536 }
537 }
538 }
539
540 #[pallet::hooks]
541 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
542 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
543 let mut meter = WeightMeter::with_limit(limit);
544 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
545 meter.consumed()
546 }
547
548 fn integrity_test() {
549 use limits::code::STATIC_MEMORY_BYTES;
550
551 assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
552
553 let max_runtime_mem: u32 = T::RuntimeMemory::get();
555 let max_call_depth =
557 limits::CALL_STACK_DEPTH.checked_add(1).expect("CallStack size is too big");
558 let max_transient_storage_size = limits::TRANSIENT_STORAGE_BYTES
561 .checked_mul(2)
562 .expect("MaxTransientStorageSize is too large");
563
564 const TOTAL_MEMORY_DEVIDER: u32 = 2;
567
568 const MEMORY_ALLOCATOR_INEFFICENCY_DEVIDER: u32 = 4;
572
573 let static_memory_limit = max_runtime_mem
581 .saturating_div(TOTAL_MEMORY_DEVIDER)
582 .saturating_sub(max_transient_storage_size)
583 .saturating_div(max_call_depth)
584 .saturating_sub(STATIC_MEMORY_BYTES)
585 .saturating_div(MEMORY_ALLOCATOR_INEFFICENCY_DEVIDER);
586
587 assert!(
588 STATIC_MEMORY_BYTES < static_memory_limit,
589 "Given `CallStack` height {:?}, `STATIC_MEMORY_LIMIT` should be set less than {:?} \
590 (current value is {:?}), to avoid possible runtime oom issues.",
591 max_call_depth,
592 static_memory_limit,
593 STATIC_MEMORY_BYTES,
594 );
595
596 let max_block_ref_time = T::BlockWeights::get()
602 .get(DispatchClass::Normal)
603 .max_total
604 .unwrap_or_else(|| T::BlockWeights::get().max_block)
605 .ref_time();
606 let max_payload_size = limits::PAYLOAD_BYTES;
607 let max_key_size =
608 Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
609 .expect("Key of maximal size shall be created")
610 .hash()
611 .len() as u32;
612
613 let max_immutable_key_size = T::AccountId::max_encoded_len() as u32;
614 let max_immutable_size: u32 = ((max_block_ref_time /
615 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetImmutableData(
616 limits::IMMUTABLE_BYTES,
617 ))
618 .ref_time()))
619 .saturating_mul(limits::IMMUTABLE_BYTES.saturating_add(max_immutable_key_size) as u64))
620 .try_into()
621 .expect("Immutable data size too big");
622
623 let max_storage_size: u32 = ((max_block_ref_time /
626 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
627 new_bytes: max_payload_size,
628 old_bytes: 0,
629 })
630 .ref_time()))
631 .saturating_mul(max_payload_size.saturating_add(max_key_size) as u64))
632 .saturating_add(max_immutable_size.into())
633 .try_into()
634 .expect("Storage size too big");
635
636 let max_pvf_mem: u32 = T::PVFMemory::get();
637 let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
638
639 assert!(
640 max_storage_size < storage_size_limit,
641 "Maximal storage size {} exceeds the storage limit {}",
642 max_storage_size,
643 storage_size_limit
644 );
645
646 let max_events_size: u32 = ((max_block_ref_time /
650 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
651 num_topic: 0,
652 len: max_payload_size,
653 })
654 .saturating_add(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::HostFn))
655 .ref_time()))
656 .saturating_mul(max_payload_size as u64))
657 .try_into()
658 .expect("Events size too big");
659
660 assert!(
661 max_events_size < storage_size_limit,
662 "Maximal events size {} exceeds the events limit {}",
663 max_events_size,
664 storage_size_limit
665 );
666 }
667 }
668
669 #[pallet::call]
670 impl<T: Config> Pallet<T>
671 where
672 BalanceOf<T>: Into<U256> + TryFrom<U256>,
673 MomentOf<T>: Into<U256>,
674 T::Hash: frame_support::traits::IsType<H256>,
675 {
676 #[allow(unused_variables)]
692 #[pallet::call_index(0)]
693 #[pallet::weight(Weight::MAX)]
694 pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
695 Err(frame_system::Error::CallFiltered::<T>.into())
696 }
697
698 #[pallet::call_index(1)]
715 #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))]
716 pub fn call(
717 origin: OriginFor<T>,
718 dest: H160,
719 #[pallet::compact] value: BalanceOf<T>,
720 gas_limit: Weight,
721 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
722 data: Vec<u8>,
723 ) -> DispatchResultWithPostInfo {
724 let mut output = Self::bare_call(
725 origin,
726 dest,
727 value,
728 gas_limit,
729 DepositLimit::Balance(storage_deposit_limit),
730 data,
731 );
732
733 if let Ok(return_value) = &output.result {
734 if return_value.did_revert() {
735 output.result = Err(<Error<T>>::ContractReverted.into());
736 }
737 }
738 dispatch_result(output.result, output.gas_consumed, T::WeightInfo::call())
739 }
740
741 #[pallet::call_index(2)]
747 #[pallet::weight(
748 T::WeightInfo::instantiate(data.len() as u32).saturating_add(*gas_limit)
749 )]
750 pub fn instantiate(
751 origin: OriginFor<T>,
752 #[pallet::compact] value: BalanceOf<T>,
753 gas_limit: Weight,
754 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
755 code_hash: sp_core::H256,
756 data: Vec<u8>,
757 salt: Option<[u8; 32]>,
758 ) -> DispatchResultWithPostInfo {
759 let data_len = data.len() as u32;
760 let mut output = Self::bare_instantiate(
761 origin,
762 value,
763 gas_limit,
764 DepositLimit::Balance(storage_deposit_limit),
765 Code::Existing(code_hash),
766 data,
767 salt,
768 );
769 if let Ok(retval) = &output.result {
770 if retval.result.did_revert() {
771 output.result = Err(<Error<T>>::ContractReverted.into());
772 }
773 }
774 dispatch_result(
775 output.result.map(|result| result.result),
776 output.gas_consumed,
777 T::WeightInfo::instantiate(data_len),
778 )
779 }
780
781 #[pallet::call_index(3)]
809 #[pallet::weight(
810 T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
811 .saturating_add(*gas_limit)
812 )]
813 pub fn instantiate_with_code(
814 origin: OriginFor<T>,
815 #[pallet::compact] value: BalanceOf<T>,
816 gas_limit: Weight,
817 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
818 code: Vec<u8>,
819 data: Vec<u8>,
820 salt: Option<[u8; 32]>,
821 ) -> DispatchResultWithPostInfo {
822 let code_len = code.len() as u32;
823 let data_len = data.len() as u32;
824 let mut output = Self::bare_instantiate(
825 origin,
826 value,
827 gas_limit,
828 DepositLimit::Balance(storage_deposit_limit),
829 Code::Upload(code),
830 data,
831 salt,
832 );
833 if let Ok(retval) = &output.result {
834 if retval.result.did_revert() {
835 output.result = Err(<Error<T>>::ContractReverted.into());
836 }
837 }
838 dispatch_result(
839 output.result.map(|result| result.result),
840 output.gas_consumed,
841 T::WeightInfo::instantiate_with_code(code_len, data_len),
842 )
843 }
844
845 #[pallet::call_index(4)]
858 #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))]
859 pub fn upload_code(
860 origin: OriginFor<T>,
861 code: Vec<u8>,
862 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
863 ) -> DispatchResult {
864 Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
865 }
866
867 #[pallet::call_index(5)]
872 #[pallet::weight(T::WeightInfo::remove_code())]
873 pub fn remove_code(
874 origin: OriginFor<T>,
875 code_hash: sp_core::H256,
876 ) -> DispatchResultWithPostInfo {
877 let origin = ensure_signed(origin)?;
878 <WasmBlob<T>>::remove(&origin, code_hash)?;
879 Ok(Pays::No.into())
881 }
882
883 #[pallet::call_index(6)]
894 #[pallet::weight(T::WeightInfo::set_code())]
895 pub fn set_code(
896 origin: OriginFor<T>,
897 dest: H160,
898 code_hash: sp_core::H256,
899 ) -> DispatchResult {
900 ensure_root(origin)?;
901 <ContractInfoOf<T>>::try_mutate(&dest, |contract| {
902 let contract = if let Some(contract) = contract {
903 contract
904 } else {
905 return Err(<Error<T>>::ContractNotFound.into());
906 };
907 <CodeInfo<T>>::increment_refcount(code_hash)?;
908 <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
909 contract.code_hash = code_hash;
910
911 Ok(())
912 })
913 }
914
915 #[pallet::call_index(7)]
920 #[pallet::weight(T::WeightInfo::map_account())]
921 pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
922 let origin = ensure_signed(origin)?;
923 T::AddressMapper::map(&origin)
924 }
925
926 #[pallet::call_index(8)]
931 #[pallet::weight(T::WeightInfo::unmap_account())]
932 pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
933 let origin = ensure_signed(origin)?;
934 T::AddressMapper::unmap(&origin)
935 }
936
937 #[pallet::call_index(9)]
943 #[pallet::weight({
944 let dispatch_info = call.get_dispatch_info();
945 (
946 T::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
947 dispatch_info.class
948 )
949 })]
950 pub fn dispatch_as_fallback_account(
951 origin: OriginFor<T>,
952 call: Box<<T as Config>::RuntimeCall>,
953 ) -> DispatchResultWithPostInfo {
954 let origin = ensure_signed(origin)?;
955 let unmapped_account =
956 T::AddressMapper::to_fallback_account_id(&T::AddressMapper::to_address(&origin));
957 call.dispatch(RawOrigin::Signed(unmapped_account).into())
958 }
959 }
960}
961
962fn dispatch_result<R>(
964 result: Result<R, DispatchError>,
965 gas_consumed: Weight,
966 base_weight: Weight,
967) -> DispatchResultWithPostInfo {
968 let post_info = PostDispatchInfo {
969 actual_weight: Some(gas_consumed.saturating_add(base_weight)),
970 pays_fee: Default::default(),
971 };
972
973 result
974 .map(|_| post_info)
975 .map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
976}
977
978impl<T: Config> Pallet<T>
979where
980 BalanceOf<T>: Into<U256> + TryFrom<U256> + Bounded,
981 MomentOf<T>: Into<U256>,
982 T::Hash: frame_support::traits::IsType<H256>,
983{
984 pub fn bare_call(
991 origin: OriginFor<T>,
992 dest: H160,
993 value: BalanceOf<T>,
994 gas_limit: Weight,
995 storage_deposit_limit: DepositLimit<BalanceOf<T>>,
996 data: Vec<u8>,
997 ) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
998 let mut gas_meter = GasMeter::new(gas_limit);
999 let mut storage_deposit = Default::default();
1000
1001 let try_call = || {
1002 let origin = Origin::from_runtime_origin(origin)?;
1003 let mut storage_meter = match storage_deposit_limit {
1004 DepositLimit::Balance(limit) => StorageMeter::new(limit),
1005 DepositLimit::UnsafeOnlyForDryRun =>
1006 StorageMeter::new_unchecked(BalanceOf::<T>::max_value()),
1007 };
1008 let result = ExecStack::<T, WasmBlob<T>>::run_call(
1009 origin.clone(),
1010 dest,
1011 &mut gas_meter,
1012 &mut storage_meter,
1013 Self::convert_native_to_evm(value),
1014 data,
1015 storage_deposit_limit.is_unchecked(),
1016 )?;
1017 storage_deposit = storage_meter
1018 .try_into_deposit(&origin, storage_deposit_limit.is_unchecked())
1019 .inspect_err(|err| {
1020 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1021 })?;
1022 Ok(result)
1023 };
1024 let result = Self::run_guarded(try_call);
1025 ContractResult {
1026 result: result.map_err(|r| r.error),
1027 gas_consumed: gas_meter.gas_consumed(),
1028 gas_required: gas_meter.gas_required(),
1029 storage_deposit,
1030 }
1031 }
1032
1033 pub fn prepare_dry_run(account: &T::AccountId) {
1039 frame_system::Pallet::<T>::inc_account_nonce(account);
1042 }
1043
1044 pub fn bare_instantiate(
1050 origin: OriginFor<T>,
1051 value: BalanceOf<T>,
1052 gas_limit: Weight,
1053 storage_deposit_limit: DepositLimit<BalanceOf<T>>,
1054 code: Code,
1055 data: Vec<u8>,
1056 salt: Option<[u8; 32]>,
1057 ) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1058 let mut gas_meter = GasMeter::new(gas_limit);
1059 let mut storage_deposit = Default::default();
1060 let unchecked_deposit_limit = storage_deposit_limit.is_unchecked();
1061 let mut storage_deposit_limit = match storage_deposit_limit {
1062 DepositLimit::Balance(limit) => limit,
1063 DepositLimit::UnsafeOnlyForDryRun => BalanceOf::<T>::max_value(),
1064 };
1065
1066 let try_instantiate = || {
1067 let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1068 let (executable, upload_deposit) = match code {
1069 Code::Upload(code) => {
1070 let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1071 let (executable, upload_deposit) = Self::try_upload_code(
1072 upload_account,
1073 code,
1074 storage_deposit_limit,
1075 unchecked_deposit_limit,
1076 )?;
1077 storage_deposit_limit.saturating_reduce(upload_deposit);
1078 (executable, upload_deposit)
1079 },
1080 Code::Existing(code_hash) =>
1081 (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()),
1082 };
1083 let instantiate_origin = Origin::from_account_id(instantiate_account.clone());
1084 let mut storage_meter = if unchecked_deposit_limit {
1085 StorageMeter::new_unchecked(storage_deposit_limit)
1086 } else {
1087 StorageMeter::new(storage_deposit_limit)
1088 };
1089
1090 let result = ExecStack::<T, WasmBlob<T>>::run_instantiate(
1091 instantiate_account,
1092 executable,
1093 &mut gas_meter,
1094 &mut storage_meter,
1095 Self::convert_native_to_evm(value),
1096 data,
1097 salt.as_ref(),
1098 unchecked_deposit_limit,
1099 );
1100 storage_deposit = storage_meter
1101 .try_into_deposit(&instantiate_origin, unchecked_deposit_limit)?
1102 .saturating_add(&StorageDeposit::Charge(upload_deposit));
1103 result
1104 };
1105 let output = Self::run_guarded(try_instantiate);
1106 ContractResult {
1107 result: output
1108 .map(|(addr, result)| InstantiateReturnValue { result, addr })
1109 .map_err(|e| e.error),
1110 gas_consumed: gas_meter.gas_consumed(),
1111 gas_required: gas_meter.gas_required(),
1112 storage_deposit,
1113 }
1114 }
1115
1116 pub fn dry_run_eth_transact(
1124 mut tx: GenericTransaction,
1125 gas_limit: Weight,
1126 tx_fee: impl Fn(Call<T>, DispatchInfo) -> BalanceOf<T>,
1127 ) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
1128 where
1129 <T as frame_system::Config>::RuntimeCall:
1130 Dispatchable<Info = frame_support::dispatch::DispatchInfo>,
1131 <T as Config>::RuntimeCall: From<crate::Call<T>>,
1132 <T as Config>::RuntimeCall: Encode,
1133 T::Nonce: Into<U256>,
1134 T::Hash: frame_support::traits::IsType<H256>,
1135 {
1136 log::trace!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?} gas_limit: {gas_limit:?}");
1137
1138 let from = tx.from.unwrap_or_default();
1139 let origin = T::AddressMapper::to_account_id(&from);
1140 Self::prepare_dry_run(&origin);
1141
1142 let storage_deposit_limit = if tx.gas.is_some() {
1143 DepositLimit::Balance(BalanceOf::<T>::max_value())
1144 } else {
1145 DepositLimit::UnsafeOnlyForDryRun
1146 };
1147
1148 if tx.nonce.is_none() {
1149 tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
1150 }
1151 if tx.chain_id.is_none() {
1152 tx.chain_id = Some(T::ChainId::get().into());
1153 }
1154 if tx.gas_price.is_none() {
1155 tx.gas_price = Some(GAS_PRICE.into());
1156 }
1157 if tx.max_priority_fee_per_gas.is_none() {
1158 tx.max_priority_fee_per_gas = Some(GAS_PRICE.into());
1159 }
1160 if tx.max_fee_per_gas.is_none() {
1161 tx.max_fee_per_gas = Some(GAS_PRICE.into());
1162 }
1163 if tx.gas.is_none() {
1164 tx.gas = Some(Self::evm_block_gas_limit());
1165 }
1166 if tx.r#type.is_none() {
1167 tx.r#type = Some(TYPE_EIP1559.into());
1168 }
1169
1170 let evm_value = tx.value.unwrap_or_default();
1172 let native_value = match Self::convert_evm_to_native(evm_value, ConversionPrecision::Exact)
1173 {
1174 Ok(v) => v,
1175 Err(_) => return Err(EthTransactError::Message("Failed to convert value".into())),
1176 };
1177
1178 let input = tx.input.clone().to_vec();
1179
1180 let extract_error = |err| {
1181 if err == Error::<T>::TransferFailed.into() ||
1182 err == Error::<T>::StorageDepositNotEnoughFunds.into() ||
1183 err == Error::<T>::StorageDepositLimitExhausted.into()
1184 {
1185 let balance = Self::evm_balance(&from);
1186 return Err(EthTransactError::Message(
1187 format!("insufficient funds for gas * price + value: address {from:?} have {balance} (supplied gas {})",
1188 tx.gas.unwrap_or_default()))
1189 );
1190 }
1191
1192 return Err(EthTransactError::Message(format!(
1193 "Failed to instantiate contract: {err:?}"
1194 )));
1195 };
1196
1197 let (mut result, dispatch_info) = match tx.to {
1199 Some(dest) => {
1201 let result = crate::Pallet::<T>::bare_call(
1203 T::RuntimeOrigin::signed(origin),
1204 dest,
1205 native_value,
1206 gas_limit,
1207 storage_deposit_limit,
1208 input.clone(),
1209 );
1210
1211 let data = match result.result {
1212 Ok(return_value) => {
1213 if return_value.did_revert() {
1214 return Err(EthTransactError::Data(return_value.data));
1215 }
1216 return_value.data
1217 },
1218 Err(err) => {
1219 log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
1220 return extract_error(err)
1221 },
1222 };
1223
1224 let result = EthTransactInfo {
1225 gas_required: result.gas_required,
1226 storage_deposit: result.storage_deposit.charge_or_zero(),
1227 data,
1228 eth_gas: Default::default(),
1229 };
1230
1231 let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
1232 result.gas_required,
1233 result.storage_deposit,
1234 );
1235 let dispatch_call: <T as Config>::RuntimeCall = crate::Call::<T>::call {
1236 dest,
1237 value: native_value,
1238 gas_limit,
1239 storage_deposit_limit,
1240 data: input.clone(),
1241 }
1242 .into();
1243 (result, dispatch_call.get_dispatch_info())
1244 },
1245 None => {
1247 let (code, data) = match polkavm::ProgramBlob::blob_length(&input) {
1249 Some(blob_len) => blob_len
1250 .try_into()
1251 .ok()
1252 .and_then(|blob_len| (input.split_at_checked(blob_len)))
1253 .unwrap_or_else(|| (&input[..], &[][..])),
1254 _ => {
1255 log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length");
1256 (&input[..], &[][..])
1257 },
1258 };
1259
1260 let result = crate::Pallet::<T>::bare_instantiate(
1262 T::RuntimeOrigin::signed(origin),
1263 native_value,
1264 gas_limit,
1265 storage_deposit_limit,
1266 Code::Upload(code.to_vec()),
1267 data.to_vec(),
1268 None,
1269 );
1270
1271 let returned_data = match result.result {
1272 Ok(return_value) => {
1273 if return_value.result.did_revert() {
1274 return Err(EthTransactError::Data(return_value.result.data));
1275 }
1276 return_value.result.data
1277 },
1278 Err(err) => {
1279 log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
1280 return extract_error(err)
1281 },
1282 };
1283
1284 let result = EthTransactInfo {
1285 gas_required: result.gas_required,
1286 storage_deposit: result.storage_deposit.charge_or_zero(),
1287 data: returned_data,
1288 eth_gas: Default::default(),
1289 };
1290
1291 let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
1293 result.gas_required,
1294 result.storage_deposit,
1295 );
1296 let dispatch_call: <T as Config>::RuntimeCall =
1297 crate::Call::<T>::instantiate_with_code {
1298 value: native_value,
1299 gas_limit,
1300 storage_deposit_limit,
1301 code: code.to_vec(),
1302 data: data.to_vec(),
1303 salt: None,
1304 }
1305 .into();
1306 (result, dispatch_call.get_dispatch_info())
1307 },
1308 };
1309
1310 let Ok(unsigned_tx) = tx.clone().try_into_unsigned() else {
1311 return Err(EthTransactError::Message("Invalid transaction".into()));
1312 };
1313
1314 let eth_dispatch_call =
1315 crate::Call::<T>::eth_transact { payload: unsigned_tx.dummy_signed_payload() };
1316 let fee = tx_fee(eth_dispatch_call, dispatch_info);
1317 let raw_gas = Self::evm_fee_to_gas(fee);
1318 let eth_gas =
1319 T::EthGasEncoder::encode(raw_gas, result.gas_required, result.storage_deposit);
1320
1321 log::trace!(target: LOG_TARGET, "bare_eth_call: raw_gas: {raw_gas:?} eth_gas: {eth_gas:?}");
1322 result.eth_gas = eth_gas;
1323 Ok(result)
1324 }
1325
1326 pub fn evm_balance(address: &H160) -> U256 {
1328 let account = T::AddressMapper::to_account_id(&address);
1329 Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite))
1330 }
1331
1332 pub fn evm_fee_to_gas(fee: BalanceOf<T>) -> U256 {
1335 let fee = Self::convert_native_to_evm(fee);
1336 let gas_price = GAS_PRICE.into();
1337 let (quotient, remainder) = fee.div_mod(gas_price);
1338 if remainder.is_zero() {
1339 quotient
1340 } else {
1341 quotient + U256::one()
1342 }
1343 }
1344
1345 fn evm_gas_to_fee(gas: U256, gas_price: U256) -> Result<BalanceOf<T>, Error<T>> {
1347 let fee = gas.saturating_mul(gas_price);
1348 Self::convert_evm_to_native(fee, ConversionPrecision::RoundUp)
1349 }
1350
1351 pub fn evm_gas_from_weight(weight: Weight) -> U256 {
1353 let fee = T::WeightPrice::convert(weight);
1354 Self::evm_fee_to_gas(fee)
1355 }
1356
1357 pub fn evm_block_gas_limit() -> U256 {
1359 let max_block_weight = T::BlockWeights::get()
1360 .get(DispatchClass::Normal)
1361 .max_total
1362 .unwrap_or_else(|| T::BlockWeights::get().max_block);
1363
1364 Self::evm_gas_from_weight(max_block_weight)
1365 }
1366
1367 pub fn evm_gas_price() -> U256 {
1369 GAS_PRICE.into()
1370 }
1371
1372 pub fn evm_tracer(tracer_type: TracerType) -> Tracer {
1374 match tracer_type {
1375 TracerType::CallTracer(config) => CallTracer::new(
1376 config.unwrap_or_default(),
1377 Self::evm_gas_from_weight as fn(Weight) -> U256,
1378 )
1379 .into(),
1380 }
1381 }
1382
1383 pub fn bare_upload_code(
1387 origin: OriginFor<T>,
1388 code: Vec<u8>,
1389 storage_deposit_limit: BalanceOf<T>,
1390 ) -> CodeUploadResult<BalanceOf<T>> {
1391 let origin = T::UploadOrigin::ensure_origin(origin)?;
1392 let (module, deposit) = Self::try_upload_code(origin, code, storage_deposit_limit, false)?;
1393 Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit })
1394 }
1395
1396 pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
1398 let contract_info =
1399 ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1400
1401 let maybe_value = contract_info.read(&Key::from_fixed(key));
1402 Ok(maybe_value)
1403 }
1404
1405 pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
1407 let contract_info =
1408 ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1409
1410 let maybe_value = contract_info.read(
1411 &Key::try_from_var(key)
1412 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
1413 .into(),
1414 );
1415 Ok(maybe_value)
1416 }
1417
1418 fn try_upload_code(
1420 origin: T::AccountId,
1421 code: Vec<u8>,
1422 storage_deposit_limit: BalanceOf<T>,
1423 skip_transfer: bool,
1424 ) -> Result<(WasmBlob<T>, BalanceOf<T>), DispatchError> {
1425 let mut module = WasmBlob::from_code(code, origin)?;
1426 let deposit = module.store_code(skip_transfer)?;
1427 ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
1428 Ok((module, deposit))
1429 }
1430
1431 fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
1433 executing_contract::using_once(&mut false, || {
1434 executing_contract::with(|f| {
1435 if *f {
1437 return Err(())
1438 }
1439 *f = true;
1441 Ok(())
1442 })
1443 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
1444 .map_err(|_| <Error<T>>::ReenteredPallet.into())
1445 .map(|_| f())
1446 .and_then(|r| r)
1447 })
1448 }
1449
1450 fn convert_native_to_evm(value: BalanceOf<T>) -> U256 {
1452 value.into().saturating_mul(T::NativeToEthRatio::get().into())
1453 }
1454
1455 fn convert_evm_to_native(
1457 value: U256,
1458 precision: ConversionPrecision,
1459 ) -> Result<BalanceOf<T>, Error<T>> {
1460 if value.is_zero() {
1461 return Ok(Zero::zero())
1462 }
1463
1464 let (quotient, remainder) = value.div_mod(T::NativeToEthRatio::get().into());
1465 match (precision, remainder.is_zero()) {
1466 (ConversionPrecision::Exact, false) => Err(Error::<T>::DecimalPrecisionLoss),
1467 (_, true) => quotient.try_into().map_err(|_| Error::<T>::BalanceConversionFailed),
1468 (_, false) => quotient
1469 .saturating_add(U256::one())
1470 .try_into()
1471 .map_err(|_| Error::<T>::BalanceConversionFailed),
1472 }
1473 }
1474}
1475
1476impl<T: Config> Pallet<T> {
1477 fn min_balance() -> BalanceOf<T> {
1479 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
1480 }
1481
1482 fn deposit_event(event: Event<T>) {
1484 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
1485 }
1486}
1487
1488environmental!(executing_contract: bool);
1490
1491sp_api::decl_runtime_apis! {
1492 #[api_version(1)]
1494 pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber> where
1495 AccountId: Codec,
1496 Balance: Codec,
1497 Nonce: Codec,
1498 BlockNumber: Codec,
1499 {
1500 fn block_gas_limit() -> U256;
1502
1503 fn balance(address: H160) -> U256;
1505
1506 fn gas_price() -> U256;
1508
1509 fn nonce(address: H160) -> Nonce;
1511
1512 fn call(
1516 origin: AccountId,
1517 dest: H160,
1518 value: Balance,
1519 gas_limit: Option<Weight>,
1520 storage_deposit_limit: Option<Balance>,
1521 input_data: Vec<u8>,
1522 ) -> ContractResult<ExecReturnValue, Balance>;
1523
1524 fn instantiate(
1528 origin: AccountId,
1529 value: Balance,
1530 gas_limit: Option<Weight>,
1531 storage_deposit_limit: Option<Balance>,
1532 code: Code,
1533 data: Vec<u8>,
1534 salt: Option<[u8; 32]>,
1535 ) -> ContractResult<InstantiateReturnValue, Balance>;
1536
1537
1538 fn eth_transact(tx: GenericTransaction) -> Result<EthTransactInfo<Balance>, EthTransactError>;
1542
1543 fn upload_code(
1547 origin: AccountId,
1548 code: Vec<u8>,
1549 storage_deposit_limit: Option<Balance>,
1550 ) -> CodeUploadResult<Balance>;
1551
1552 fn get_storage(
1558 address: H160,
1559 key: [u8; 32],
1560 ) -> GetStorageResult;
1561
1562 fn get_storage_var_key(
1568 address: H160,
1569 key: Vec<u8>,
1570 ) -> GetStorageResult;
1571
1572 fn trace_block(
1579 block: Block,
1580 config: TracerType
1581 ) -> Vec<(u32, Trace)>;
1582
1583 fn trace_tx(
1590 block: Block,
1591 tx_index: u32,
1592 config: TracerType
1593 ) -> Option<Trace>;
1594
1595 fn trace_call(tx: GenericTransaction, config: TracerType) -> Result<Trace, EthTransactError>;
1599
1600 }
1601}
1602
1603#[macro_export]
1611macro_rules! impl_runtime_apis_plus_revive {
1612 ($Runtime: ty, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
1613
1614 impl_runtime_apis! {
1615 $($rest)*
1616
1617 impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber> for $Runtime {
1618 fn balance(address: $crate::H160) -> $crate::U256 {
1619 $crate::Pallet::<Self>::evm_balance(&address)
1620 }
1621
1622 fn block_gas_limit() -> $crate::U256 {
1623 $crate::Pallet::<Self>::evm_block_gas_limit()
1624 }
1625
1626 fn gas_price() -> $crate::U256 {
1627 $crate::Pallet::<Self>::evm_gas_price()
1628 }
1629
1630 fn nonce(address: $crate::H160) -> Nonce {
1631 use $crate::AddressMapper;
1632 let account = <Self as $crate::Config>::AddressMapper::to_account_id(&address);
1633 $crate::frame_system::Pallet::<Self>::account_nonce(account)
1634 }
1635
1636 fn eth_transact(
1637 tx: $crate::evm::GenericTransaction,
1638 ) -> Result<$crate::EthTransactInfo<Balance>, $crate::EthTransactError> {
1639 use $crate::{
1640 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
1641 sp_runtime::traits::TransactionExtension,
1642 sp_runtime::traits::Block as BlockT
1643 };
1644
1645 let tx_fee = |pallet_call, mut dispatch_info: $crate::DispatchInfo| {
1646 let call =
1647 <Self as $crate::frame_system::Config>::RuntimeCall::from(pallet_call);
1648 dispatch_info.extension_weight =
1649 <$EthExtra>::get_eth_extension(0, 0u32.into()).weight(&call);
1650
1651 let uxt: <Block as BlockT>::Extrinsic =
1652 $crate::sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into();
1653
1654 $crate::pallet_transaction_payment::Pallet::<Self>::compute_fee(
1655 uxt.encoded_size() as u32,
1656 &dispatch_info,
1657 0u32.into(),
1658 )
1659 };
1660
1661 let blockweights: $crate::BlockWeights =
1662 <Self as $crate::frame_system::Config>::BlockWeights::get();
1663 $crate::Pallet::<Self>::dry_run_eth_transact(tx, blockweights.max_block, tx_fee)
1664 }
1665
1666 fn call(
1667 origin: AccountId,
1668 dest: $crate::H160,
1669 value: Balance,
1670 gas_limit: Option<$crate::Weight>,
1671 storage_deposit_limit: Option<Balance>,
1672 input_data: Vec<u8>,
1673 ) -> $crate::ContractResult<$crate::ExecReturnValue, Balance> {
1674 use $crate::frame_support::traits::Get;
1675 let blockweights: $crate::BlockWeights =
1676 <Self as $crate::frame_system::Config>::BlockWeights::get();
1677
1678 $crate::Pallet::<Self>::prepare_dry_run(&origin);
1679 $crate::Pallet::<Self>::bare_call(
1680 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin),
1681 dest,
1682 value,
1683 gas_limit.unwrap_or(blockweights.max_block),
1684 $crate::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)),
1685 input_data,
1686 )
1687 }
1688
1689 fn instantiate(
1690 origin: AccountId,
1691 value: Balance,
1692 gas_limit: Option<$crate::Weight>,
1693 storage_deposit_limit: Option<Balance>,
1694 code: $crate::Code,
1695 data: Vec<u8>,
1696 salt: Option<[u8; 32]>,
1697 ) -> $crate::ContractResult<$crate::InstantiateReturnValue, Balance> {
1698 use $crate::frame_support::traits::Get;
1699 let blockweights: $crate::BlockWeights =
1700 <Self as $crate::frame_system::Config>::BlockWeights::get();
1701
1702 $crate::Pallet::<Self>::prepare_dry_run(&origin);
1703 $crate::Pallet::<Self>::bare_instantiate(
1704 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin),
1705 value,
1706 gas_limit.unwrap_or(blockweights.max_block),
1707 $crate::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)),
1708 code,
1709 data,
1710 salt,
1711 )
1712 }
1713
1714 fn upload_code(
1715 origin: AccountId,
1716 code: Vec<u8>,
1717 storage_deposit_limit: Option<Balance>,
1718 ) -> $crate::CodeUploadResult<Balance> {
1719 let origin =
1720 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin);
1721 $crate::Pallet::<Self>::bare_upload_code(
1722 origin,
1723 code,
1724 storage_deposit_limit.unwrap_or(u128::MAX),
1725 )
1726 }
1727
1728 fn get_storage_var_key(
1729 address: $crate::H160,
1730 key: Vec<u8>,
1731 ) -> $crate::GetStorageResult {
1732 $crate::Pallet::<Self>::get_storage_var_key(address, key)
1733 }
1734
1735 fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
1736 $crate::Pallet::<Self>::get_storage(address, key)
1737 }
1738
1739 fn trace_block(
1740 block: Block,
1741 tracer_type: $crate::evm::TracerType,
1742 ) -> Vec<(u32, $crate::evm::Trace)> {
1743 use $crate::{sp_runtime::traits::Block, tracing::trace};
1744 let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type);
1745 let mut traces = vec![];
1746 let (header, extrinsics) = block.deconstruct();
1747 <$Executive>::initialize_block(&header);
1748 for (index, ext) in extrinsics.into_iter().enumerate() {
1749 let t = tracer.as_tracing();
1750 trace(t, || {
1751 let _ = <$Executive>::apply_extrinsic(ext);
1752 });
1753
1754 if let Some(tx_trace) = tracer.collect_trace() {
1755 traces.push((index as u32, tx_trace));
1756 }
1757 }
1758
1759 traces
1760 }
1761
1762 fn trace_tx(
1763 block: Block,
1764 tx_index: u32,
1765 tracer_type: $crate::evm::TracerType,
1766 ) -> Option<$crate::evm::Trace> {
1767 use $crate::{sp_runtime::traits::Block, tracing::trace};
1768
1769 let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type);
1770 let (header, extrinsics) = block.deconstruct();
1771
1772 <$Executive>::initialize_block(&header);
1773 for (index, ext) in extrinsics.into_iter().enumerate() {
1774 if index as u32 == tx_index {
1775 let t = tracer.as_tracing();
1776 trace(t, || {
1777 let _ = <$Executive>::apply_extrinsic(ext);
1778 });
1779 break;
1780 } else {
1781 let _ = <$Executive>::apply_extrinsic(ext);
1782 }
1783 }
1784
1785 tracer.collect_trace()
1786 }
1787
1788 fn trace_call(
1789 tx: $crate::evm::GenericTransaction,
1790 tracer_type: $crate::evm::TracerType,
1791 ) -> Result<$crate::evm::Trace, $crate::EthTransactError> {
1792 use $crate::tracing::trace;
1793 let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type);
1794 let t = tracer.as_tracing();
1795
1796 let result = trace(t, || Self::eth_transact(tx));
1797
1798 if let Some(trace) = tracer.collect_trace() {
1799 Ok(trace)
1800 } else if let Err(err) = result {
1801 Err(err)
1802 } else {
1803 Ok(tracer.empty_trace())
1804 }
1805 }
1806 }
1807 }
1808 };
1809}