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 access_list;
26mod address;
27mod benchmarking;
28#[cfg(any(feature = "runtime-benchmarks", test))]
29pub mod call_builder;
30mod debug;
31mod deposit_payment;
32mod exec;
33mod impl_fungibles;
34mod limits;
35mod metering;
36mod primitives;
37#[doc(hidden)]
38pub mod runtime_api;
39#[doc(hidden)]
40pub mod state_overrides;
41mod storage;
42#[cfg(test)]
43mod tests;
44mod transient_storage;
45mod vm;
46mod weightinfo_extension;
47
48pub mod evm;
49pub mod migrations;
50pub mod mock;
51pub mod precompiles;
52pub mod test_utils;
53pub mod tracing;
54pub mod weights;
55
56use crate::{
57 access_list::{StorageAccessKind, Warmth},
58 evm::{
59 CallTracer, CreateCallMode, ExecutionTracer, GenericTransaction, PrestateTracer,
60 StateOverrideSet, TYPE_EIP1559, Tracer, TracerType, block_hash::EthereumBlockBuilderIR,
61 block_storage, fees::InfoT as FeeInfo, runtime::SetWeightLimit,
62 },
63 exec::{AccountIdOf, ExecError, Stack as ExecStack},
64 sp_runtime::TransactionOutcome,
65 storage::{AccountType, DeletionQueueManager},
66 tracing::if_tracing,
67 vm::{CodeInfo, RuntimeCosts, pvm::extract_code_and_data},
68 weightinfo_extension::OnFinalizeBlockParts,
69};
70use alloc::{boxed::Box, format, vec};
71use codec::{Codec, Decode, Encode};
72use environmental::*;
73use frame_support::{
74 BoundedVec,
75 dispatch::{
76 DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
77 Pays, PostDispatchInfo, RawOrigin,
78 },
79 ensure,
80 pallet_prelude::DispatchClass,
81 storage::with_transaction,
82 traits::{
83 ConstU32, ConstU64, DefensiveResult, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced,
84 OriginTrait,
85 fungible::{Balanced, Credit, Inspect, Mutate, MutateHold},
86 tokens::Balance,
87 },
88 weights::WeightMeter,
89};
90use frame_system::{
91 Pallet as System, ensure_signed,
92 pallet_prelude::{BlockNumberFor, OriginFor},
93};
94use pallet_revive_types::runtime_api::*;
95use scale_info::TypeInfo;
96use sp_runtime::{
97 AccountId32, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion,
98 traits::{
99 BadOrigin, Bounded, Convert, Dispatchable, Saturating, UniqueSaturatedFrom,
100 UniqueSaturatedInto, Zero,
101 },
102};
103
104pub use crate::{
105 address::{AccountId32Mapper, AddressMapper, AutoMapper, TestAccountMapper, create1, create2},
106 debug::DebugSettings,
107 deposit_payment::{Deposit, PGasDeposit},
108 evm::{Address as EthAddress, Block as EthBlock, block_hash::ReceiptGasInfo},
109 exec::{
110 CallResources, DelegateInfo, Executable, Key, MomentOf, Origin as ExecOrigin,
111 ReentrancyProtection,
112 },
113 limits::TRANSIENT_STORAGE_BYTES as TRANSIENT_STORAGE_LIMIT,
114 metering::{
115 EthTxInfo, FrameMeter, ResourceMeter, Token as WeightToken, TransactionLimits,
116 TransactionMeter,
117 },
118 pallet::{genesis, *},
119 storage::{AccountInfo, ContractInfo},
120 transient_storage::{MeterEntry, StorageMeter as TransientStorageMeter, TransientStorage},
121 vm::{BytecodeType, ContractBlob},
122};
123pub use codec;
124use frame_support::traits::tokens::Precision;
125pub use frame_support::{self, dispatch::DispatchInfo, traits::Time, weights::Weight};
126pub use frame_system::{self, limits::BlockWeights};
127pub use primitives::*;
128pub use sp_core::{H160, H256, U256};
129pub use sp_crypto_hashing::keccak_256;
130pub use sp_runtime;
131pub use weights::WeightInfo;
132
133pub extern crate pallet_revive_types;
135
136#[cfg(doc)]
137pub use crate::vm::pvm::SyscallDoc;
138
139pub type BalanceOf<T> = <T as Config>::Balance;
140pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
141type TrieId = BoundedVec<u8, ConstU32<128>>;
142type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
143type CallOf<T> = <T as Config>::RuntimeCall;
144
145const SENTINEL: u32 = u32::MAX;
152
153const LOG_TARGET: &str = "runtime::revive";
159
160#[frame_support::pallet]
161pub mod pallet {
162 use super::*;
163 use frame_support::{pallet_prelude::*, traits::FindAuthor};
164 use frame_system::pallet_prelude::*;
165 use sp_core::U256;
166 use sp_runtime::Perbill;
167
168 pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
170
171 #[pallet::pallet]
172 #[pallet::storage_version(STORAGE_VERSION)]
173 pub struct Pallet<T>(_);
174
175 #[pallet::config(with_default)]
176 pub trait Config: frame_system::Config {
177 type Time: Time<Moment: Into<U256>>;
179
180 #[pallet::no_default]
184 type Balance: Balance
185 + TryFrom<U256>
186 + Into<U256>
187 + Bounded
188 + UniqueSaturatedInto<u64>
189 + UniqueSaturatedFrom<u64>
190 + UniqueSaturatedInto<u128>;
191
192 #[pallet::no_default]
194 type Currency: Inspect<Self::AccountId, Balance = Self::Balance>
195 + Mutate<Self::AccountId>
196 + MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>
197 + Balanced<Self::AccountId>;
198
199 #[pallet::no_default_bounds]
206 type OnBurn: OnUnbalanced<CreditOf<Self>>;
207
208 #[pallet::no_default_bounds]
210 #[allow(deprecated)]
211 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
212
213 #[pallet::no_default_bounds]
215 type RuntimeCall: Parameter
216 + Dispatchable<
217 RuntimeOrigin = OriginFor<Self>,
218 Info = DispatchInfo,
219 PostInfo = PostDispatchInfo,
220 > + IsType<<Self as frame_system::Config>::RuntimeCall>
221 + From<Call<Self>>
222 + IsSubType<Call<Self>>
223 + GetDispatchInfo;
224
225 #[pallet::no_default_bounds]
227 type RuntimeOrigin: IsType<OriginFor<Self>>
228 + From<Origin<Self>>
229 + Into<Result<Origin<Self>, OriginFor<Self>>>;
230
231 #[pallet::no_default_bounds]
233 type RuntimeHoldReason: From<HoldReason>;
234
235 type WeightInfo: WeightInfo;
238
239 #[pallet::no_default_bounds]
243 #[allow(private_bounds)]
244 type Precompiles: precompiles::Precompiles<Self>;
245
246 type FindAuthor: FindAuthor<Self::AccountId>;
248
249 #[pallet::constant]
255 #[pallet::no_default_bounds]
256 type DepositPerByte: Get<BalanceOf<Self>>;
257
258 #[pallet::constant]
264 #[pallet::no_default_bounds]
265 type DepositPerItem: Get<BalanceOf<Self>>;
266
267 #[pallet::constant]
277 #[pallet::no_default_bounds]
278 type DepositPerChildTrieItem: Get<BalanceOf<Self>>;
279
280 #[pallet::constant]
284 type CodeHashLockupDepositPercent: Get<Perbill>;
285
286 #[pallet::no_default]
288 type AddressMapper: AddressMapper<Self>;
289
290 #[pallet::constant]
292 type AllowEVMBytecode: Get<bool>;
293
294 #[pallet::no_default_bounds]
299 type UploadOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
300
301 #[pallet::no_default_bounds]
312 type InstantiateOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
313
314 type RuntimeMemory: Get<u32>;
319
320 type PVFMemory: Get<u32>;
328
329 #[pallet::constant]
334 type ChainId: Get<u64>;
335
336 #[pallet::constant]
338 type NativeToEthRatio: Get<u32>;
339
340 #[pallet::no_default_bounds]
345 type FeeInfo: FeeInfo<Self>;
346
347 #[pallet::no_default_bounds]
350 type Deposit: Deposit<Self>;
351
352 #[pallet::constant]
365 type MaxEthExtrinsicWeight: Get<FixedU128>;
366
367 #[pallet::constant]
369 type DebugEnabled: Get<bool>;
370
371 #[pallet::constant]
378 type AutoMap: Get<bool>;
379
380 #[pallet::constant]
398 #[pallet::no_default_bounds]
399 type GasScale: Get<u32>;
400 }
401
402 pub mod config_preludes {
404 use super::*;
405 use frame_support::{
406 derive_impl,
407 traits::{ConstBool, ConstU32},
408 };
409 use frame_system::EnsureSigned;
410 use sp_core::parameter_types;
411
412 type Balance = u64;
413
414 pub const DOLLARS: Balance = 1_000_000_000_000;
415 pub const CENTS: Balance = DOLLARS / 100;
416 pub const MILLICENTS: Balance = CENTS / 1_000;
417
418 pub const fn deposit(items: u32, bytes: u32) -> Balance {
419 items as Balance * 20 * CENTS + (bytes as Balance) * MILLICENTS
420 }
421
422 parameter_types! {
423 pub const DepositPerItem: Balance = deposit(1, 0);
424 pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
425 pub const DepositPerByte: Balance = deposit(0, 1);
426 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
427 pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(9, 10);
428 pub const GasScale: u32 = 10u32;
429 }
430
431 pub struct TestDefaultConfig;
433
434 impl Time for TestDefaultConfig {
435 type Moment = u64;
436 fn now() -> Self::Moment {
437 0u64
438 }
439 }
440
441 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
442 fn convert(w: Weight) -> T {
443 w.ref_time().into()
444 }
445 }
446
447 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
448 impl frame_system::DefaultConfig for TestDefaultConfig {}
449
450 #[frame_support::register_default_impl(TestDefaultConfig)]
451 impl DefaultConfig for TestDefaultConfig {
452 #[inject_runtime_type]
453 type RuntimeEvent = ();
454
455 #[inject_runtime_type]
456 type RuntimeHoldReason = ();
457
458 #[inject_runtime_type]
459 type RuntimeCall = ();
460
461 #[inject_runtime_type]
462 type RuntimeOrigin = ();
463
464 type Precompiles = ();
465 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
466 type DepositPerByte = DepositPerByte;
467 type DepositPerItem = DepositPerItem;
468 type DepositPerChildTrieItem = DepositPerChildTrieItem;
469 type Time = Self;
470 type AllowEVMBytecode = ConstBool<true>;
471 type UploadOrigin = EnsureSigned<Self::AccountId>;
472 type InstantiateOrigin = EnsureSigned<Self::AccountId>;
473 type WeightInfo = ();
474 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
475 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
476 type ChainId = ConstU64<42>;
477 type NativeToEthRatio = ConstU32<1_000_000>;
478 type FindAuthor = ();
479 type FeeInfo = ();
480 type Deposit = ();
481 type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
482 type DebugEnabled = ConstBool<false>;
483 type AutoMap = ConstBool<false>;
484 type GasScale = GasScale;
485 type OnBurn = ();
486 }
487 }
488
489 #[pallet::event]
490 pub enum Event<T: Config> {
491 ContractEmitted {
493 contract: H160,
495 data: Vec<u8>,
498 topics: Vec<H256>,
501 },
502
503 Instantiated { deployer: H160, contract: H160 },
505
506 EthExtrinsicRevert { dispatch_error: DispatchError },
513 }
514
515 #[pallet::error]
516 #[repr(u8)]
517 pub enum Error<T> {
518 InvalidSchedule = 0x01,
520 InvalidCallFlags = 0x02,
522 OutOfGas = 0x03,
524 TransferFailed = 0x04,
527 MaxCallDepthReached = 0x05,
530 ContractNotFound = 0x06,
532 CodeNotFound = 0x07,
534 CodeInfoNotFound = 0x08,
536 OutOfBounds = 0x09,
538 DecodingFailed = 0x0A,
540 ContractTrapped = 0x0B,
542 ValueTooLarge = 0x0C,
544 TerminatedWhileReentrant = 0x0D,
547 InputForwarded = 0x0E,
549 TooManyTopics = 0x0F,
551 DuplicateContract = 0x12,
553 TerminatedInConstructor = 0x13,
557 ReentranceDenied = 0x14,
559 ReenteredPallet = 0x15,
561 StateChangeDenied = 0x16,
563 StorageDepositNotEnoughFunds = 0x17,
565 StorageDepositLimitExhausted = 0x18,
567 CodeInUse = 0x19,
569 ContractReverted = 0x1A,
574 CodeRejected = 0x1B,
579 BlobTooLarge = 0x1C,
581 StaticMemoryTooLarge = 0x1D,
583 BasicBlockTooLarge = 0x1E,
585 InvalidInstruction = 0x1F,
587 MaxDelegateDependenciesReached = 0x20,
589 DelegateDependencyNotFound = 0x21,
591 DelegateDependencyAlreadyExists = 0x22,
593 CannotAddSelfAsDelegateDependency = 0x23,
595 OutOfTransientStorage = 0x24,
597 InvalidSyscall = 0x25,
599 InvalidStorageFlags = 0x26,
601 ExecutionFailed = 0x27,
603 BalanceConversionFailed = 0x28,
605 InvalidImmutableAccess = 0x2A,
608 AccountUnmapped = 0x2B,
612 AccountAlreadyMapped = 0x2C,
614 InvalidGenericTransaction = 0x2D,
616 RefcountOverOrUnderflow = 0x2E,
618 UnsupportedPrecompileAddress = 0x2F,
620 CallDataTooLarge = 0x30,
622 ReturnDataTooLarge = 0x31,
624 InvalidJump = 0x32,
626 StackUnderflow = 0x33,
628 StackOverflow = 0x34,
630 TxFeeOverdraw = 0x35,
634 EvmConstructorNonEmptyData = 0x36,
638 EvmConstructedFromHash = 0x37,
643 StorageRefundNotEnoughFunds = 0x38,
647 StorageRefundLocked = 0x39,
652 PrecompileDelegateDenied = 0x40,
657 EcdsaRecoveryFailed = 0x41,
659 AutoMappingEnabled = 0x42,
661 PendingDepositCleanup = 0x43,
665 #[cfg(feature = "runtime-benchmarks")]
667 BenchmarkingError = 0xFF,
668 }
669
670 #[pallet::composite_enum]
672 pub enum HoldReason {
673 CodeUploadDepositReserve,
675 StorageDepositReserve,
677 AddressMapping,
679 }
680
681 #[pallet::composite_enum]
683 pub enum FreezeReason {
684 PGasMinBalance,
689 }
690
691 #[derive(
692 PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug,
693 )]
694 #[pallet::origin]
695 pub enum Origin<T: Config> {
696 EthTransaction(T::AccountId),
697 }
698
699 #[pallet::storage]
703 #[pallet::unbounded]
704 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, Vec<u8>>;
705
706 #[pallet::storage]
708 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
709
710 #[pallet::storage]
712 pub(crate) type AccountInfoOf<T: Config> = StorageMap<_, Identity, H160, AccountInfo<T>>;
713
714 #[pallet::storage]
725 pub(crate) type NativeDepositOf<T: Config> = StorageDoubleMap<
726 _,
727 Identity,
728 T::AccountId,
729 Identity,
730 T::AccountId,
731 BalanceOf<T>,
732 ValueQuery,
733 >;
734
735 #[pallet::storage]
737 pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
738
739 #[pallet::storage]
745 pub(crate) type DeletionQueue<T: Config> =
746 StorageMap<_, Twox64Concat, u32, crate::storage::DeletionQueueItem<T>>;
747
748 #[pallet::storage]
751 pub(crate) type DeletionQueueCounter<T: Config> =
752 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
753
754 #[pallet::storage]
761 pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
762
763 #[pallet::storage]
773 #[pallet::unbounded]
774 pub(crate) type EthereumBlock<T> = StorageValue<_, EthBlock, ValueQuery>;
775
776 #[pallet::storage]
780 pub(crate) type BlockHash<T: Config> =
781 StorageMap<_, Identity, BlockNumberFor<T>, H256, ValueQuery>;
782
783 #[pallet::storage]
790 #[pallet::unbounded]
791 pub(crate) type ReceiptInfoData<T: Config> = StorageValue<_, Vec<ReceiptGasInfo>, ValueQuery>;
792
793 #[pallet::storage]
795 #[pallet::unbounded]
796 pub(crate) type EthBlockBuilderIR<T: Config> =
797 StorageValue<_, EthereumBlockBuilderIR<T>, ValueQuery>;
798
799 #[pallet::storage]
804 #[pallet::unbounded]
805 pub(crate) type EthBlockBuilderFirstValues<T: Config> =
806 StorageValue<_, Option<(Vec<u8>, Vec<u8>)>, ValueQuery>;
807
808 #[pallet::storage]
810 pub(crate) type DebugSettingsOf<T: Config> = StorageValue<_, DebugSettings, ValueQuery>;
811
812 pub mod genesis {
813 use super::*;
814 use crate::evm::Bytes32;
815
816 #[derive(Clone, PartialEq, Debug, Default, serde::Serialize, serde::Deserialize)]
818 pub struct ContractData {
819 pub code: crate::evm::Bytes,
821 pub storage: alloc::collections::BTreeMap<Bytes32, Bytes32>,
823 }
824
825 #[derive(PartialEq, Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
827 pub struct Account<T: Config> {
828 pub address: H160,
830 #[serde(default)]
832 pub balance: U256,
833 #[serde(default)]
835 pub nonce: T::Nonce,
836 #[serde(flatten, skip_serializing_if = "Option::is_none")]
838 pub contract_data: Option<ContractData>,
839 }
840 }
841
842 #[pallet::genesis_config]
843 #[derive(Debug, PartialEq, frame_support::DefaultNoBound)]
844 pub struct GenesisConfig<T: Config> {
845 #[serde(default, skip_serializing_if = "Vec::is_empty")]
848 pub mapped_accounts: Vec<T::AccountId>,
849
850 #[serde(default, skip_serializing_if = "Vec::is_empty")]
852 pub accounts: Vec<genesis::Account<T>>,
853
854 #[serde(default, skip_serializing_if = "Option::is_none")]
856 pub debug_settings: Option<DebugSettings>,
857 }
858
859 #[pallet::genesis_build]
860 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
861 fn build(&self) {
862 use crate::{exec::Key, vm::ContractBlob};
863 use frame_support::traits::fungible::Mutate;
864
865 if !System::<T>::account_exists(&Pallet::<T>::account_id()) {
866 let _ = T::Currency::mint_into(
867 &Pallet::<T>::account_id(),
868 T::Currency::minimum_balance(),
869 );
870 }
871
872 for id in &self.mapped_accounts {
873 if let Err(err) = T::AddressMapper::map_no_deposit_unchecked(id) {
874 log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
875 }
876 }
877
878 let owner = Pallet::<T>::account_id();
879
880 for genesis::Account { address, balance, nonce, contract_data } in &self.accounts {
881 let account_id = T::AddressMapper::to_account_id(address);
882
883 if !System::<T>::account_exists(&account_id) {
884 let _ = T::Currency::mint_into(&account_id, T::Currency::minimum_balance());
885 }
886
887 frame_system::Account::<T>::mutate(&account_id, |info| {
888 info.nonce = (*nonce).into();
889 });
890
891 match contract_data {
892 None => {
893 AccountInfoOf::<T>::insert(
894 address,
895 AccountInfo { account_type: AccountType::EOA, dust: 0 },
896 );
897 },
898 Some(genesis::ContractData { code, storage }) => {
899 let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) {
900 ContractBlob::<T>::from_pvm_code(code.0.clone(), owner.clone())
901 .inspect_err(|err| {
902 log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}");
903 })
904 } else {
905 ContractBlob::<T>::from_evm_runtime_code(code.0.clone(), account_id)
906 .inspect_err(|err| {
907 log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}");
908 })
909 };
910
911 let Ok(blob) = blob else {
912 continue;
913 };
914
915 let code_hash = *blob.code_hash();
916 let Ok(info) = <ContractInfo<T>>::new(&address, 0u32.into(), code_hash)
917 .inspect_err(|err| {
918 log::error!(target: LOG_TARGET, "Failed to create ContractInfo for {address:?}: {err:?}");
919 })
920 else {
921 continue;
922 };
923
924 AccountInfoOf::<T>::insert(
925 address,
926 AccountInfo { account_type: info.clone().into(), dust: 0 },
927 );
928
929 <PristineCode<T>>::insert(blob.code_hash(), code.0.clone());
930 <CodeInfoOf<T>>::insert(blob.code_hash(), blob.code_info().clone());
931 for (k, v) in storage {
932 let _ = info.write(&Key::from_fixed(k.0), Some(v.0.to_vec()), None, false).inspect_err(|err| {
933 log::error!(target: LOG_TARGET, "Failed to write genesis storage for {address:?} at key {k:?}: {err:?}");
934 });
935 }
936 },
937 }
938
939 let _ = Pallet::<T>::set_evm_balance(address, *balance).inspect_err(|err| {
940 log::error!(target: LOG_TARGET, "Failed to set EVM balance for {address:?}: {err:?}");
941 });
942 }
943
944 block_storage::on_finalize_build_eth_block::<T>(
946 frame_system::Pallet::<T>::block_number(),
949 );
950
951 if let Some(settings) = self.debug_settings.as_ref() {
953 settings.write_to_storage::<T>()
954 }
955 }
956 }
957
958 #[pallet::hooks]
959 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
960 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
961 let mut meter = WeightMeter::with_limit(limit);
962 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
963 meter.consumed()
964 }
965
966 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
967 block_storage::on_initialize::<T>();
969
970 System::<T>::account_exists(&Pallet::<T>::account_id());
972 <T as Config>::WeightInfo::on_finalize_block_fixed()
974 }
975
976 fn on_finalize(block_number: BlockNumberFor<T>) {
977 block_storage::on_finalize_build_eth_block::<T>(block_number);
979 }
980
981 fn integrity_test() {
982 assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
983
984 assert!(T::GasScale::get() > 0u32.into(), "GasScale must not be 0");
985
986 T::FeeInfo::integrity_test();
987
988 let max_runtime_mem: u64 = T::RuntimeMemory::get().into();
990
991 const TOTAL_MEMORY_DEVIDER: u64 = 2;
994
995 let max_block_weight = T::BlockWeights::get()
1001 .get(DispatchClass::Normal)
1002 .max_total
1003 .unwrap_or_else(|| T::BlockWeights::get().max_block);
1004 let max_key_size: u64 =
1005 Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
1006 .expect("Key of maximal size shall be created")
1007 .hash()
1008 .len()
1009 .try_into()
1010 .unwrap();
1011
1012 let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
1013 let max_immutable_size: u64 = max_block_weight
1014 .checked_div_per_component(&<RuntimeCosts as WeightToken<T>>::weight(
1015 &RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
1016 ))
1017 .unwrap()
1018 .saturating_mul(
1019 u64::from(limits::IMMUTABLE_BYTES)
1020 .saturating_add(max_immutable_key_size)
1021 .into(),
1022 );
1023
1024 let max_pvf_mem: u64 = T::PVFMemory::get().into();
1025 let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
1026
1027 let max_events_size = max_block_weight
1031 .checked_div_per_component(
1032 &(<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::DepositEvent {
1033 num_topic: 0,
1034 len: limits::EVENT_BYTES,
1035 })
1036 .saturating_add(<RuntimeCosts as WeightToken<T>>::weight(
1037 &RuntimeCosts::HostFn,
1038 ))),
1039 )
1040 .unwrap()
1041 .saturating_mul(limits::EVENT_BYTES.into());
1042
1043 assert!(
1044 max_events_size <= storage_size_limit,
1045 "Maximal events size {} exceeds the events limit {}",
1046 max_events_size,
1047 storage_size_limit
1048 );
1049
1050 let max_eth_block_builder_bytes =
1085 block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());
1086
1087 log::debug!(
1088 target: LOG_TARGET,
1089 "Integrity check: max_eth_block_builder_bytes={} KB using max_events_size={} KB",
1090 max_eth_block_builder_bytes / 1024,
1091 max_events_size / 1024,
1092 );
1093
1094 let memory_left = i128::from(max_runtime_mem)
1099 .saturating_div(TOTAL_MEMORY_DEVIDER.into())
1100 .saturating_sub(limits::MEMORY_REQUIRED.into())
1101 .saturating_sub(max_eth_block_builder_bytes.into());
1102
1103 log::debug!(target: LOG_TARGET, "Integrity check: memory_left={} KB", memory_left / 1024);
1104
1105 assert!(
1106 memory_left >= 0,
1107 "Runtime does not have enough memory for current limits. Additional runtime memory required: {} KB",
1108 memory_left.saturating_mul(TOTAL_MEMORY_DEVIDER.into()).abs() / 1024
1109 );
1110
1111 let max_storage_size = max_block_weight
1114 .checked_div_per_component(
1115 &<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::SetStorage {
1116 new_bytes: limits::STORAGE_BYTES,
1117 old_bytes: 0,
1118 kind: StorageAccessKind::Persistent(Warmth::Cold { revertible: true }),
1119 })
1120 .saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
1121 )
1122 .unwrap()
1123 .saturating_add(max_immutable_size.into())
1124 .saturating_add(max_eth_block_builder_bytes.into());
1125
1126 assert!(
1127 max_storage_size <= storage_size_limit,
1128 "Maximal storage size {} exceeds the storage limit {}",
1129 max_storage_size,
1130 storage_size_limit
1131 );
1132 }
1133 }
1134
1135 #[pallet::call]
1136 impl<T: Config> Pallet<T> {
1137 #[allow(unused_variables)]
1150 #[pallet::call_index(0)]
1151 #[pallet::weight(Weight::MAX)]
1152 pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
1153 Err(frame_system::Error::CallFiltered::<T>.into())
1154 }
1155
1156 #[pallet::call_index(1)]
1173 #[pallet::weight(<T as Config>::WeightInfo::call().saturating_add(*weight_limit))]
1174 pub fn call(
1175 origin: OriginFor<T>,
1176 dest: H160,
1177 #[pallet::compact] value: BalanceOf<T>,
1178 weight_limit: Weight,
1179 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1180 data: Vec<u8>,
1181 ) -> DispatchResultWithPostInfo {
1182 Self::ensure_non_contract_if_signed(&origin)?;
1183 let mut output = Self::bare_call(
1184 origin,
1185 dest,
1186 Pallet::<T>::convert_native_to_evm(value),
1187 TransactionLimits::WeightAndDeposit {
1188 weight_limit,
1189 deposit_limit: storage_deposit_limit,
1190 },
1191 data,
1192 &ExecConfig::new_substrate_tx(),
1193 );
1194
1195 if let Ok(return_value) = &output.result &&
1196 return_value.did_revert()
1197 {
1198 output.result = Err(<Error<T>>::ContractReverted.into());
1199 }
1200 dispatch_result(
1201 output.result,
1202 output.weight_consumed,
1203 <T as Config>::WeightInfo::call(),
1204 )
1205 }
1206
1207 #[pallet::call_index(2)]
1213 #[pallet::weight(
1214 <T as Config>::WeightInfo::instantiate(data.len() as u32).saturating_add(*weight_limit)
1215 )]
1216 pub fn instantiate(
1217 origin: OriginFor<T>,
1218 #[pallet::compact] value: BalanceOf<T>,
1219 weight_limit: Weight,
1220 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1221 code_hash: sp_core::H256,
1222 data: Vec<u8>,
1223 salt: Option<[u8; 32]>,
1224 ) -> DispatchResultWithPostInfo {
1225 Self::ensure_non_contract_if_signed(&origin)?;
1226 let data_len = data.len() as u32;
1227 let mut output = Self::bare_instantiate(
1228 origin,
1229 Pallet::<T>::convert_native_to_evm(value),
1230 TransactionLimits::WeightAndDeposit {
1231 weight_limit,
1232 deposit_limit: storage_deposit_limit,
1233 },
1234 Code::Existing(code_hash),
1235 data,
1236 salt,
1237 &ExecConfig::new_substrate_tx(),
1238 );
1239 if let Ok(retval) = &output.result &&
1240 retval.result.did_revert()
1241 {
1242 output.result = Err(<Error<T>>::ContractReverted.into());
1243 }
1244 dispatch_result(
1245 output.result.map(|result| result.result),
1246 output.weight_consumed,
1247 <T as Config>::WeightInfo::instantiate(data_len),
1248 )
1249 }
1250
1251 #[pallet::call_index(3)]
1279 #[pallet::weight(
1280 <T as Config>::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
1281 .saturating_add(*weight_limit)
1282 )]
1283 pub fn instantiate_with_code(
1284 origin: OriginFor<T>,
1285 #[pallet::compact] value: BalanceOf<T>,
1286 weight_limit: Weight,
1287 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1288 code: Vec<u8>,
1289 data: Vec<u8>,
1290 salt: Option<[u8; 32]>,
1291 ) -> DispatchResultWithPostInfo {
1292 Self::ensure_non_contract_if_signed(&origin)?;
1293 let code_len = code.len() as u32;
1294 let data_len = data.len() as u32;
1295 let mut output = Self::bare_instantiate(
1296 origin,
1297 Pallet::<T>::convert_native_to_evm(value),
1298 TransactionLimits::WeightAndDeposit {
1299 weight_limit,
1300 deposit_limit: storage_deposit_limit,
1301 },
1302 Code::Upload(code),
1303 data,
1304 salt,
1305 &ExecConfig::new_substrate_tx(),
1306 );
1307 if let Ok(retval) = &output.result &&
1308 retval.result.did_revert()
1309 {
1310 output.result = Err(<Error<T>>::ContractReverted.into());
1311 }
1312 dispatch_result(
1313 output.result.map(|result| result.result),
1314 output.weight_consumed,
1315 <T as Config>::WeightInfo::instantiate_with_code(code_len, data_len),
1316 )
1317 }
1318
1319 #[pallet::call_index(10)]
1341 #[pallet::weight(
1342 <T as Config>::WeightInfo::eth_instantiate_with_code(code.len() as u32, data.len() as u32, Pallet::<T>::has_dust(*value).into())
1343 .saturating_add(*weight_limit)
1344 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1345 )]
1346 pub fn eth_instantiate_with_code(
1347 origin: OriginFor<T>,
1348 value: U256,
1349 weight_limit: Weight,
1350 eth_gas_limit: U256,
1351 code: Vec<u8>,
1352 data: Vec<u8>,
1353 transaction_encoded: Vec<u8>,
1354 effective_gas_price: U256,
1355 encoded_len: u32,
1356 ) -> DispatchResultWithPostInfo {
1357 let signer = Self::ensure_eth_signed(origin)?;
1358 let origin = OriginFor::<T>::signed(signer.clone());
1359 Self::ensure_non_contract_if_signed(&origin)?;
1360 let mut call = Call::<T>::eth_instantiate_with_code {
1361 value,
1362 weight_limit,
1363 eth_gas_limit,
1364 code: code.clone(),
1365 data: data.clone(),
1366 transaction_encoded: transaction_encoded.clone(),
1367 effective_gas_price,
1368 encoded_len,
1369 }
1370 .into();
1371 let info = T::FeeInfo::dispatch_info(&call);
1372 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1373 drop(call);
1374
1375 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1376 let extra_weight = base_info.total_weight();
1377 let output = Self::bare_instantiate(
1378 origin,
1379 value,
1380 TransactionLimits::EthereumGas {
1381 eth_gas_limit: eth_gas_limit.saturated_into(),
1382 weight_limit,
1383 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1384 },
1385 Code::Upload(code),
1386 data,
1387 None,
1388 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1389 );
1390
1391 block_storage::EthereumCallResult::new::<T>(
1392 signer,
1393 output.map_result(|r| r.result),
1394 base_info.call_weight,
1395 encoded_len,
1396 &info,
1397 effective_gas_price,
1398 )
1399 })
1400 }
1401
1402 #[pallet::call_index(11)]
1419 #[pallet::weight(
1420 T::WeightInfo::eth_call(Pallet::<T>::has_dust(*value).into())
1421 .saturating_add(*weight_limit)
1422 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1423 )]
1424 pub fn eth_call(
1425 origin: OriginFor<T>,
1426 dest: H160,
1427 value: U256,
1428 weight_limit: Weight,
1429 eth_gas_limit: U256,
1430 data: Vec<u8>,
1431 transaction_encoded: Vec<u8>,
1432 effective_gas_price: U256,
1433 encoded_len: u32,
1434 ) -> DispatchResultWithPostInfo {
1435 let signer = Self::ensure_eth_signed(origin)?;
1436 let origin = OriginFor::<T>::signed(signer.clone());
1437
1438 Self::ensure_non_contract_if_signed(&origin)?;
1439 let mut call = Call::<T>::eth_call {
1440 dest,
1441 value,
1442 weight_limit,
1443 eth_gas_limit,
1444 data: data.clone(),
1445 transaction_encoded: transaction_encoded.clone(),
1446 effective_gas_price,
1447 encoded_len,
1448 }
1449 .into();
1450 let info = T::FeeInfo::dispatch_info(&call);
1451 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1452 drop(call);
1453
1454 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1455 let extra_weight = base_info.total_weight();
1456 let output = Self::bare_call(
1457 origin,
1458 dest,
1459 value,
1460 TransactionLimits::EthereumGas {
1461 eth_gas_limit: eth_gas_limit.saturated_into(),
1462 weight_limit,
1463 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1464 },
1465 data,
1466 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1467 );
1468
1469 block_storage::EthereumCallResult::new::<T>(
1470 signer,
1471 output,
1472 base_info.call_weight,
1473 encoded_len,
1474 &info,
1475 effective_gas_price,
1476 )
1477 })
1478 }
1479
1480 #[pallet::call_index(12)]
1491 #[pallet::weight(
1492 T::WeightInfo::eth_substrate_call(transaction_encoded.len() as u32)
1493 .saturating_add(call.get_dispatch_info().call_weight)
1494 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1495 )]
1496 pub fn eth_substrate_call(
1497 origin: OriginFor<T>,
1498 call: Box<<T as Config>::RuntimeCall>,
1499 transaction_encoded: Vec<u8>,
1500 ) -> DispatchResultWithPostInfo {
1501 let signer = Self::ensure_eth_signed(origin)?;
1504 Self::ensure_non_contract_if_signed(&OriginFor::<T>::signed(signer.clone()))?;
1505 let tx_len = transaction_encoded.len() as u32;
1506 let weight_overhead = T::WeightInfo::eth_substrate_call(tx_len)
1507 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(tx_len));
1508
1509 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1510 let call_weight = call.get_dispatch_info().call_weight;
1511 let mut call_result = call.dispatch(RawOrigin::Signed(signer).into());
1512
1513 match &mut call_result {
1515 Ok(post_info) | Err(DispatchErrorWithPostInfo { post_info, .. }) => {
1516 post_info.actual_weight = Some(
1517 post_info
1518 .actual_weight
1519 .unwrap_or_else(|| call_weight)
1520 .saturating_add(weight_overhead),
1521 );
1522 },
1523 }
1524
1525 block_storage::EthereumCallResult {
1528 receipt_gas_info: ReceiptGasInfo::default(),
1529 result: call_result,
1530 }
1531 })
1532 }
1533
1534 #[pallet::call_index(4)]
1549 #[pallet::weight(<T as Config>::WeightInfo::upload_code(code.len() as u32))]
1550 pub fn upload_code(
1551 origin: OriginFor<T>,
1552 code: Vec<u8>,
1553 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1554 ) -> DispatchResult {
1555 Self::ensure_non_contract_if_signed(&origin)?;
1556 Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
1557 }
1558
1559 #[pallet::call_index(5)]
1564 #[pallet::weight(<T as Config>::WeightInfo::remove_code())]
1565 pub fn remove_code(
1566 origin: OriginFor<T>,
1567 code_hash: sp_core::H256,
1568 ) -> DispatchResultWithPostInfo {
1569 let origin = ensure_signed(origin)?;
1570 <ContractBlob<T>>::remove(&origin, code_hash)?;
1571 Ok(Pays::No.into())
1573 }
1574
1575 #[pallet::call_index(6)]
1586 #[pallet::weight(<T as Config>::WeightInfo::set_code())]
1587 pub fn set_code(
1588 origin: OriginFor<T>,
1589 dest: H160,
1590 code_hash: sp_core::H256,
1591 ) -> DispatchResult {
1592 ensure_root(origin)?;
1593 <AccountInfoOf<T>>::try_mutate(&dest, |account| {
1594 let Some(account) = account else {
1595 return Err(<Error<T>>::ContractNotFound.into());
1596 };
1597
1598 let AccountType::Contract(ref mut contract) = account.account_type else {
1599 return Err(<Error<T>>::ContractNotFound.into());
1600 };
1601
1602 <CodeInfo<T>>::increment_refcount(code_hash)?;
1603 let _ = <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
1604 contract.code_hash = code_hash;
1605
1606 Ok(())
1607 })
1608 }
1609
1610 #[pallet::call_index(7)]
1618 #[pallet::weight(<T as Config>::WeightInfo::map_account())]
1619 pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
1620 #[cfg(not(feature = "runtime-benchmarks"))]
1621 if T::AutoMap::get() {
1622 return Ok(());
1623 }
1624
1625 Self::ensure_non_contract_if_signed(&origin)?;
1626 let origin = ensure_signed(origin)?;
1627 T::AddressMapper::map(&origin)
1628 }
1629
1630 #[pallet::call_index(13)]
1632 #[pallet::weight(<T as Config>::WeightInfo::batch_map_accounts(accounts.len().saturated_into::<u32>()))]
1633 pub fn batch_map_accounts(
1634 origin: OriginFor<T>,
1635 accounts: Vec<T::AccountId>,
1636 ) -> DispatchResultWithPostInfo {
1637 ensure_signed(origin.clone())?;
1638 Self::ensure_non_contract_if_signed(&origin)?;
1639
1640 let total: u32 = accounts.len().saturated_into();
1641 let mut mapped = 0;
1642
1643 for account_id in accounts
1644 .iter()
1645 .filter(|&a| !T::AddressMapper::is_eth_derived(a))
1647 .filter(|&a| frame_system::Pallet::<T>::account_exists(a))
1650 {
1651 let mut useful = false;
1652
1653 match T::AddressMapper::map_no_deposit_unchecked(account_id) {
1654 Ok(()) => {
1655 useful = true;
1656 },
1657 Err(err) => log::debug!(
1658 target: LOG_TARGET,
1659 "Failed to map account {account_id:?}: {err:?}",
1660 ),
1661 }
1662
1663 match T::Currency::release_all(
1664 &HoldReason::AddressMapping.into(),
1665 account_id,
1666 Precision::BestEffort,
1667 ) {
1668 Ok(released) if !released.is_zero() => {
1671 useful = true;
1672 },
1673 Ok(_) => {},
1674 Err(err) => log::debug!(
1675 target: LOG_TARGET,
1676 "Failed to release mapping deposit for {account_id:?}: {err:?}",
1677 ),
1678 }
1679
1680 if useful {
1681 mapped = mapped.saturating_add(1);
1682 }
1683 }
1684
1685 if total == 0 || mapped == 0 {
1687 return Ok(Pays::Yes.into());
1688 }
1689
1690 let proportion_mapped = Perbill::from_rational(mapped, total);
1691 if proportion_mapped >= Perbill::from_percent(90) {
1692 Ok(Pays::No.into())
1693 } else {
1694 Ok(Pays::Yes.into())
1695 }
1696 }
1697
1698 #[pallet::call_index(8)]
1706 #[pallet::weight(<T as Config>::WeightInfo::unmap_account())]
1707 pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
1708 #[cfg(not(feature = "runtime-benchmarks"))]
1709 ensure!(!T::AutoMap::get(), <Error<T>>::AutoMappingEnabled);
1710 let origin = ensure_signed(origin)?;
1711 T::AddressMapper::unmap(&origin)
1712 }
1713
1714 #[pallet::call_index(9)]
1720 #[pallet::weight({
1721 let dispatch_info = call.get_dispatch_info();
1722 (
1723 <T as Config>::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
1724 dispatch_info.class
1725 )
1726 })]
1727 pub fn dispatch_as_fallback_account(
1728 mut origin: OriginFor<T>,
1729 call: Box<<T as Config>::RuntimeCall>,
1730 ) -> DispatchResultWithPostInfo {
1731 Self::ensure_non_contract_if_signed(&origin)?;
1732 let account_id = origin.as_signer().ok_or(DispatchError::BadOrigin)?;
1733 let unmapped_account = T::AddressMapper::to_fallback_account_id(
1734 &T::AddressMapper::to_address(&account_id),
1735 );
1736 origin.set_caller_from(RawOrigin::Signed(unmapped_account));
1737 call.dispatch(origin)
1738 }
1739 }
1740}
1741
1742fn dispatch_result<R>(
1744 result: Result<R, DispatchError>,
1745 weight_consumed: Weight,
1746 base_weight: Weight,
1747) -> DispatchResultWithPostInfo {
1748 let post_info = PostDispatchInfo {
1749 actual_weight: Some(weight_consumed.saturating_add(base_weight)),
1750 pays_fee: Default::default(),
1751 };
1752
1753 result
1754 .map(|_| post_info)
1755 .map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
1756}
1757
1758impl<T: Config> Pallet<T> {
1759 pub fn bare_call(
1766 origin: OriginFor<T>,
1767 dest: H160,
1768 evm_value: U256,
1769 transaction_limits: TransactionLimits<T>,
1770 data: Vec<u8>,
1771 exec_config: &ExecConfig<T>,
1772 ) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
1773 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1774 Ok(transaction_meter) => transaction_meter,
1775 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1776 };
1777 let mut storage_deposit = Default::default();
1778
1779 let try_call = || {
1780 let origin = ExecOrigin::from_runtime_origin(origin)?;
1781 let result = ExecStack::<T, ContractBlob<T>>::run_call(
1782 origin.clone(),
1783 dest,
1784 &mut transaction_meter,
1785 evm_value,
1786 data,
1787 &exec_config,
1788 )?;
1789
1790 storage_deposit = transaction_meter
1791 .execute_postponed_deposits(&origin, &exec_config)
1792 .inspect_err(|err| {
1793 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1794 })?;
1795
1796 Ok(result)
1797 };
1798 let result = Self::run_guarded(try_call);
1799
1800 log::trace!(target: LOG_TARGET, "Bare call ends: \
1801 result={result:?}, \
1802 weight_consumed={:?}, \
1803 weight_required={:?}, \
1804 storage_deposit={:?}, \
1805 gas_consumed={:?}, \
1806 max_storage_deposit={:?}",
1807 transaction_meter.weight_consumed(),
1808 transaction_meter.weight_required(),
1809 storage_deposit,
1810 transaction_meter.total_consumed_gas(),
1811 transaction_meter.deposit_required()
1812 );
1813
1814 ContractResult {
1815 result: result.map_err(|r| r.error),
1816 weight_consumed: transaction_meter.weight_consumed(),
1817 weight_required: transaction_meter.weight_required(),
1818 storage_deposit,
1819 gas_consumed: transaction_meter.total_consumed_gas(),
1820 max_storage_deposit: transaction_meter.deposit_required(),
1821 }
1822 }
1823
1824 pub fn prepare_dry_run(account: &T::AccountId) {
1830 frame_system::Pallet::<T>::inc_account_nonce(account);
1833
1834 if !T::AddressMapper::is_mapped(account) {
1837 let _ = T::AddressMapper::map_no_deposit_unchecked(account);
1838 }
1839 }
1840
1841 pub fn bare_instantiate(
1847 origin: OriginFor<T>,
1848 evm_value: U256,
1849 transaction_limits: TransactionLimits<T>,
1850 code: Code,
1851 data: Vec<u8>,
1852 salt: Option<[u8; 32]>,
1853 exec_config: &ExecConfig<T>,
1854 ) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1855 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1856 Ok(transaction_meter) => transaction_meter,
1857 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1858 };
1859
1860 let mut storage_deposit = Default::default();
1861
1862 let try_instantiate = || {
1863 let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1864
1865 if_tracing(|t| t.instantiate_code(&code, salt.as_ref()));
1866 let executable = match code {
1867 Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => {
1868 let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1869 let executable = Self::try_upload_code(
1870 upload_account,
1871 code,
1872 BytecodeType::Pvm,
1873 &mut transaction_meter,
1874 &exec_config,
1875 )?;
1876 executable
1877 },
1878 Code::Upload(code) => {
1879 if T::AllowEVMBytecode::get() {
1880 ensure!(data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
1881 let origin = T::UploadOrigin::ensure_origin(origin)?;
1882 let executable = ContractBlob::from_evm_init_code(code, origin)?;
1883 executable
1884 } else {
1885 return Err(<Error<T>>::CodeRejected.into());
1886 }
1887 },
1888 Code::Existing(code_hash) => {
1889 let executable = ContractBlob::from_storage(code_hash, &mut transaction_meter)?;
1890 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
1891 executable
1892 },
1893 };
1894 let instantiate_origin = ExecOrigin::from_account_id(instantiate_account.clone());
1895 let result = ExecStack::<T, ContractBlob<T>>::run_instantiate(
1896 instantiate_account,
1897 executable,
1898 &mut transaction_meter,
1899 evm_value,
1900 data,
1901 salt.as_ref(),
1902 &exec_config,
1903 );
1904
1905 storage_deposit = transaction_meter
1906 .execute_postponed_deposits(&instantiate_origin, &exec_config)
1907 .inspect_err(|err| {
1908 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1909 })?;
1910 result
1911 };
1912 let output = Self::run_guarded(try_instantiate);
1913
1914 log::trace!(target: LOG_TARGET, "Bare instantiate ends: weight_consumed={:?}\
1915 weight_required={:?} \
1916 storage_deposit={:?} \
1917 gas_consumed={:?} \
1918 max_storage_deposit={:?}",
1919 transaction_meter.weight_consumed(),
1920 transaction_meter.weight_required(),
1921 storage_deposit,
1922 transaction_meter.total_consumed_gas(),
1923 transaction_meter.deposit_required()
1924 );
1925
1926 ContractResult {
1927 result: output
1928 .map(|(addr, result)| InstantiateReturnValue { result, addr })
1929 .map_err(|e| e.error),
1930 weight_consumed: transaction_meter.weight_consumed(),
1931 weight_required: transaction_meter.weight_required(),
1932 storage_deposit,
1933 gas_consumed: transaction_meter.total_consumed_gas(),
1934 max_storage_deposit: transaction_meter.deposit_required(),
1935 }
1936 }
1937
1938 pub fn eth_estimate_gas(
1950 tx: GenericTransaction,
1951 timestamp_override: Option<MomentOf<T>>,
1952 state_overrides: Option<StateOverrideSet>,
1953 ) -> Result<U256, EthTransactError>
1954 where
1955 T::Nonce: Into<U256> + TryFrom<U256>,
1956 CallOf<T>: SetWeightLimit,
1957 {
1958 log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}");
1959
1960 let mut low = U256::zero();
1961 let mut high = Self::evm_block_gas_limit();
1962
1963 log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}");
1964
1965 let perform_balance_checks = if let Some(gas_limit) = tx.gas {
1969 high = gas_limit;
1970 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}");
1971 true
1972 } else {
1973 false
1974 };
1975
1976 let fee_cap = tx.max_fee_per_gas.or(tx.gas_price);
1978 if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) {
1979 let mut available_balance = Self::evm_balance(&from);
1980 if let Some(value) = tx.value {
1981 available_balance = available_balance.checked_sub(value).ok_or_else(|| {
1982 EthTransactError::Message("insufficient funds for value transfer".into())
1983 })?;
1984 }
1985 if let Some(allowance) = available_balance.checked_div(fee_cap) {
1986 if high > allowance && allowance != U256::zero() {
1987 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}");
1988 high = allowance
1989 }
1990 }
1991 }
1992
1993 let dry_run_at = |gas: U256| {
1997 let mut transaction = tx.clone();
1998 transaction.gas = Some(gas);
1999 with_transaction(|| {
2000 TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
2001 transaction,
2002 timestamp_override,
2003 perform_balance_checks,
2004 state_overrides.clone(),
2005 )))
2006 })
2007 .expect("Rollback shouldn't error out")
2008 };
2009
2010 let is_simple_transfer = with_transaction(|| {
2013 let probe = state_overrides
2014 .clone()
2015 .map_or(Ok(()), state_overrides::apply_state_overrides::<T>)
2016 .map(|()| Self::is_simple_transfer(&tx));
2017 TransactionOutcome::Rollback(Ok::<_, DispatchError>(probe))
2018 })
2019 .expect("Rollback shouldn't error out")?;
2020
2021 if is_simple_transfer {
2022 let dry_run_result = dry_run_at(high)?;
2023 log::trace!(
2024 target: LOG_TARGET,
2025 "eth_estimate_gas short-circuited simple transfer to {:?} with eth_gas={}",
2026 tx.to,
2027 dry_run_result.eth_gas,
2028 );
2029 return Ok(dry_run_result.eth_gas);
2030 }
2031
2032 let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()]
2037 .map(|gas_limit| (gas_limit, dry_run_at(gas_limit)));
2038 let (gas_limit, first_dry_run_result) = match dry_run_results {
2039 [(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => {
2040 if dry_run_result2.eth_gas >= gas_limit2 {
2041 (gas_limit1, dry_run_result1)
2042 } else {
2043 (gas_limit2, dry_run_result2)
2044 }
2045 },
2046 [(gas_limit, Ok(dry_run_result)), (_, Err(_))] |
2047 [(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result),
2048 [(_, Err(err)), (_, Err(..))] => return Err(err),
2049 };
2050 log::trace!(
2051 target: LOG_TARGET,
2052 "eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}",
2053 gas_limit,
2054 first_dry_run_result.eth_gas
2055 );
2056 low = first_dry_run_result.eth_gas;
2057 high = gas_limit;
2058
2059 while low + U256::one() < high {
2060 log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}");
2061 let error_ratio = high
2062 .checked_sub(low)
2063 .and_then(|value| value.checked_mul(U256::from(1000)))
2064 .and_then(|value| value.checked_div(high))
2065 .ok_or_else(|| {
2066 EthTransactError::Message(
2067 "failed to calculate error ratio in gas estimation".into(),
2068 )
2069 })?;
2070 if error_ratio <= U256::from(15) {
2071 log::trace!(
2072 target: LOG_TARGET,
2073 "eth_estimate_gas finished due to error ratio being less than 1.5% high={}",
2074 high
2075 );
2076 break;
2077 }
2078
2079 let mut midpoint = high
2080 .checked_sub(low)
2081 .and_then(|value| value.checked_div(U256::from(2)))
2082 .and_then(|value| value.checked_add(low))
2083 .ok_or_else(|| {
2084 EthTransactError::Message(
2085 "failed to calculate midpoint in gas estimation".into(),
2086 )
2087 })?;
2088
2089 if let Some(other_midpoint) = low.checked_mul(U256::from(2)) {
2090 if other_midpoint != U256::zero() {
2091 midpoint = midpoint.min(other_midpoint)
2092 }
2093 };
2094
2095 let dry_run_result = dry_run_at(midpoint);
2096 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}");
2097 match dry_run_result {
2098 Ok(..) => {
2099 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}");
2100 high = midpoint
2101 },
2102 Err(..) => {
2103 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}");
2104 low = midpoint
2105 },
2106 }
2107 }
2108
2109 log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}");
2110 Ok(high)
2111 }
2112
2113 pub(crate) fn is_simple_transfer(tx: &GenericTransaction) -> bool {
2115 tx.to
2116 .map(|to| tx.has_simple_transfer_fields() && Self::address_runs_no_code(&to))
2117 .unwrap_or(false)
2118 }
2119
2120 fn address_runs_no_code(address: &H160) -> bool {
2123 *address != RUNTIME_PALLETS_ADDR &&
2126 !exec::is_precompile::<T, ContractBlob<T>>(address) &&
2127 !<AccountInfo<T>>::is_contract(address)
2128 }
2129
2130 pub fn eth_pre_dispatch_weight(transaction_encoded: Vec<u8>) -> Result<Weight, EthTransactError>
2138 where
2139 CallOf<T>: SetWeightLimit,
2140 {
2141 let signed_tx =
2142 crate::evm::TransactionSigned::decode(&transaction_encoded).map_err(|err| {
2143 EthTransactError::Message(format!("Failed to decode transaction: {err:?}"))
2144 })?;
2145 let signer_addr = signed_tx.recover_eth_address().map_err(|err| {
2146 EthTransactError::Message(format!("Failed to recover signer: {err:?}"))
2147 })?;
2148 let tx =
2149 GenericTransaction::from_signed(signed_tx, Self::evm_base_fee(), Some(signer_addr));
2150 let encoded_len = T::FeeInfo::encoded_len(
2151 crate::Call::<T>::eth_transact { payload: transaction_encoded.clone() }.into(),
2152 );
2153 let call_info = tx
2154 .into_call::<T>(CreateCallMode::ExtrinsicExecution(encoded_len, transaction_encoded))
2155 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2156 let info = T::FeeInfo::dispatch_info(&call_info.call);
2157
2158 Ok(frame_system::calculate_consumed_extrinsic_weight::<CallOf<T>>(
2159 &T::BlockWeights::get(),
2160 &info,
2161 call_info.encoded_len as usize,
2162 ))
2163 }
2164
2165 pub fn dry_run_eth_transact(
2176 mut tx: GenericTransaction,
2177 timestamp_override: Option<MomentOf<T>>,
2178 perform_balance_checks: bool,
2179 state_overrides: Option<StateOverrideSet>,
2180 ) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
2181 where
2182 T::Nonce: Into<U256> + TryFrom<U256>,
2183 CallOf<T>: SetWeightLimit,
2184 {
2185 log::debug!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?}");
2186
2187 let origin = T::AddressMapper::to_account_id(&tx.from.unwrap_or_default());
2188 Self::prepare_dry_run(&origin);
2189
2190 if let Some(overrides) = state_overrides {
2191 state_overrides::apply_state_overrides::<T>(overrides)?;
2192 }
2193
2194 let base_fee = Self::evm_base_fee();
2195 let effective_gas_price = tx.effective_gas_price(base_fee).unwrap_or(base_fee);
2196
2197 if effective_gas_price < base_fee {
2198 Err(EthTransactError::Message(format!(
2199 "Effective gas price {effective_gas_price:?} lower than base fee {base_fee:?}"
2200 )))?;
2201 }
2202
2203 if tx.nonce.is_none() {
2204 tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
2205 }
2206 if tx.chain_id.is_none() {
2207 tx.chain_id = Some(T::ChainId::get().into());
2208 }
2209
2210 tx.gas_price = Some(effective_gas_price);
2212 tx.max_priority_fee_per_gas = Some(0.into());
2215 if tx.max_fee_per_gas.is_none() {
2216 tx.max_fee_per_gas = Some(effective_gas_price);
2217 }
2218
2219 let gas = tx.gas;
2220 if tx.gas.is_none() {
2221 tx.gas = Some(Self::evm_block_gas_limit());
2222 }
2223 if tx.r#type.is_none() {
2224 tx.r#type = Some(TYPE_EIP1559.into());
2225 }
2226
2227 let value = tx.value.unwrap_or_default();
2229 let input = tx.input.clone().to_vec();
2230 let from = tx.from;
2231 let to = tx.to;
2232
2233 let mut call_info = tx
2236 .into_call::<T>(CreateCallMode::DryRun)
2237 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2238
2239 let base_info = T::FeeInfo::base_dispatch_info(&mut call_info.call);
2243 let base_weight = base_info.total_weight();
2244 let exec_config =
2245 ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight)
2246 .with_dry_run(timestamp_override);
2247
2248 let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
2250 if let Some(from) = &from {
2251 let fees = if gas.is_some() && perform_balance_checks { fees } else { Zero::zero() };
2252 let balance = Self::evm_balance(from);
2253 if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
2254 return Err(EthTransactError::Message(format!(
2255 "insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
2256 )));
2257 }
2258 }
2259
2260 T::FeeInfo::deposit_txfee(T::Currency::issue(fees));
2263
2264 let extract_error = |err| {
2265 if err == Error::<T>::StorageDepositNotEnoughFunds.into() {
2266 Err(EthTransactError::Message(format!("Not enough gas supplied: {err:?}")))
2267 } else {
2268 Err(EthTransactError::Message(format!("failed to run contract: {err:?}")))
2269 }
2270 };
2271
2272 let transaction_limits = TransactionLimits::EthereumGas {
2273 eth_gas_limit: call_info.eth_gas_limit.saturated_into(),
2274 weight_limit: Self::evm_max_extrinsic_weight(),
2275 eth_tx_info: EthTxInfo::new(call_info.encoded_len, base_weight),
2276 };
2277
2278 let mut dry_run = match to {
2280 Some(dest) => {
2282 if dest == RUNTIME_PALLETS_ADDR {
2283 let Ok(dispatch_call) = <CallOf<T>>::decode(&mut &input[..]) else {
2284 return Err(EthTransactError::Message(format!(
2285 "Failed to decode pallet-call {input:?}"
2286 )));
2287 };
2288
2289 if let Err(result) =
2290 dispatch_call.clone().dispatch(RawOrigin::Signed(origin).into())
2291 {
2292 return Err(EthTransactError::Message(format!(
2293 "Failed to dispatch call: {:?}",
2294 result.error,
2295 )));
2296 };
2297
2298 Default::default()
2299 } else {
2300 let result = crate::Pallet::<T>::bare_call(
2302 OriginFor::<T>::signed(origin),
2303 dest,
2304 value,
2305 transaction_limits,
2306 input.clone(),
2307 &exec_config,
2308 );
2309
2310 let data = match result.result {
2311 Ok(return_value) => {
2312 if return_value.did_revert() {
2313 return Err(EthTransactError::Data(return_value.data));
2314 }
2315 return_value.data
2316 },
2317 Err(err) => {
2318 log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
2319 return extract_error(err);
2320 },
2321 };
2322
2323 EthTransactInfo {
2324 weight_required: result.weight_required,
2325 storage_deposit: result.storage_deposit.charge_or_zero(),
2326 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2327 data,
2328 eth_gas: Default::default(),
2329 }
2330 }
2331 },
2332 None => {
2334 let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2336 extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default()))
2337 } else {
2338 (input, vec![])
2339 };
2340
2341 let result = crate::Pallet::<T>::bare_instantiate(
2343 OriginFor::<T>::signed(origin),
2344 value,
2345 transaction_limits,
2346 Code::Upload(code.clone()),
2347 data.clone(),
2348 None,
2349 &exec_config,
2350 );
2351
2352 let returned_data = match result.result {
2353 Ok(return_value) => {
2354 if return_value.result.did_revert() {
2355 return Err(EthTransactError::Data(return_value.result.data));
2356 }
2357 return_value.result.data
2358 },
2359 Err(err) => {
2360 log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
2361 return extract_error(err);
2362 },
2363 };
2364
2365 EthTransactInfo {
2366 weight_required: result.weight_required,
2367 storage_deposit: result.storage_deposit.charge_or_zero(),
2368 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2369 data: returned_data,
2370 eth_gas: Default::default(),
2371 }
2372 },
2373 };
2374
2375 call_info.call.set_weight_limit(dry_run.weight_required);
2377
2378 let total_weight = T::FeeInfo::dispatch_info(&call_info.call).total_weight();
2380 let max_weight = Self::evm_max_extrinsic_weight();
2381 if total_weight.any_gt(max_weight) {
2382 log::debug!(target: LOG_TARGET, "Transaction weight estimate exceeds extrinsic maximum: \
2383 total_weight={total_weight:?} \
2384 max_weight={max_weight:?}",
2385 );
2386
2387 Err(EthTransactError::Message(format!(
2388 "\
2389 The transaction consumes more than the allowed weight. \
2390 needed={total_weight} \
2391 allowed={max_weight} \
2392 overweight_by={}\
2393 ",
2394 total_weight.saturating_sub(max_weight),
2395 )))?;
2396 }
2397
2398 let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
2400 let available_fee = T::FeeInfo::remaining_txfee();
2401 if transaction_fee > available_fee {
2402 Err(EthTransactError::Message(format!(
2403 "Not enough gas supplied: Off by: {:?}",
2404 transaction_fee.saturating_sub(available_fee),
2405 )))?;
2406 }
2407
2408 let total_cost = transaction_fee.saturating_add(dry_run.max_storage_deposit);
2409 let total_cost_wei = Pallet::<T>::convert_native_to_evm(total_cost);
2410 let (mut eth_gas, rest) = total_cost_wei.div_mod(base_fee);
2411 if !rest.is_zero() {
2412 eth_gas = eth_gas.saturating_add(1_u32.into());
2413 }
2414
2415 log::debug!(target: LOG_TARGET, "\
2416 dry_run_eth_transact finished: \
2417 weight_limit={}, \
2418 total_weight={total_weight}, \
2419 max_weight={max_weight}, \
2420 weight_left={}, \
2421 eth_gas={eth_gas}, \
2422 encoded_len={}, \
2423 tx_fee={transaction_fee:?}, \
2424 storage_deposit={:?}, \
2425 max_storage_deposit={:?}\
2426 ",
2427 dry_run.weight_required,
2428 max_weight.saturating_sub(total_weight),
2429 call_info.encoded_len,
2430 dry_run.storage_deposit,
2431 dry_run.max_storage_deposit,
2432
2433 );
2434 dry_run.eth_gas = eth_gas;
2435 Ok(dry_run)
2436 }
2437
2438 pub fn evm_balance(address: &H160) -> U256 {
2442 let balance = AccountInfo::<T>::balance_of((*address).into());
2443 Self::convert_native_to_evm(balance)
2444 }
2445
2446 pub fn eth_block() -> EthBlock {
2448 EthereumBlock::<T>::get()
2449 }
2450
2451 pub fn eth_block_hash_from_number(number: U256) -> Option<H256> {
2458 let number = BlockNumberFor::<T>::try_from(number).ok()?;
2459 let hash = <BlockHash<T>>::get(number);
2460 if hash == H256::zero() { None } else { Some(hash) }
2461 }
2462
2463 pub fn eth_receipt_data() -> Vec<ReceiptGasInfo> {
2465 ReceiptInfoData::<T>::get()
2466 }
2467
2468 pub fn set_evm_balance(address: &H160, evm_value: U256) -> Result<(), Error<T>> {
2474 let (balance, dust) = Self::new_balance_with_dust(evm_value)
2475 .map_err(|_| <Error<T>>::BalanceConversionFailed)?;
2476 let account_id = T::AddressMapper::to_account_id(&address);
2477 T::Currency::set_balance(&account_id, balance);
2478 AccountInfoOf::<T>::mutate(&address, |account| {
2479 if let Some(account) = account {
2480 account.dust = dust;
2481 } else {
2482 *account = Some(AccountInfo { dust, ..Default::default() });
2483 }
2484 });
2485
2486 Ok(())
2487 }
2488
2489 pub fn new_balance_with_dust(
2493 evm_value: U256,
2494 ) -> Result<(BalanceOf<T>, u32), BalanceConversionError> {
2495 let ed = T::Currency::minimum_balance();
2496 let balance_with_dust = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(evm_value)?;
2497 let (value, dust) = balance_with_dust.deconstruct();
2498
2499 Ok((ed.saturating_add(value), dust))
2500 }
2501
2502 pub fn evm_nonce(address: &H160) -> u32
2504 where
2505 T::Nonce: Into<u32>,
2506 {
2507 let account = T::AddressMapper::to_account_id(&address);
2508 System::<T>::account_nonce(account).into()
2509 }
2510
2511 pub fn evm_block_gas_limit() -> U256 {
2513 u64::MAX.into()
2520 }
2521
2522 pub fn evm_max_extrinsic_weight_in_gas() -> U256 {
2524 let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight());
2525 let gas_scale: BalanceOf<T> = T::GasScale::get().into();
2526 (max_extrinsic_fee / gas_scale).into()
2527 }
2528
2529 pub fn evm_max_extrinsic_weight() -> Weight {
2531 let factor = <T as Config>::MaxEthExtrinsicWeight::get();
2532 let max_weight = <T as frame_system::Config>::BlockWeights::get()
2533 .get(DispatchClass::Normal)
2534 .max_extrinsic
2535 .unwrap_or_else(|| <T as frame_system::Config>::BlockWeights::get().max_block);
2536 Weight::from_parts(
2537 factor.saturating_mul_int(max_weight.ref_time()),
2538 factor.saturating_mul_int(max_weight.proof_size()),
2539 )
2540 }
2541
2542 pub fn evm_base_fee() -> U256 {
2544 let gas_scale = <T as Config>::GasScale::get();
2545 let multiplier = T::FeeInfo::next_fee_multiplier();
2546 multiplier
2547 .saturating_mul_int::<u128>(T::NativeToEthRatio::get().into())
2548 .saturating_mul(gas_scale.saturated_into())
2549 .into()
2550 }
2551
2552 pub fn evm_tracer(tracer_type: TracerType) -> Tracer<T>
2554 where
2555 T::Nonce: Into<u32>,
2556 {
2557 match tracer_type {
2558 TracerType::CallTracer(config) => CallTracer::new(config.unwrap_or_default()).into(),
2559 TracerType::PrestateTracer(config) => {
2560 PrestateTracer::new(config.unwrap_or_default()).into()
2561 },
2562 TracerType::ExecutionTracer(config) => {
2563 ExecutionTracer::new(config.unwrap_or_default()).into()
2564 },
2565 }
2566 }
2567
2568 pub fn bare_upload_code(
2572 origin: OriginFor<T>,
2573 code: Vec<u8>,
2574 storage_deposit_limit: BalanceOf<T>,
2575 ) -> CodeUploadResult<BalanceOf<T>> {
2576 let origin = T::UploadOrigin::ensure_origin(origin)?;
2577
2578 let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2579 BytecodeType::Pvm
2580 } else {
2581 if !T::AllowEVMBytecode::get() {
2582 return Err(<Error<T>>::CodeRejected.into());
2583 }
2584 BytecodeType::Evm
2585 };
2586
2587 let mut meter = TransactionMeter::new(TransactionLimits::WeightAndDeposit {
2588 weight_limit: Default::default(),
2589 deposit_limit: storage_deposit_limit,
2590 })?;
2591
2592 let module = Self::try_upload_code(
2593 origin,
2594 code,
2595 bytecode_type,
2596 &mut meter,
2597 &ExecConfig::new_substrate_tx(),
2598 )?;
2599 Ok(CodeUploadReturnValue {
2600 code_hash: *module.code_hash(),
2601 deposit: meter.deposit_consumed().charge_or_zero(),
2602 })
2603 }
2604
2605 pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
2607 let contract_info =
2608 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2609
2610 let maybe_value = contract_info.read(&Key::from_fixed(key));
2611 Ok(maybe_value)
2612 }
2613
2614 pub fn get_immutables(address: H160) -> Option<ImmutableData> {
2618 let immutable_data = <ImmutableDataOf<T>>::get(address);
2619 immutable_data
2620 }
2621
2622 pub fn set_immutables(address: H160, data: ImmutableData) -> Result<(), ContractAccessError> {
2630 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2631 <ImmutableDataOf<T>>::insert(address, data);
2632 Ok(())
2633 }
2634
2635 pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
2637 let contract_info =
2638 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2639
2640 let maybe_value = contract_info.read(
2641 &Key::try_from_var(key)
2642 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2643 .into(),
2644 );
2645 Ok(maybe_value)
2646 }
2647
2648 pub fn convert_native_to_evm(value: impl Into<BalanceWithDust<BalanceOf<T>>>) -> U256 {
2650 let (value, dust) = value.into().deconstruct();
2651 value
2652 .into()
2653 .saturating_mul(T::NativeToEthRatio::get().into())
2654 .saturating_add(dust.into())
2655 }
2656
2657 pub fn set_storage(address: H160, key: [u8; 32], value: Option<Vec<u8>>) -> SetStorageResult {
2667 let contract_info =
2668 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2669
2670 contract_info
2671 .write(&Key::from_fixed(key), value, None, false)
2672 .map_err(ContractAccessError::StorageWriteFailed)
2673 }
2674
2675 pub fn set_storage_var_key(
2686 address: H160,
2687 key: Vec<u8>,
2688 value: Option<Vec<u8>>,
2689 ) -> SetStorageResult {
2690 let contract_info =
2691 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2692
2693 contract_info
2694 .write(
2695 &Key::try_from_var(key)
2696 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2697 .into(),
2698 value,
2699 None,
2700 false,
2701 )
2702 .map_err(ContractAccessError::StorageWriteFailed)
2703 }
2704
2705 pub fn account_id() -> T::AccountId {
2707 use frame_support::PalletId;
2708 use sp_runtime::traits::AccountIdConversion;
2709 PalletId(*b"py/reviv").into_account_truncating()
2710 }
2711
2712 pub fn block_author() -> H160 {
2714 use frame_support::traits::FindAuthor;
2715
2716 let digest = <frame_system::Pallet<T>>::digest();
2717 let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
2718
2719 T::FindAuthor::find_author(pre_runtime_digests)
2720 .map(|account_id| T::AddressMapper::to_address(&account_id))
2721 .unwrap_or_default()
2722 }
2723
2724 pub fn code(address: &H160) -> Vec<u8> {
2728 use precompiles::{All, Precompiles};
2729 if let Some(code) = <All<T>>::code(address.as_fixed_bytes()) {
2730 return code.into();
2731 }
2732 AccountInfo::<T>::load_contract(&address)
2733 .and_then(|contract| <PristineCode<T>>::get(contract.code_hash))
2734 .map(|code| code.into())
2735 .unwrap_or_default()
2736 }
2737
2738 pub fn try_upload_code(
2740 origin: T::AccountId,
2741 code: Vec<u8>,
2742 code_type: BytecodeType,
2743 meter: &mut TransactionMeter<T>,
2744 exec_config: &ExecConfig<T>,
2745 ) -> Result<ContractBlob<T>, DispatchError> {
2746 let mut module = match code_type {
2747 BytecodeType::Pvm => ContractBlob::from_pvm_code(code, origin)?,
2748 BytecodeType::Evm => ContractBlob::from_evm_runtime_code(code, origin)?,
2749 };
2750 module.store_code(exec_config, meter)?;
2751 Ok(module)
2752 }
2753
2754 fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
2756 executing_contract::using_once(&mut false, || {
2757 executing_contract::with(|f| {
2758 if *f {
2760 return Err(())
2761 }
2762 *f = true;
2764 Ok(())
2765 })
2766 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
2767 .map_err(|_| <Error<T>>::ReenteredPallet.into())
2768 .map(|_| f())
2769 .and_then(|r| r)
2770 })
2771 }
2772
2773 fn charge_deposit(
2778 hold_reason: HoldReason,
2779 from: &T::AccountId,
2780 to: &T::AccountId,
2781 amount: BalanceOf<T>,
2782 exec_config: &ExecConfig<T>,
2783 ) -> DispatchResult {
2784 if amount.is_zero() {
2785 return Ok(());
2786 }
2787
2788 T::Deposit::charge_and_hold(hold_reason, exec_config.funds(from), to, amount)
2789 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
2790 Ok(())
2791 }
2792
2793 fn refund_deposit(
2798 hold_reason: HoldReason,
2799 from: &T::AccountId,
2800 dst: deposit_payment::Funds<T::AccountId>,
2801 amount: BalanceOf<T>,
2802 ) -> Result<(), DispatchError> {
2803 if amount.is_zero() {
2804 return Ok(());
2805 }
2806
2807 let to = match &dst {
2808 deposit_payment::Funds::Balance(to) | deposit_payment::Funds::TxFee(to) => *to,
2809 };
2810 let result = T::Deposit::refund_on_hold(hold_reason, from, dst, amount);
2811
2812 result.defensive_map_err(|err| {
2813 let available = T::Deposit::total_on_hold(hold_reason, from);
2814 if available < amount {
2815 log::error!(
2818 target: LOG_TARGET,
2819 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}. Not enough deposit: {available:?}. This is a bug.",
2820 );
2821 Error::<T>::StorageRefundNotEnoughFunds.into()
2822 } else {
2823 log::warn!(
2828 target: LOG_TARGET,
2829 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}: {err:?}. First remove locks (staking, governance) from the contracts account.",
2830 );
2831 Error::<T>::StorageRefundLocked.into()
2832 }
2833 })
2834 }
2835
2836 fn has_dust(value: U256) -> bool {
2838 value % U256::from(<T>::NativeToEthRatio::get()) != U256::zero()
2839 }
2840
2841 fn has_balance(value: U256) -> bool {
2843 value >= U256::from(<T>::NativeToEthRatio::get())
2844 }
2845
2846 #[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))]
2848 fn min_balance() -> BalanceOf<T> {
2849 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
2850 }
2851
2852 fn deposit_event(event: Event<T>) {
2857 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
2858 }
2859
2860 fn ensure_eth_signed(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
2862 match <T as Config>::RuntimeOrigin::from(origin).into() {
2863 Ok(Origin::EthTransaction(signer)) => Ok(signer),
2864 _ => Err(BadOrigin.into()),
2865 }
2866 }
2867
2868 fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
2872 if DebugSettings::bypass_eip_3607::<T>() {
2873 return Ok(());
2874 }
2875 let Some(address) = origin
2876 .as_system_ref()
2877 .and_then(|o| o.as_signed())
2878 .map(<T::AddressMapper as AddressMapper<T>>::to_address)
2879 else {
2880 return Ok(());
2881 };
2882 if exec::is_precompile::<T, ContractBlob<T>>(&address) ||
2883 <AccountInfo<T>>::is_contract(&address)
2884 {
2885 log::debug!(
2886 target: crate::LOG_TARGET,
2887 "EIP-3607: reject tx as pre-compile or account exist at {address:?}",
2888 );
2889 Err(DispatchError::BadOrigin)
2890 } else {
2891 Ok(())
2892 }
2893 }
2894}
2895
2896pub const RUNTIME_PALLETS_ADDR: H160 =
2901 H160(hex_literal::hex!("6d6f646c70792f70616464720000000000000000"));
2902
2903environmental!(executing_contract: bool);
2905
2906sp_api::decl_runtime_apis! {
2907 #[api_version(2)]
2909 pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber, Moment> where
2910 AccountId: Codec,
2911 Balance: Codec,
2912 Nonce: Codec,
2913 BlockNumber: Codec,
2914 Moment: Codec,
2915 {
2916 #[deprecated(note = "Use the versioned equivalent `eth_block_versioned` if available on your runtime")]
2920 fn eth_block() -> BlockV1;
2921
2922 #[deprecated(note = "Use the versioned equivalent `eth_block_hash_versioned` if available on your runtime")]
2924 fn eth_block_hash(number: U256) -> Option<H256>;
2925
2926 #[deprecated(note = "Use the versioned equivalent `eth_receipt_data_versioned` if available on your runtime")]
2932 fn eth_receipt_data() -> Vec<ReceiptGasInfoV1>;
2933
2934 #[deprecated(note = "Use the versioned equivalent `block_gas_limit_versioned` if available on your runtime")]
2936 fn block_gas_limit() -> U256;
2937
2938 #[deprecated(note = "Use the versioned equivalent `max_extrinsic_weight_in_gas_versioned` if available on your runtime")]
2940 fn max_extrinsic_weight_in_gas() -> U256;
2941
2942 #[deprecated(note = "Use the versioned equivalent `balance_versioned` if available on your runtime")]
2944 fn balance(address: H160) -> U256;
2945
2946 #[deprecated(note = "Use the versioned equivalent `gas_price_versioned` if available on your runtime")]
2948 fn gas_price() -> U256;
2949
2950 #[deprecated(note = "Use the versioned equivalent `nonce_versioned` if available on your runtime")]
2952 fn nonce(address: H160) -> Nonce;
2953
2954 #[deprecated(note = "Use the versioned equivalent `call_versioned` if available on your runtime")]
2958 fn call(
2959 origin: AccountId,
2960 dest: H160,
2961 value: Balance,
2962 gas_limit: Option<Weight>,
2963 storage_deposit_limit: Option<Balance>,
2964 input_data: Vec<u8>,
2965 ) -> ContractResultV1<ExecReturnValueV1, Balance>;
2966
2967 #[deprecated(note = "Use the versioned equivalent `instantiate_versioned` if available on your runtime")]
2971 fn instantiate(
2972 origin: AccountId,
2973 value: Balance,
2974 gas_limit: Option<Weight>,
2975 storage_deposit_limit: Option<Balance>,
2976 code: CodeV1,
2977 data: Vec<u8>,
2978 salt: Option<[u8; 32]>,
2979 ) -> ContractResultV1<InstantiateReturnValueV1, Balance>;
2980
2981
2982 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
2986 fn eth_transact(tx: GenericTransactionV1) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
2987
2988 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
2992 fn eth_transact_with_config(
2993 tx: GenericTransactionV1,
2994 config: DryRunConfigV1<Moment>,
2995 ) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
2996
2997 #[deprecated(note = "Use the versioned equivalent `eth_estimate_gas_versioned` if available on your runtime")]
3003 fn eth_estimate_gas(
3004 tx: GenericTransactionV1,
3005 config: DryRunConfigV1<Moment>
3006 ) -> Result<U256, EthTransactError>;
3007
3008 #[deprecated(note = "Use the versioned equivalent `eth_pre_dispatch_weight_versioned` if available on your runtime")]
3010 fn eth_pre_dispatch_weight(tx: Vec<u8>) -> Result<Weight, EthTransactError>;
3011
3012 #[deprecated(note = "Use the versioned equivalent `upload_code_versioned` if available on your runtime")]
3016 fn upload_code(
3017 origin: AccountId,
3018 code: Vec<u8>,
3019 storage_deposit_limit: Option<Balance>,
3020 ) -> Result<CodeUploadReturnValueV1<Balance>, DispatchError>;
3021
3022 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3028 fn get_storage(
3029 address: H160,
3030 key: [u8; 32],
3031 ) -> GetStorageResult;
3032
3033 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3039 fn get_storage_var_key(
3040 address: H160,
3041 key: Vec<u8>,
3042 ) -> GetStorageResult;
3043
3044 #[deprecated(note = "Use the versioned equivalent `trace_block_versioned` if available on your runtime")]
3051 fn trace_block(
3052 block: Block,
3053 config: TracerTypeV1
3054 ) -> Vec<(u32, TraceV1)>;
3055
3056 #[deprecated(note = "Use the versioned equivalent `trace_tx_versioned` if available on your runtime")]
3063 fn trace_tx(
3064 block: Block,
3065 tx_index: u32,
3066 config: TracerTypeV1
3067 ) -> Option<TraceV1>;
3068
3069 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3073 fn trace_call(tx: GenericTransactionV1, config: TracerTypeV1) -> Result<TraceV1, EthTransactError>;
3074
3075 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3080 fn trace_call_with_config(
3081 tx: GenericTransactionV1,
3082 tracer_type: TracerTypeV1,
3083 config: TracingConfigV1,
3084 ) -> Result<TraceV1, EthTransactError>;
3085
3086 #[deprecated(note = "Use the versioned equivalent `block_author_versioned` if available on your runtime")]
3088 fn block_author() -> H160;
3089
3090 #[deprecated(note = "Use the versioned equivalent `address_versioned` if available on your runtime")]
3092 fn address(account_id: AccountId) -> H160;
3093
3094 #[deprecated(note = "Use the versioned equivalent `account_id_versioned` if available on your runtime")]
3096 fn account_id(address: H160) -> AccountId;
3097
3098 #[deprecated(note = "Use the versioned equivalent `runtime_pallets_address_versioned` if available on your runtime")]
3100 fn runtime_pallets_address() -> H160;
3101
3102 #[deprecated(note = "Use the versioned equivalent `code_versioned` if available on your runtime")]
3104 fn code(address: H160) -> Vec<u8>;
3105
3106 #[deprecated(note = "Use the versioned equivalent `new_balance_with_dust_versioned` if available on your runtime")]
3108 fn new_balance_with_dust(balance: U256) -> Result<(Balance, u32), BalanceConversionError>;
3109
3110 #[api_version(2)]
3113 fn version_declarations() -> ReviveRuntimeApiVersionDeclarations;
3114
3115 #[api_version(2)]
3116 fn eth_block_versioned(input: BlockVersionedInputPayload) -> BlockVersionedOutputPayload;
3117
3118 #[api_version(2)]
3119 fn eth_block_hash_versioned(input: BlockHashVersionedInputPayload) -> BlockHashVersionedOutputPayload;
3120
3121 #[api_version(2)]
3122 fn eth_receipt_data_versioned(input: ReceiptDataVersionedInputPayload) -> ReceiptDataVersionedOutputPayload;
3123
3124 #[api_version(2)]
3125 fn block_gas_limit_versioned(
3126 input: BlockGasLimitVersionedInputPayload
3127 ) -> BlockGasLimitVersionedOutputPayload;
3128
3129 #[api_version(2)]
3130 fn max_extrinsic_weight_in_gas_versioned(
3131 input: MaxExtrinsicWeightInGasVersionedInputPayload
3132 ) -> MaxExtrinsicWeightInGasVersionedOutputPayload;
3133
3134 #[api_version(2)]
3135 fn balance_versioned(input: BalanceVersionedInputPayload) -> BalanceVersionedOutputPayload;
3136
3137 #[api_version(2)]
3138 fn gas_price_versioned(input: GasPriceVersionedInputPayload) -> GasPriceVersionedOutputPayload;
3139
3140 #[api_version(2)]
3141 fn nonce_versioned(input: NonceVersionedInputPayload) -> NonceVersionedOutputPayload<Nonce>;
3142
3143 #[api_version(2)]
3144 fn call_versioned(
3145 input: CallVersionedInputPayload<AccountId, Balance>
3146 ) -> CallVersionedOutputPayload<Balance>;
3147
3148 #[api_version(2)]
3149 fn instantiate_versioned(
3150 input: InstantiateVersionedInputPayload<AccountId, Balance>
3151 ) -> InstantiateVersionedOutputPayload<Balance>;
3152
3153 #[api_version(2)]
3154 fn eth_transact_versioned(
3155 input: TransactVersionedInputPayload<Moment>
3156 ) -> Result<TransactVersionedOutputPayload<Balance>, EthTransactError>;
3157
3158 #[api_version(2)]
3159 fn eth_estimate_gas_versioned(
3160 input: EstimateGasVersionedInputPayload<Moment>
3161 ) -> Result<EstimateGasVersionedOutputPayload, EthTransactError>;
3162
3163 #[api_version(2)]
3164 fn eth_pre_dispatch_weight_versioned(
3165 input: PreDispatchWeightVersionedInputPayload
3166 ) -> Result<PreDispatchWeightVersionedOutputPayload, EthTransactError>;
3167
3168 #[api_version(2)]
3169 fn upload_code_versioned(
3170 input: UploadCodeVersionedInputPayload<AccountId, Balance>
3171 ) -> Result<UploadCodeVersionedOutputPayload<Balance>, DispatchError>;
3172
3173 #[api_version(2)]
3174 fn get_storage_versioned(
3175 input: GetStorageVersionedInputPayload
3176 ) -> Result<GetStorageVersionedOutputPayload, ContractAccessError>;
3177
3178 #[api_version(2)]
3179 fn runtime_pallets_address_versioned(
3180 input: RuntimePalletsAddressVersionedInputPayload
3181 ) -> RuntimePalletsAddressVersionedOutputPayload;
3182
3183 #[api_version(2)]
3184 fn code_versioned(input: CodeVersionedInputPayload) -> CodeVersionedOutputPayload;
3185
3186 #[api_version(2)]
3187 fn account_id_versioned(input: AccountIdVersionedInputPayload) -> AccountIdVersionedOutputPayload<AccountId>;
3188
3189 #[api_version(2)]
3190 fn new_balance_with_dust_versioned(
3191 input: NewBalanceWithDustVersionedInputPayload
3192 ) -> Result<NewBalanceWithDustVersionedOutputPayload<Balance>, BalanceConversionError>;
3193
3194 #[api_version(2)]
3195 fn block_author_versioned(input: BlockAuthorVersionedInputPayload) -> BlockAuthorVersionedOutputPayload;
3196
3197 #[api_version(2)]
3198 fn address_versioned(input: AddressVersionedInputPayload<AccountId>) -> AddressVersionedOutputPayload;
3199
3200 #[api_version(2)]
3201 fn trace_block_versioned(input: TraceBlockVersionedInputPayload<Block>) -> TraceBlockVersionedOutputPayload;
3202
3203 #[api_version(2)]
3204 fn trace_tx_versioned(input: TraceTxVersionedInputPayload<Block>) -> TraceTxVersionedOutputPayload;
3205
3206 #[api_version(2)]
3207 fn trace_call_versioned(
3208 input: TraceCallVersionedInputPayload
3209 ) -> Result<TraceCallVersionedOutputPayload, EthTransactError>;
3210 }
3211}
3212
3213#[macro_export]
3227macro_rules! impl_runtime_apis_plus_revive_traits {
3228 ($Runtime: ty, $Revive: ident, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
3229
3230 type __ReviveMacroMoment = $crate::MomentOf<$Runtime>;
3231
3232 impl $crate::evm::runtime::SetWeightLimit for RuntimeCall {
3233 fn set_weight_limit(&mut self, new_weight_limit: Weight) -> Weight {
3234 use $crate::pallet::Call as ReviveCall;
3235 match self {
3236 Self::$Revive(
3237 ReviveCall::eth_call{ weight_limit, .. } |
3238 ReviveCall::eth_instantiate_with_code{ weight_limit, .. }
3239 ) => {
3240 let old = *weight_limit;
3241 *weight_limit = new_weight_limit;
3242 old
3243 },
3244 _ => Weight::default(),
3245 }
3246 }
3247 }
3248
3249 impl_runtime_apis! {
3250 $($rest)*
3251
3252 #[api_version(2)]
3253 impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber, __ReviveMacroMoment> for $Runtime
3254 {
3255 fn eth_block() -> $crate::pallet_revive_types::runtime_api::BlockV1 {
3256 use $crate::pallet_revive_types::runtime_api::*;
3257
3258 let input = BlockVersionedInputPayload::from(BlockInputPayloadV1);
3259 let output = Self::eth_block_versioned(input);
3260 BlockOutputPayloadV1::try_from(output)
3261 .expect("v1 input must produce v1 output; qed")
3262 .block
3263 }
3264
3265 fn eth_block_hash(number: $crate::U256) -> Option<$crate::H256> {
3266 use $crate::pallet_revive_types::runtime_api::*;
3267
3268 let input = BlockHashVersionedInputPayload::from(BlockHashInputPayloadV1 {
3269 block_number: number
3270 });
3271 let output = Self::eth_block_hash_versioned(input);
3272 BlockHashOutputPayloadV1::try_from(output)
3273 .expect("v1 input must produce v1 output; qed")
3274 .block_hash
3275 }
3276
3277 fn eth_receipt_data() -> Vec<$crate::pallet_revive_types::runtime_api::ReceiptGasInfoV1> {
3278 use $crate::pallet_revive_types::runtime_api::*;
3279
3280 let input = ReceiptDataVersionedInputPayload::from(ReceiptDataInputPayloadV1);
3281 let output = Self::eth_receipt_data_versioned(input);
3282 ReceiptDataOutputPayloadV1::try_from(output)
3283 .expect("v1 input must produce v1 output; qed")
3284 .receipt_data
3285 }
3286
3287 fn balance(address: $crate::H160) -> $crate::U256 {
3288 use $crate::pallet_revive_types::runtime_api::*;
3289
3290 let input = BalanceVersionedInputPayload::from(BalanceInputPayloadV1 { address });
3291 let output = Self::balance_versioned(input);
3292 BalanceOutputPayloadV1::try_from(output)
3293 .expect("v1 input must produce v1 output; qed")
3294 .balance
3295 }
3296
3297 fn block_author() -> $crate::H160 {
3298 use $crate::pallet_revive_types::runtime_api::*;
3299
3300 let input = BlockAuthorVersionedInputPayload::from(BlockAuthorInputPayloadV1);
3301 let output = Self::block_author_versioned(input);
3302 BlockAuthorOutputPayloadV1::try_from(output)
3303 .expect("v1 input must produce v1 output; qed")
3304 .block_author
3305 }
3306
3307 fn block_gas_limit() -> $crate::U256 {
3308 use $crate::pallet_revive_types::runtime_api::*;
3309
3310 let input = BlockGasLimitVersionedInputPayload::from(BlockGasLimitInputPayloadV1);
3311 let output = Self::block_gas_limit_versioned(input);
3312 BlockGasLimitOutputPayloadV1::try_from(output)
3313 .expect("v1 input must produce v1 output; qed")
3314 .block_gas_limit
3315 }
3316
3317 fn max_extrinsic_weight_in_gas() -> $crate::U256 {
3318 use $crate::pallet_revive_types::runtime_api::*;
3319
3320 let input = MaxExtrinsicWeightInGasVersionedInputPayload::from(
3321 MaxExtrinsicWeightInGasInputPayloadV1
3322 );
3323 let output = Self::max_extrinsic_weight_in_gas_versioned(input);
3324 MaxExtrinsicWeightInGasOutputPayloadV1::try_from(output)
3325 .expect("v1 input must produce v1 output; qed")
3326 .max_extrinsic_weight_in_gas
3327 }
3328
3329 fn gas_price() -> $crate::U256 {
3330 use $crate::pallet_revive_types::runtime_api::*;
3331
3332 let input = GasPriceVersionedInputPayload::from(GasPriceInputPayloadV1);
3333 let output = Self::gas_price_versioned(input);
3334 GasPriceOutputPayloadV1::try_from(output)
3335 .expect("v1 input must produce v1 output; qed")
3336 .gas_price
3337 }
3338
3339 fn nonce(address: $crate::H160) -> Nonce {
3340 use $crate::pallet_revive_types::runtime_api::*;
3341
3342 let input = NonceVersionedInputPayload::from(NonceInputPayloadV1 { address });
3343 let output = Self::nonce_versioned(input);
3344 NonceOutputPayloadV1::try_from(output)
3345 .expect("v1 input must produce v1 output; qed")
3346 .nonce
3347 }
3348
3349 fn address(account_id: AccountId) -> $crate::H160 {
3350 use $crate::pallet_revive_types::runtime_api::*;
3351
3352 let input = AddressVersionedInputPayload::from(AddressInputPayloadV1 { account_id });
3353 let output = Self::address_versioned(input);
3354 AddressOutputPayloadV1::try_from(output)
3355 .expect("v1 input must produce v1 output; qed")
3356 .address
3357 }
3358
3359 fn eth_transact(
3360 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3361 ) -> Result<
3362 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3363 $crate::EthTransactError
3364 > {
3365 use $crate::pallet_revive_types::runtime_api::*;
3366
3367 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3368 tx,
3369 timestamp_override: None,
3370 perform_balance_checks: true,
3371 state_overrides: None
3372 });
3373 let output = Self::eth_transact_versioned(input)?;
3374 Ok(TransactOutputPayloadV1::try_from(output)
3375 .expect("v1 input must produce v1 output; qed")
3376 .transact_info)
3377 }
3378
3379 fn eth_transact_with_config(
3380 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3381 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3382 ) -> Result<
3383 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3384 $crate::EthTransactError
3385 > {
3386 use $crate::pallet_revive_types::runtime_api::*;
3387
3388 let DryRunConfigV1 { timestamp_override, perform_balance_checks, state_overrides } =
3389 config;
3390
3391 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3392 tx,
3393 timestamp_override,
3394 perform_balance_checks: perform_balance_checks.unwrap_or(false),
3395 state_overrides
3396 });
3397 let output = Self::eth_transact_versioned(input)?;
3398 Ok(TransactOutputPayloadV1::try_from(output)
3399 .expect("v1 input must produce v1 output; qed")
3400 .transact_info)
3401 }
3402
3403 fn eth_estimate_gas(
3404 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3405 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3406 ) -> Result<$crate::U256, $crate::EthTransactError> {
3407 use $crate::pallet_revive_types::runtime_api::*;
3408
3409 let DryRunConfigV1 { timestamp_override, perform_balance_checks: _, state_overrides } =
3410 config;
3411
3412 let input = EstimateGasVersionedInputPayload::from(EstimateGasInputPayloadV1 {
3413 tx,
3414 timestamp_override,
3415 state_overrides
3416 });
3417 let output = Self::eth_estimate_gas_versioned(input)?;
3418 Ok(EstimateGasOutputPayloadV1::try_from(output)
3419 .expect("v1 input must produce v1 output; qed")
3420 .gas_estimate)
3421 }
3422
3423 fn eth_pre_dispatch_weight(
3424 tx: Vec<u8>,
3425 ) -> Result<$crate::Weight, $crate::EthTransactError> {
3426 use $crate::pallet_revive_types::runtime_api::*;
3427
3428 let input = PreDispatchWeightVersionedInputPayload::from(
3429 PreDispatchWeightInputPayloadV1 { tx }
3430 );
3431 let output = Self::eth_pre_dispatch_weight_versioned(input)?;
3432 Ok(PreDispatchWeightOutputPayloadV1::try_from(output)
3433 .expect("v1 input must produce v1 output; qed")
3434 .weight)
3435 }
3436
3437 fn call(
3438 origin: AccountId,
3439 dest: $crate::H160,
3440 value: Balance,
3441 weight_limit: Option<$crate::Weight>,
3442 storage_deposit_limit: Option<Balance>,
3443 input_data: Vec<u8>,
3444 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3445 $crate::pallet_revive_types::runtime_api::ExecReturnValueV1,
3446 Balance
3447 > {
3448 use $crate::pallet_revive_types::runtime_api::*;
3449
3450 let input = CallVersionedInputPayload::from(CallInputPayloadV1 {
3451 origin,
3452 dest,
3453 value,
3454 gas_limit: weight_limit,
3455 storage_deposit_limit,
3456 input_data
3457 });
3458 let output = Self::call_versioned(input);
3459 CallOutputPayloadV1::try_from(output)
3460 .expect("v1 input must produce v1 output; qed")
3461 .contract_result
3462 }
3463
3464 fn instantiate(
3465 origin: AccountId,
3466 value: Balance,
3467 weight_limit: Option<$crate::Weight>,
3468 storage_deposit_limit: Option<Balance>,
3469 code: $crate::pallet_revive_types::runtime_api::CodeV1,
3470 data: Vec<u8>,
3471 salt: Option<[u8; 32]>,
3472 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3473 $crate::pallet_revive_types::runtime_api::InstantiateReturnValueV1,
3474 Balance
3475 > {
3476 use $crate::pallet_revive_types::runtime_api::*;
3477
3478 let input = InstantiateVersionedInputPayload::from(InstantiateInputPayloadV1 {
3479 origin,
3480 value,
3481 gas_limit: weight_limit,
3482 storage_deposit_limit,
3483 code,
3484 data,
3485 salt
3486 });
3487 let output = Self::instantiate_versioned(input);
3488 InstantiateOutputPayloadV1::try_from(output)
3489 .expect("v1 input must produce v1 output; qed")
3490 .contract_result
3491 }
3492
3493 fn upload_code(
3494 origin: AccountId,
3495 code: Vec<u8>,
3496 storage_deposit_limit: Option<Balance>,
3497 ) -> Result<$crate::pallet_revive_types::runtime_api::CodeUploadReturnValueV1<Balance>, $crate::sp_runtime::DispatchError> {
3498 use $crate::pallet_revive_types::runtime_api::*;
3499
3500 let input = UploadCodeVersionedInputPayload::from(UploadCodeInputPayloadV1 {
3501 origin,
3502 code,
3503 storage_deposit_limit
3504 });
3505 let output = Self::upload_code_versioned(input)?;
3506 Ok(UploadCodeOutputPayloadV1::try_from(output)
3507 .expect("v1 input must produce v1 output; qed")
3508 .code_upload_return_value)
3509 }
3510
3511 fn get_storage_var_key(
3512 address: $crate::H160,
3513 key: Vec<u8>,
3514 ) -> $crate::GetStorageResult {
3515 use $crate::pallet_revive_types::runtime_api::*;
3516
3517 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3518 address,
3519 key: StorageKeyV1::Variable(key)
3520 });
3521 let output = Self::get_storage_versioned(input)?;
3522 Ok(GetStorageOutputPayloadV1::try_from(output)
3523 .expect("v1 input must produce v1 output; qed")
3524 .storage)
3525 }
3526
3527 fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
3528 use $crate::pallet_revive_types::runtime_api::*;
3529
3530 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3531 address,
3532 key: StorageKeyV1::Fixed(key)
3533 });
3534 let output = Self::get_storage_versioned(input)?;
3535 Ok(GetStorageOutputPayloadV1::try_from(output)
3536 .expect("v1 input must produce v1 output; qed")
3537 .storage)
3538 }
3539
3540 fn trace_block(
3541 block: Block,
3542 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3543 ) -> Vec<(u32, $crate::pallet_revive_types::runtime_api::TraceV1)> {
3544 use $crate::pallet_revive_types::runtime_api::*;
3545
3546 let input = TraceBlockVersionedInputPayload::from(TraceBlockInputPayloadV1 {
3547 block,
3548 config: tracer_type
3549 });
3550 let output = Self::trace_block_versioned(input);
3551 TraceBlockOutputPayloadV1::try_from(output)
3552 .expect("v1 input must produce v1 output; qed")
3553 .traces
3554 }
3555
3556 fn trace_tx(
3557 block: Block,
3558 tx_index: u32,
3559 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3560 ) -> Option<$crate::pallet_revive_types::runtime_api::TraceV1> {
3561 use $crate::pallet_revive_types::runtime_api::*;
3562
3563 let input = TraceTxVersionedInputPayload::from(TraceTxInputPayloadV1 {
3564 block,
3565 tx_index,
3566 config: tracer_type
3567 });
3568 let output = Self::trace_tx_versioned(input);
3569 TraceTxOutputPayloadV1::try_from(output)
3570 .expect("v1 input must produce v1 output; qed")
3571 .trace
3572 }
3573
3574 fn trace_call(
3575 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3576 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3577 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3578 use $crate::pallet_revive_types::runtime_api::*;
3579
3580 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3581 tx,
3582 config: tracer_type,
3583 state_overrides: None
3584 });
3585 let output = Self::trace_call_versioned(input)?;
3586 Ok(TraceCallOutputPayloadV1::try_from(output)
3587 .expect("v1 input must produce v1 output; qed")
3588 .trace)
3589 }
3590
3591 fn trace_call_with_config(
3592 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3593 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3594 config: $crate::pallet_revive_types::runtime_api::TracingConfigV1,
3595 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3596 use $crate::pallet_revive_types::runtime_api::*;
3597
3598 let TracingConfigV1 { state_overrides } = config;
3599
3600 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3601 tx,
3602 config: tracer_type,
3603 state_overrides
3604 });
3605 let output = Self::trace_call_versioned(input)?;
3606 Ok(TraceCallOutputPayloadV1::try_from(output)
3607 .expect("v1 input must produce v1 output; qed")
3608 .trace)
3609 }
3610
3611 fn runtime_pallets_address() -> $crate::H160 {
3612 use $crate::pallet_revive_types::runtime_api::*;
3613
3614 let input = RuntimePalletsAddressVersionedInputPayload::from(
3615 RuntimePalletsAddressInputPayloadV1
3616 );
3617 let output = Self::runtime_pallets_address_versioned(input);
3618 RuntimePalletsAddressOutputPayloadV1::try_from(output)
3619 .expect("v1 input must produce v1 output; qed")
3620 .runtime_pallets_address
3621 }
3622
3623 fn code(address: $crate::H160) -> Vec<u8> {
3624 use $crate::pallet_revive_types::runtime_api::*;
3625
3626 let input = CodeVersionedInputPayload::from(CodeInputPayloadV1 { address });
3627 let output = Self::code_versioned(input);
3628 CodeOutputPayloadV1::try_from(output)
3629 .expect("v1 input must produce v1 output; qed")
3630 .code
3631 }
3632
3633 fn account_id(address: $crate::H160) -> AccountId {
3634 use $crate::pallet_revive_types::runtime_api::*;
3635
3636 let input = AccountIdVersionedInputPayload::from(AccountIdInputPayloadV1 { address });
3637 let output = Self::account_id_versioned(input);
3638 AccountIdOutputPayloadV1::try_from(output)
3639 .expect("v1 input must produce v1 output; qed")
3640 .account_id
3641 }
3642
3643 fn new_balance_with_dust(balance: $crate::U256) -> Result<(Balance, u32), $crate::BalanceConversionError> {
3644 use $crate::pallet_revive_types::runtime_api::*;
3645
3646 let input = NewBalanceWithDustVersionedInputPayload::from(
3647 NewBalanceWithDustInputPayloadV1 { balance }
3648 );
3649 let output = Self::new_balance_with_dust_versioned(input)?;
3650 let output = NewBalanceWithDustOutputPayloadV1::try_from(output)
3651 .expect("v1 input must produce v1 output; qed");
3652 Ok((output.new_balance, output.dust))
3653 }
3654
3655 fn version_declarations()
3658 -> $crate::pallet_revive_types::runtime_api::ReviveRuntimeApiVersionDeclarations
3659 {
3660 use $crate::pallet_revive_types::runtime_api::*;
3661
3662 ReviveRuntimeApiVersionDeclarations::new()
3663 .insert("eth_block_versioned", 1)
3664 .insert("eth_block_hash_versioned", 1)
3665 .insert("eth_receipt_data_versioned", 1)
3666 .insert("block_gas_limit_versioned", 1)
3667 .insert("max_extrinsic_weight_in_gas_versioned", 1)
3668 .insert("balance_versioned", 1)
3669 .insert("gas_price_versioned", 1)
3670 .insert("nonce_versioned", 1)
3671 .insert("call_versioned", 1)
3672 .insert("instantiate_versioned", 1)
3673 .insert("eth_transact_versioned", 1)
3674 .insert("eth_estimate_gas_versioned", 1)
3675 .insert("eth_pre_dispatch_weight_versioned", 1)
3676 .insert("upload_code_versioned", 1)
3677 .insert("get_storage_versioned", 1)
3678 .insert("runtime_pallets_address_versioned", 1)
3679 .insert("code_versioned", 1)
3680 .insert("account_id_versioned", 1)
3681 .insert("new_balance_with_dust_versioned", 1)
3682 .insert("block_author_versioned", 1)
3683 .insert("address_versioned", 1)
3684 .insert("trace_block_versioned", 2)
3685 .insert("trace_tx_versioned", 2)
3686 .insert("trace_call_versioned", 2)
3687 }
3688
3689 fn eth_block_versioned(
3690 input: $crate::pallet_revive_types::runtime_api::BlockVersionedInputPayload
3691 ) -> $crate::pallet_revive_types::runtime_api::BlockVersionedOutputPayload {
3692 use $crate::pallet_revive_types::runtime_api::*;
3693 use $crate::runtime_api::*;
3694 use alloc::boxed::Box;
3695
3696 let (_input, output_wrapper): (
3697 _,
3698 Box<dyn Fn(BlockOutputPayload) -> BlockVersionedOutputPayload>,
3699 ) = match input {
3700 BlockVersionedInputPayload::V1(payload) => (
3701 BlockInputPayload::from(payload),
3702 Box::new(|output| BlockVersionedOutputPayload::V1(output.into())),
3703 ),
3704 };
3705
3706 let output = BlockOutputPayload { block: $crate::Pallet::<Self>::eth_block() };
3707 output_wrapper(output)
3708 }
3709
3710 fn eth_block_hash_versioned(
3711 input: $crate::pallet_revive_types::runtime_api::BlockHashVersionedInputPayload
3712 ) -> $crate::pallet_revive_types::runtime_api::BlockHashVersionedOutputPayload {
3713 use $crate::pallet_revive_types::runtime_api::*;
3714 use $crate::runtime_api::*;
3715 use alloc::boxed::Box;
3716
3717 let (input, output_wrapper): (
3718 _,
3719 Box<dyn Fn(BlockHashOutputPayload) -> BlockHashVersionedOutputPayload>,
3720 ) = match input {
3721 BlockHashVersionedInputPayload::V1(payload) => (
3722 BlockHashInputPayload::from(payload),
3723 Box::new(|output| BlockHashVersionedOutputPayload::V1(output.into())),
3724 ),
3725 };
3726
3727 let output = BlockHashOutputPayload {
3728 block_hash: $crate::Pallet::<Self>::eth_block_hash_from_number(input.block_number)
3729 };
3730 output_wrapper(output)
3731 }
3732
3733 fn eth_receipt_data_versioned(
3734 input: $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedInputPayload
3735 ) -> $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedOutputPayload {
3736 use $crate::pallet_revive_types::runtime_api::*;
3737 use $crate::runtime_api::*;
3738 use alloc::boxed::Box;
3739
3740 let (_input, output_wrapper): (
3741 _,
3742 Box<dyn Fn(ReceiptDataOutputPayload) -> ReceiptDataVersionedOutputPayload>,
3743 ) = match input {
3744 ReceiptDataVersionedInputPayload::V1(payload) => (
3745 ReceiptDataInputPayload::from(payload),
3746 Box::new(|output| ReceiptDataVersionedOutputPayload::V1(output.into())),
3747 ),
3748 };
3749
3750 let output = ReceiptDataOutputPayload {
3751 receipt_data: $crate::Pallet::<Self>::eth_receipt_data()
3752 };
3753 output_wrapper(output)
3754 }
3755
3756 fn block_gas_limit_versioned(
3757 input: $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedInputPayload
3758 ) -> $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedOutputPayload {
3759 use $crate::pallet_revive_types::runtime_api::*;
3760 use $crate::runtime_api::*;
3761 use alloc::boxed::Box;
3762
3763 let (_input, output_wrapper): (
3764 _,
3765 Box<dyn Fn(BlockGasLimitOutputPayload) -> BlockGasLimitVersionedOutputPayload>,
3766 ) = match input {
3767 BlockGasLimitVersionedInputPayload::V1(payload) => (
3768 BlockGasLimitInputPayload::from(payload),
3769 Box::new(|output| BlockGasLimitVersionedOutputPayload::V1(output.into())),
3770 ),
3771 };
3772
3773 let output = BlockGasLimitOutputPayload {
3774 block_gas_limit: $crate::Pallet::<Self>::evm_block_gas_limit()
3775 };
3776 output_wrapper(output)
3777 }
3778
3779 fn max_extrinsic_weight_in_gas_versioned(
3780 input: $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedInputPayload
3781 ) -> $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedOutputPayload {
3782 use $crate::pallet_revive_types::runtime_api::*;
3783 use $crate::runtime_api::*;
3784 use alloc::boxed::Box;
3785
3786 let (_input, output_wrapper): (
3787 _,
3788 Box<dyn Fn(MaxExtrinsicWeightInGasOutputPayload) -> MaxExtrinsicWeightInGasVersionedOutputPayload>,
3789 ) = match input {
3790 MaxExtrinsicWeightInGasVersionedInputPayload::V1(payload) => (
3791 MaxExtrinsicWeightInGasInputPayload::from(payload),
3792 Box::new(|output| MaxExtrinsicWeightInGasVersionedOutputPayload::V1(output.into())),
3793 ),
3794 };
3795
3796 let output = MaxExtrinsicWeightInGasOutputPayload {
3797 max_extrinsic_weight_in_gas: $crate::Pallet::<Self>::evm_max_extrinsic_weight_in_gas()
3798 };
3799 output_wrapper(output)
3800 }
3801
3802 fn balance_versioned(
3803 input: $crate::pallet_revive_types::runtime_api::BalanceVersionedInputPayload
3804 ) -> $crate::pallet_revive_types::runtime_api::BalanceVersionedOutputPayload {
3805 use $crate::pallet_revive_types::runtime_api::*;
3806 use $crate::runtime_api::*;
3807 use alloc::boxed::Box;
3808
3809 let (input, output_wrapper): (
3810 _,
3811 Box<dyn Fn(BalanceOutputPayload) -> BalanceVersionedOutputPayload>,
3812 ) = match input {
3813 BalanceVersionedInputPayload::V1(payload) => (
3814 BalanceInputPayload::from(payload),
3815 Box::new(|output| BalanceVersionedOutputPayload::V1(output.into())),
3816 ),
3817 };
3818
3819 let output = BalanceOutputPayload {
3820 balance: $crate::Pallet::<Self>::evm_balance(&input.address)
3821 };
3822 output_wrapper(output)
3823 }
3824
3825 fn gas_price_versioned(
3826 input: $crate::pallet_revive_types::runtime_api::GasPriceVersionedInputPayload
3827 ) -> $crate::pallet_revive_types::runtime_api::GasPriceVersionedOutputPayload {
3828 use $crate::pallet_revive_types::runtime_api::*;
3829 use $crate::runtime_api::*;
3830 use alloc::boxed::Box;
3831
3832 let (_input, output_wrapper): (
3833 _,
3834 Box<dyn Fn(GasPriceOutputPayload) -> GasPriceVersionedOutputPayload>,
3835 ) = match input {
3836 GasPriceVersionedInputPayload::V1(payload) => (
3837 GasPriceInputPayload::from(payload),
3838 Box::new(|output| GasPriceVersionedOutputPayload::V1(output.into())),
3839 ),
3840 };
3841
3842 let output = GasPriceOutputPayload {
3843 gas_price: $crate::Pallet::<Self>::evm_base_fee()
3844 };
3845 output_wrapper(output)
3846 }
3847
3848 fn nonce_versioned(
3849 input: $crate::pallet_revive_types::runtime_api::NonceVersionedInputPayload
3850 ) -> $crate::pallet_revive_types::runtime_api::NonceVersionedOutputPayload<Nonce> {
3851 use $crate::pallet_revive_types::runtime_api::*;
3852 use $crate::runtime_api::*;
3853 use $crate::AddressMapper;
3854 use alloc::boxed::Box;
3855
3856 let (input, output_wrapper): (
3857 _,
3858 Box<dyn Fn(NonceOutputPayload<Nonce>) -> NonceVersionedOutputPayload<Nonce>>,
3859 ) = match input {
3860 NonceVersionedInputPayload::V1(payload) => (
3861 NonceInputPayload::from(payload),
3862 Box::new(|output| NonceVersionedOutputPayload::V1(output.into())),
3863 ),
3864 };
3865
3866 let account = <Self as $crate::Config>::AddressMapper::to_account_id(&input.address);
3867 let output = NonceOutputPayload {
3868 nonce: $crate::frame_system::Pallet::<Self>::account_nonce(account)
3869 };
3870 output_wrapper(output)
3871 }
3872
3873 fn call_versioned(
3874 input: $crate::pallet_revive_types::runtime_api::CallVersionedInputPayload<AccountId, Balance>
3875 ) -> $crate::pallet_revive_types::runtime_api::CallVersionedOutputPayload<Balance> {
3876 use $crate::pallet_revive_types::runtime_api::*;
3877 use $crate::runtime_api::*;
3878 use $crate::frame_support::traits::Get;
3879 use alloc::boxed::Box;
3880
3881 let (input, output_wrapper): (
3882 _,
3883 Box<dyn Fn(CallOutputPayload<Balance>) -> CallVersionedOutputPayload<Balance>>,
3884 ) = match input {
3885 CallVersionedInputPayload::V1(payload) => (
3886 CallInputPayload::from(payload),
3887 Box::new(|output| CallVersionedOutputPayload::V1(output.into())),
3888 ),
3889 };
3890
3891 let blockweights: $crate::BlockWeights =
3892 <Self as $crate::frame_system::Config>::BlockWeights::get();
3893
3894 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
3895 let contract_result = $crate::Pallet::<Self>::bare_call(
3896 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
3897 input.dest,
3898 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
3899 $crate::TransactionLimits::WeightAndDeposit {
3900 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
3901 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
3902 },
3903 input.input_data,
3904 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
3905 );
3906
3907 let output = CallOutputPayload { contract_result };
3908 output_wrapper(output)
3909 }
3910
3911 fn instantiate_versioned(
3912 input: $crate::pallet_revive_types::runtime_api::InstantiateVersionedInputPayload<AccountId, Balance>
3913 ) -> $crate::pallet_revive_types::runtime_api::InstantiateVersionedOutputPayload<Balance> {
3914 use $crate::pallet_revive_types::runtime_api::*;
3915 use $crate::runtime_api::*;
3916 use $crate::frame_support::traits::Get;
3917 use alloc::boxed::Box;
3918
3919 let (input, output_wrapper): (
3920 _,
3921 Box<dyn Fn(InstantiateOutputPayload<Balance>) -> InstantiateVersionedOutputPayload<Balance>>,
3922 ) = match input {
3923 InstantiateVersionedInputPayload::V1(payload) => (
3924 InstantiateInputPayload::from(payload),
3925 Box::new(|output| InstantiateVersionedOutputPayload::V1(output.into())),
3926 ),
3927 };
3928
3929 let blockweights: $crate::BlockWeights =
3930 <Self as $crate::frame_system::Config>::BlockWeights::get();
3931
3932 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
3933 let contract_result = $crate::Pallet::<Self>::bare_instantiate(
3934 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
3935 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
3936 $crate::TransactionLimits::WeightAndDeposit {
3937 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
3938 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
3939 },
3940 input.code,
3941 input.data,
3942 input.salt,
3943 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
3944 );
3945
3946 let output = InstantiateOutputPayload { contract_result };
3947 output_wrapper(output)
3948 }
3949
3950 fn eth_transact_versioned(
3951 input: $crate::pallet_revive_types::runtime_api::TransactVersionedInputPayload<__ReviveMacroMoment>
3952 ) -> Result<
3953 $crate::pallet_revive_types::runtime_api::TransactVersionedOutputPayload<Balance>,
3954 $crate::EthTransactError
3955 > {
3956 use $crate::pallet_revive_types::runtime_api::*;
3957 use $crate::runtime_api::*;
3958 use $crate::{
3959 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
3960 sp_runtime::traits::TransactionExtension,
3961 sp_runtime::traits::Block as BlockT
3962 };
3963 use alloc::boxed::Box;
3964
3965 let (input, output_wrapper): (
3966 _,
3967 Box<dyn Fn(TransactOutputPayload<Balance>) -> TransactVersionedOutputPayload<Balance>>,
3968 ) = match input {
3969 TransactVersionedInputPayload::V1(payload) => (
3970 TransactInputPayload::from(payload),
3971 Box::new(|output| TransactVersionedOutputPayload::V1(output.into())),
3972 ),
3973 };
3974
3975 let transact_info = $crate::Pallet::<Self>::dry_run_eth_transact(
3976 input.tx,
3977 input.timestamp_override,
3978 input.perform_balance_checks,
3979 input.state_overrides,
3980 )?;
3981 let output = TransactOutputPayload { transact_info };
3982 Ok(output_wrapper(output))
3983 }
3984
3985 fn eth_estimate_gas_versioned(
3986 input: $crate::pallet_revive_types::runtime_api::EstimateGasVersionedInputPayload<__ReviveMacroMoment>
3987 ) -> Result<
3988 $crate::pallet_revive_types::runtime_api::EstimateGasVersionedOutputPayload,
3989 $crate::EthTransactError
3990 > {
3991 use $crate::pallet_revive_types::runtime_api::*;
3992 use $crate::runtime_api::*;
3993 use $crate::{
3994 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
3995 sp_runtime::traits::TransactionExtension,
3996 sp_runtime::traits::Block as BlockT
3997 };
3998 use alloc::boxed::Box;
3999
4000 let (input, output_wrapper): (
4001 _,
4002 Box<dyn Fn(EstimateGasOutputPayload) -> EstimateGasVersionedOutputPayload>,
4003 ) = match input {
4004 EstimateGasVersionedInputPayload::V1(payload) => (
4005 EstimateGasInputPayload::from(payload),
4006 Box::new(|output| EstimateGasVersionedOutputPayload::V1(output.into())),
4007 ),
4008 };
4009
4010 let gas_estimate = $crate::Pallet::<Self>::eth_estimate_gas(
4011 input.tx,
4012 input.timestamp_override,
4013 input.state_overrides,
4014 )?;
4015 let output = EstimateGasOutputPayload { gas_estimate };
4016 Ok(output_wrapper(output))
4017 }
4018
4019 fn eth_pre_dispatch_weight_versioned(
4020 input: $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedInputPayload
4021 ) -> Result<
4022 $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedOutputPayload,
4023 $crate::EthTransactError
4024 > {
4025 use $crate::pallet_revive_types::runtime_api::*;
4026 use $crate::runtime_api::*;
4027 use alloc::boxed::Box;
4028
4029 let (input, output_wrapper): (
4030 _,
4031 Box<dyn Fn(PreDispatchWeightOutputPayload) -> PreDispatchWeightVersionedOutputPayload>,
4032 ) = match input {
4033 PreDispatchWeightVersionedInputPayload::V1(payload) => (
4034 PreDispatchWeightInputPayload::from(payload),
4035 Box::new(|output| PreDispatchWeightVersionedOutputPayload::V1(output.into())),
4036 ),
4037 };
4038
4039 let output = PreDispatchWeightOutputPayload {
4040 weight: $crate::Pallet::<Self>::eth_pre_dispatch_weight(input.tx)?
4041 };
4042 Ok(output_wrapper(output))
4043 }
4044
4045 fn upload_code_versioned(
4046 input: $crate::pallet_revive_types::runtime_api::UploadCodeVersionedInputPayload<AccountId, Balance>
4047 ) -> Result<
4048 $crate::pallet_revive_types::runtime_api::UploadCodeVersionedOutputPayload<Balance>,
4049 $crate::sp_runtime::DispatchError
4050 > {
4051 use $crate::pallet_revive_types::runtime_api::*;
4052 use $crate::runtime_api::*;
4053 use alloc::boxed::Box;
4054
4055 let (input, output_wrapper): (
4056 _,
4057 Box<dyn Fn(UploadCodeOutputPayload<Balance>) -> UploadCodeVersionedOutputPayload<Balance>>,
4058 ) = match input {
4059 UploadCodeVersionedInputPayload::V1(payload) => (
4060 UploadCodeInputPayload::from(payload),
4061 Box::new(|output| UploadCodeVersionedOutputPayload::V1(output.into())),
4062 ),
4063 };
4064
4065 let origin =
4066 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin);
4067 let code_upload_return_value = $crate::Pallet::<Self>::bare_upload_code(
4068 origin,
4069 input.code,
4070 input.storage_deposit_limit.unwrap_or(u128::MAX),
4071 )?;
4072 let output = UploadCodeOutputPayload { code_upload_return_value };
4073 Ok(output_wrapper(output))
4074 }
4075
4076 fn get_storage_versioned(
4077 input: $crate::pallet_revive_types::runtime_api::GetStorageVersionedInputPayload
4078 ) -> Result<
4079 $crate::pallet_revive_types::runtime_api::GetStorageVersionedOutputPayload,
4080 $crate::ContractAccessError
4081 > {
4082 use $crate::pallet_revive_types::runtime_api::*;
4083 use $crate::runtime_api::*;
4084 use alloc::boxed::Box;
4085
4086 let (input, output_wrapper): (
4087 _,
4088 Box<dyn Fn(GetStorageOutputPayload) -> GetStorageVersionedOutputPayload>,
4089 ) = match input {
4090 GetStorageVersionedInputPayload::V1(payload) => (
4091 GetStorageInputPayload::from(payload),
4092 Box::new(|output| GetStorageVersionedOutputPayload::V1(output.into())),
4093 ),
4094 };
4095
4096 let storage = match input.key {
4097 StorageKey::Fixed(key) => $crate::Pallet::<Self>::get_storage(input.address, key)?,
4098 StorageKey::Variable(key) => $crate::Pallet::<Self>::get_storage_var_key(input.address, key)?,
4099 };
4100 let output = GetStorageOutputPayload { storage };
4101 Ok(output_wrapper(output))
4102 }
4103
4104 fn runtime_pallets_address_versioned(
4105 input: $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedInputPayload
4106 ) -> $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedOutputPayload {
4107 use $crate::pallet_revive_types::runtime_api::*;
4108 use $crate::runtime_api::*;
4109 use alloc::boxed::Box;
4110
4111 let (_input, output_wrapper): (
4112 _,
4113 Box<dyn Fn(RuntimePalletsAddressOutputPayload) -> RuntimePalletsAddressVersionedOutputPayload>,
4114 ) = match input {
4115 RuntimePalletsAddressVersionedInputPayload::V1(payload) => (
4116 RuntimePalletsAddressInputPayload::from(payload),
4117 Box::new(|output| RuntimePalletsAddressVersionedOutputPayload::V1(output.into())),
4118 ),
4119 };
4120
4121 let output = RuntimePalletsAddressOutputPayload {
4122 runtime_pallets_address: $crate::RUNTIME_PALLETS_ADDR
4123 };
4124 output_wrapper(output)
4125 }
4126
4127 fn code_versioned(
4128 input: $crate::pallet_revive_types::runtime_api::CodeVersionedInputPayload
4129 ) -> $crate::pallet_revive_types::runtime_api::CodeVersionedOutputPayload {
4130 use $crate::pallet_revive_types::runtime_api::*;
4131 use $crate::runtime_api::*;
4132 use alloc::boxed::Box;
4133
4134 let (input, output_wrapper): (
4135 _,
4136 Box<dyn Fn(CodeOutputPayload) -> CodeVersionedOutputPayload>,
4137 ) = match input {
4138 CodeVersionedInputPayload::V1(payload) => (
4139 CodeInputPayload::from(payload),
4140 Box::new(|output| CodeVersionedOutputPayload::V1(output.into())),
4141 ),
4142 };
4143
4144 let output = CodeOutputPayload {
4145 code: $crate::Pallet::<Self>::code(&input.address)
4146 };
4147 output_wrapper(output)
4148 }
4149
4150 fn account_id_versioned(
4151 input: $crate::pallet_revive_types::runtime_api::AccountIdVersionedInputPayload
4152 ) -> $crate::pallet_revive_types::runtime_api::AccountIdVersionedOutputPayload<AccountId> {
4153 use $crate::pallet_revive_types::runtime_api::*;
4154 use $crate::runtime_api::*;
4155 use $crate::AddressMapper;
4156 use alloc::boxed::Box;
4157
4158 let (input, output_wrapper): (
4159 _,
4160 Box<dyn Fn(AccountIdOutputPayload<AccountId>) -> AccountIdVersionedOutputPayload<AccountId>>,
4161 ) = match input {
4162 AccountIdVersionedInputPayload::V1(payload) => (
4163 AccountIdInputPayload::from(payload),
4164 Box::new(|output| AccountIdVersionedOutputPayload::V1(output.into())),
4165 ),
4166 };
4167
4168 let output = AccountIdOutputPayload {
4169 account_id: <Self as $crate::Config>::AddressMapper::to_account_id(&input.address)
4170 };
4171 output_wrapper(output)
4172 }
4173
4174 fn new_balance_with_dust_versioned(
4175 input: $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedInputPayload
4176 ) -> Result<
4177 $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedOutputPayload<Balance>,
4178 $crate::BalanceConversionError
4179 > {
4180 use $crate::pallet_revive_types::runtime_api::*;
4181 use $crate::runtime_api::*;
4182 use alloc::boxed::Box;
4183
4184 let (input, output_wrapper): (
4185 _,
4186 Box<
4187 dyn Fn(NewBalanceWithDustOutputPayload<Balance>) -> NewBalanceWithDustVersionedOutputPayload<Balance>,
4188 >,
4189 ) = match input {
4190 NewBalanceWithDustVersionedInputPayload::V1(payload) => (
4191 NewBalanceWithDustInputPayload::from(payload),
4192 Box::new(|output| NewBalanceWithDustVersionedOutputPayload::V1(output.into())),
4193 ),
4194 };
4195
4196 let (new_balance, dust) = $crate::Pallet::<Self>::new_balance_with_dust(input.balance)?;
4197 let output = NewBalanceWithDustOutputPayload { new_balance, dust };
4198 Ok(output_wrapper(output))
4199 }
4200
4201 fn block_author_versioned(
4202 input: $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedInputPayload
4203 ) -> $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedOutputPayload {
4204 use $crate::pallet_revive_types::runtime_api::*;
4205 use $crate::runtime_api::*;
4206 use alloc::boxed::Box;
4207
4208 let (_input, output_wrapper): (
4209 _,
4210 Box<dyn Fn(BlockAuthorOutputPayload) -> BlockAuthorVersionedOutputPayload>,
4211 ) = match input {
4212 BlockAuthorVersionedInputPayload::V1(payload) => (
4213 BlockAuthorInputPayload::from(payload),
4214 Box::new(|output| BlockAuthorVersionedOutputPayload::V1(output.into())),
4215 ),
4216 };
4217
4218 let output = BlockAuthorOutputPayload {
4219 block_author: $crate::Pallet::<Self>::block_author()
4220 };
4221 output_wrapper(output)
4222 }
4223
4224 fn address_versioned(
4225 input: $crate::pallet_revive_types::runtime_api::AddressVersionedInputPayload<AccountId>
4226 ) -> $crate::pallet_revive_types::runtime_api::AddressVersionedOutputPayload {
4227 use $crate::pallet_revive_types::runtime_api::*;
4228 use $crate::runtime_api::*;
4229 use $crate::AddressMapper;
4230 use alloc::boxed::Box;
4231
4232 let (input, output_wrapper): (
4233 _,
4234 Box<dyn Fn(AddressOutputPayload) -> AddressVersionedOutputPayload>,
4235 ) = match input {
4236 AddressVersionedInputPayload::V1(payload) => (
4237 AddressInputPayload::from(payload),
4238 Box::new(|output| AddressVersionedOutputPayload::V1(output.into())),
4239 ),
4240 };
4241
4242 let output = AddressOutputPayload {
4243 address: <Self as $crate::Config>::AddressMapper::to_address(&input.account_id)
4244 };
4245 output_wrapper(output)
4246 }
4247
4248 fn trace_block_versioned(
4249 input: $crate::pallet_revive_types::runtime_api::TraceBlockVersionedInputPayload<Block>
4250 ) -> $crate::pallet_revive_types::runtime_api::TraceBlockVersionedOutputPayload {
4251 use $crate::{
4252 sp_runtime::traits::Block,
4253 tracing::trace,
4254 evm::TraceEntry,
4255 runtime_api::*,
4256 pallet_revive_types::runtime_api::*
4257 };
4258 use alloc::boxed::Box;
4259
4260 let (input, output_wrapper): (_, Box<dyn Fn(TraceBlockOutputPayload) -> TraceBlockVersionedOutputPayload>) = match input {
4261 TraceBlockVersionedInputPayload::V1(payload) => (
4262 TraceBlockInputPayload::from(payload),
4263 Box::new(|output| TraceBlockVersionedOutputPayload::V1(output.into()))
4264 ),
4265 TraceBlockVersionedInputPayload::V2(payload) => (
4266 TraceBlockInputPayload::from(payload),
4267 Box::new(|output| TraceBlockVersionedOutputPayload::V2(output.into()))
4268 ),
4269 };
4270
4271 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4272 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4273 {
4274 return output_wrapper(Default::default())
4275 }
4276
4277 let mut entries = vec![];
4281 let (header, extrinsics) = input.block.deconstruct();
4282 <$Executive>::initialize_block(&header);
4283 for (index, ext) in extrinsics.into_iter().enumerate() {
4284 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4285 let t = tracer.as_tracing();
4286 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4287
4288 if let Some(tx_trace) = tracer.collect_trace() {
4289 entries.push((index as u32, TraceEntry::Traced(tx_trace)));
4290 } else if let Some(entry) = TraceEntry::for_untraced(&result) {
4291 entries.push((index as u32, entry));
4292 }
4293 }
4294
4295 let output = TraceBlockOutputPayload { entries };
4296 output_wrapper(output)
4297 }
4298
4299 fn trace_tx_versioned(
4300 input: $crate::pallet_revive_types::runtime_api::TraceTxVersionedInputPayload<Block>
4301 ) -> $crate::pallet_revive_types::runtime_api::TraceTxVersionedOutputPayload {
4302 use $crate::pallet_revive_types::runtime_api::*;
4303 use $crate::runtime_api::*;
4304 use $crate::{evm::TraceEntry, sp_runtime::traits::Block, tracing::trace};
4305 use alloc::boxed::Box;
4306
4307 let (input, output_wrapper): (
4308 _,
4309 Box<dyn Fn(TraceTxOutputPayload) -> TraceTxVersionedOutputPayload>,
4310 ) = match input {
4311 TraceTxVersionedInputPayload::V1(payload) => (
4312 TraceTxInputPayload::from(payload),
4313 Box::new(|output| TraceTxVersionedOutputPayload::V1(output.into())),
4314 ),
4315 TraceTxVersionedInputPayload::V2(payload) => (
4316 TraceTxInputPayload::from(payload),
4317 Box::new(|output| TraceTxVersionedOutputPayload::V2(output.into())),
4318 ),
4319 };
4320
4321 if matches!(&input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4322 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4323 {
4324 return output_wrapper(TraceTxOutputPayload { entry: None })
4325 }
4326
4327 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config);
4331 let (header, extrinsics) = input.block.deconstruct();
4332
4333 <$Executive>::initialize_block(&header);
4334 let mut entry = None;
4335 for (index, ext) in extrinsics.into_iter().enumerate() {
4336 if index as u32 == input.tx_index {
4337 let t = tracer.as_tracing();
4338 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4339 entry = match tracer.collect_trace() {
4340 Some(tx_trace) => Some(TraceEntry::Traced(tx_trace)),
4341 None => TraceEntry::for_untraced(&result),
4342 };
4343 break;
4344 } else {
4345 let _ = <$Executive>::apply_extrinsic(ext);
4346 }
4347 }
4348
4349 let output = TraceTxOutputPayload { entry };
4350 output_wrapper(output)
4351 }
4352
4353 fn trace_call_versioned(
4354 input: $crate::pallet_revive_types::runtime_api::TraceCallVersionedInputPayload
4355 ) -> Result<
4356 $crate::pallet_revive_types::runtime_api::TraceCallVersionedOutputPayload,
4357 $crate::EthTransactError
4358 > {
4359 use $crate::pallet_revive_types::runtime_api::*;
4360 use $crate::runtime_api::*;
4361 use $crate::tracing::trace;
4362 use alloc::boxed::Box;
4363
4364 let (input, output_wrapper): (
4365 _,
4366 Box<dyn Fn(TraceCallOutputPayload) -> TraceCallVersionedOutputPayload>,
4367 ) = match input {
4368 TraceCallVersionedInputPayload::V1(payload) => (
4369 TraceCallInputPayload::from(payload),
4370 Box::new(|output| TraceCallVersionedOutputPayload::V1(output.into())),
4371 ),
4372 TraceCallVersionedInputPayload::V2(payload) => (
4373 TraceCallInputPayload::from(payload),
4374 Box::new(|output| TraceCallVersionedOutputPayload::V2(output.into())),
4375 ),
4376 };
4377
4378 if let Some(overrides) = input.state_overrides {
4379 $crate::state_overrides::apply_state_overrides::<Runtime>(overrides)?;
4380 }
4381
4382 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4383 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4384 {
4385 return Err($crate::EthTransactError::Message("Execution Tracing is disabled".into()))
4386 }
4387
4388 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4389 let t = tracer.as_tracing();
4390
4391 t.watch_address(&input.tx.from.unwrap_or_default());
4392 t.watch_address(&$crate::Pallet::<Self>::block_author());
4393 let result = trace(t, || {
4394 $crate::Pallet::<Self>::dry_run_eth_transact(input.tx, None, true, None)
4395 });
4396
4397 let trace = if let Some(trace) = tracer.collect_trace() {
4398 Ok(trace)
4399 } else if let Err(err) = result {
4400 Err(err)
4401 } else {
4402 Ok($crate::Pallet::<Self>::evm_tracer(input.config).empty_trace())
4403 }?;
4404
4405 let output = TraceCallOutputPayload { trace };
4406 Ok(output_wrapper(output))
4407 }
4408 }
4409 }
4410 };
4411}