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::Warmth,
58 evm::{
59 CallTracer, CreateCallMode, ExecutionTracer, GenericTransaction, PrestateTracer,
60 StateOverrideSet, TYPE_EIP1559, TYPE_EIP7702, Tracer, TracerType,
61 block_hash::EthereumBlockBuilderIR, block_storage, fees::InfoT as FeeInfo,
62 runtime::SetWeightLimit,
63 },
64 exec::{AccountIdOf, ExecError, Stack as ExecStack},
65 sp_runtime::TransactionOutcome,
66 storage::{AccountType, DeletionQueueManager},
67 tracing::if_tracing,
68 vm::{CodeInfo, RuntimeCosts, StorageAccessKind, pvm::extract_code_and_data},
69 weightinfo_extension::OnFinalizeBlockParts,
70};
71use alloc::{boxed::Box, format, vec};
72use codec::{Codec, Decode, Encode, MaxEncodedLen};
73use environmental::*;
74use frame_support::{
75 BoundedVec,
76 dispatch::{
77 DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
78 Pays, PostDispatchInfo, RawOrigin,
79 },
80 ensure,
81 pallet_prelude::DispatchClass,
82 storage::with_transaction,
83 traits::{
84 ConstU32, ConstU64, DefensiveResult, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced,
85 OriginTrait,
86 fungible::{Balanced, Credit, Inspect, Mutate, MutateHold},
87 tokens::Balance,
88 },
89 weights::WeightMeter,
90};
91use frame_system::{
92 Pallet as System, ensure_signed,
93 pallet_prelude::{BlockNumberFor, OriginFor},
94};
95use pallet_revive_types::runtime_api::*;
96use scale_info::TypeInfo;
97use sp_runtime::{
98 AccountId32, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion,
99 traits::{
100 BadOrigin, Bounded, Convert, Dispatchable, Saturating, UniqueSaturatedFrom,
101 UniqueSaturatedInto, Zero,
102 },
103};
104
105pub use crate::{
106 address::{AccountId32Mapper, AddressMapper, AutoMapper, TestAccountMapper, create1, create2},
107 debug::DebugSettings,
108 deposit_payment::{Deposit, PGasDeposit},
109 evm::{Address as EthAddress, Block as EthBlock, block_hash::ReceiptGasInfo},
110 exec::{
111 CallResources, DelegateInfo, Executable, Key, MomentOf, Origin as ExecOrigin,
112 ReentrancyProtection,
113 },
114 limits::TRANSIENT_STORAGE_BYTES as TRANSIENT_STORAGE_LIMIT,
115 metering::{
116 EthTxInfo, FrameMeter, ResourceMeter, Token as WeightToken, TransactionLimits,
117 TransactionMeter,
118 },
119 pallet::{genesis, *},
120 storage::{AccountInfo, ContractInfo},
121 transient_storage::{MeterEntry, StorageMeter as TransientStorageMeter, TransientStorage},
122 vm::{BytecodeType, ContractBlob},
123};
124pub use codec;
125use frame_support::traits::tokens::Precision;
126pub use frame_support::{self, dispatch::DispatchInfo, traits::Time, weights::Weight};
127pub use frame_system::{self, limits::BlockWeights};
128pub use primitives::*;
129pub use sp_core::{H160, H256, U256};
130pub use sp_crypto_hashing::keccak_256;
131pub use sp_runtime;
132pub use weights::WeightInfo;
133
134pub extern crate pallet_revive_types;
136
137#[cfg(doc)]
138pub use crate::vm::pvm::SyscallDoc;
139
140pub type BalanceOf<T> = <T as Config>::Balance;
141pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
142type TrieId = BoundedVec<u8, ConstU32<128>>;
143type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
144type CallOf<T> = <T as Config>::RuntimeCall;
145
146const SENTINEL: u32 = u32::MAX;
153
154const LOG_TARGET: &str = "runtime::revive";
160
161#[frame_support::pallet]
162pub mod pallet {
163 use super::*;
164 use frame_support::{pallet_prelude::*, traits::FindAuthor};
165 use frame_system::pallet_prelude::*;
166 use sp_core::U256;
167 use sp_runtime::Perbill;
168
169 pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
171
172 #[pallet::pallet]
173 #[pallet::storage_version(STORAGE_VERSION)]
174 pub struct Pallet<T>(_);
175
176 #[pallet::config(with_default)]
177 pub trait Config: frame_system::Config {
178 type Time: Time<Moment: Into<U256>>;
180
181 #[pallet::no_default]
185 type Balance: Balance
186 + TryFrom<U256>
187 + Into<U256>
188 + Bounded
189 + UniqueSaturatedInto<u64>
190 + UniqueSaturatedFrom<u64>
191 + UniqueSaturatedInto<u128>;
192
193 #[pallet::no_default]
195 type Currency: Inspect<Self::AccountId, Balance = Self::Balance>
196 + Mutate<Self::AccountId>
197 + MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>
198 + Balanced<Self::AccountId>;
199
200 #[pallet::no_default_bounds]
207 type OnBurn: OnUnbalanced<CreditOf<Self>>;
208
209 #[pallet::no_default_bounds]
211 #[allow(deprecated)]
212 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
213
214 #[pallet::no_default_bounds]
216 type RuntimeCall: Parameter
217 + Dispatchable<
218 RuntimeOrigin = OriginFor<Self>,
219 Info = DispatchInfo,
220 PostInfo = PostDispatchInfo,
221 > + IsType<<Self as frame_system::Config>::RuntimeCall>
222 + From<Call<Self>>
223 + IsSubType<Call<Self>>
224 + GetDispatchInfo;
225
226 #[pallet::no_default_bounds]
228 type RuntimeOrigin: IsType<OriginFor<Self>>
229 + From<Origin<Self>>
230 + Into<Result<Origin<Self>, OriginFor<Self>>>;
231
232 #[pallet::no_default_bounds]
234 type RuntimeHoldReason: From<HoldReason>;
235
236 type WeightInfo: WeightInfo;
239
240 #[pallet::no_default_bounds]
244 #[allow(private_bounds)]
245 type Precompiles: precompiles::Precompiles<Self>;
246
247 type FindAuthor: FindAuthor<Self::AccountId>;
249
250 #[pallet::constant]
256 #[pallet::no_default_bounds]
257 type DepositPerByte: Get<BalanceOf<Self>>;
258
259 #[pallet::constant]
265 #[pallet::no_default_bounds]
266 type DepositPerItem: Get<BalanceOf<Self>>;
267
268 #[pallet::constant]
278 #[pallet::no_default_bounds]
279 type DepositPerChildTrieItem: Get<BalanceOf<Self>>;
280
281 #[pallet::constant]
285 type CodeHashLockupDepositPercent: Get<Perbill>;
286
287 #[pallet::no_default]
289 type AddressMapper: AddressMapper<Self>;
290
291 #[pallet::constant]
293 type AllowEVMBytecode: Get<bool>;
294
295 #[pallet::no_default_bounds]
300 type UploadOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
301
302 #[pallet::no_default_bounds]
313 type InstantiateOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
314
315 type RuntimeMemory: Get<u32>;
320
321 type PVFMemory: Get<u32>;
329
330 #[pallet::constant]
335 type ChainId: Get<u64>;
336
337 #[pallet::constant]
339 type NativeToEthRatio: Get<u32>;
340
341 #[pallet::no_default_bounds]
346 type FeeInfo: FeeInfo<Self>;
347
348 #[pallet::no_default_bounds]
351 type Deposit: Deposit<Self>;
352
353 #[pallet::constant]
366 type MaxEthExtrinsicWeight: Get<FixedU128>;
367
368 #[pallet::constant]
370 type DebugEnabled: Get<bool>;
371
372 #[pallet::constant]
379 type AutoMap: Get<bool>;
380
381 #[pallet::constant]
399 #[pallet::no_default_bounds]
400 type GasScale: Get<u32>;
401 }
402
403 pub mod config_preludes {
405 use super::*;
406 use frame_support::{
407 derive_impl,
408 traits::{ConstBool, ConstU32},
409 };
410 use frame_system::EnsureSigned;
411 use sp_core::parameter_types;
412
413 type Balance = u64;
414
415 pub const DOLLARS: Balance = 1_000_000_000_000;
416 pub const CENTS: Balance = DOLLARS / 100;
417 pub const MILLICENTS: Balance = CENTS / 1_000;
418
419 pub const fn deposit(items: u32, bytes: u32) -> Balance {
420 items as Balance * 20 * CENTS + (bytes as Balance) * MILLICENTS
421 }
422
423 parameter_types! {
424 pub const DepositPerItem: Balance = deposit(1, 0);
425 pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
426 pub const DepositPerByte: Balance = deposit(0, 1);
427 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
428 pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(9, 10);
429 pub const GasScale: u32 = 10u32;
430 }
431
432 pub struct TestDefaultConfig;
434
435 impl Time for TestDefaultConfig {
436 type Moment = u64;
437 fn now() -> Self::Moment {
438 0u64
439 }
440 }
441
442 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
443 fn convert(w: Weight) -> T {
444 w.ref_time().into()
445 }
446 }
447
448 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
449 impl frame_system::DefaultConfig for TestDefaultConfig {}
450
451 #[frame_support::register_default_impl(TestDefaultConfig)]
452 impl DefaultConfig for TestDefaultConfig {
453 #[inject_runtime_type]
454 type RuntimeEvent = ();
455
456 #[inject_runtime_type]
457 type RuntimeHoldReason = ();
458
459 #[inject_runtime_type]
460 type RuntimeCall = ();
461
462 #[inject_runtime_type]
463 type RuntimeOrigin = ();
464
465 type Precompiles = ();
466 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
467 type DepositPerByte = DepositPerByte;
468 type DepositPerItem = DepositPerItem;
469 type DepositPerChildTrieItem = DepositPerChildTrieItem;
470 type Time = Self;
471 type AllowEVMBytecode = ConstBool<true>;
472 type UploadOrigin = EnsureSigned<Self::AccountId>;
473 type InstantiateOrigin = EnsureSigned<Self::AccountId>;
474 type WeightInfo = ();
475 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
476 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
477 type ChainId = ConstU64<42>;
478 type NativeToEthRatio = ConstU32<1_000_000>;
479 type FindAuthor = ();
480 type FeeInfo = ();
481 type Deposit = ();
482 type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
483 type DebugEnabled = ConstBool<false>;
484 type AutoMap = ConstBool<false>;
485 type GasScale = GasScale;
486 type OnBurn = ();
487 }
488 }
489
490 #[pallet::event]
491 pub enum Event<T: Config> {
492 ContractEmitted {
494 contract: H160,
496 data: Vec<u8>,
499 topics: Vec<H256>,
502 },
503
504 Instantiated { deployer: H160, contract: H160 },
506
507 EthExtrinsicRevert { dispatch_error: DispatchError },
514 }
515
516 #[pallet::error]
517 #[repr(u8)]
518 pub enum Error<T> {
519 InvalidSchedule = 0x01,
521 InvalidCallFlags = 0x02,
523 OutOfGas = 0x03,
525 TransferFailed = 0x04,
528 MaxCallDepthReached = 0x05,
531 ContractNotFound = 0x06,
533 CodeNotFound = 0x07,
535 CodeInfoNotFound = 0x08,
537 OutOfBounds = 0x09,
539 DecodingFailed = 0x0A,
541 ContractTrapped = 0x0B,
543 ValueTooLarge = 0x0C,
545 TerminatedWhileReentrant = 0x0D,
548 InputForwarded = 0x0E,
550 TooManyTopics = 0x0F,
552 DuplicateContract = 0x12,
554 TerminatedInConstructor = 0x13,
558 ReentranceDenied = 0x14,
560 ReenteredPallet = 0x15,
562 StateChangeDenied = 0x16,
564 StorageDepositNotEnoughFunds = 0x17,
566 StorageDepositLimitExhausted = 0x18,
568 CodeInUse = 0x19,
570 ContractReverted = 0x1A,
575 CodeRejected = 0x1B,
580 BlobTooLarge = 0x1C,
582 StaticMemoryTooLarge = 0x1D,
584 BasicBlockTooLarge = 0x1E,
586 InvalidInstruction = 0x1F,
588 MaxDelegateDependenciesReached = 0x20,
590 DelegateDependencyNotFound = 0x21,
592 DelegateDependencyAlreadyExists = 0x22,
594 CannotAddSelfAsDelegateDependency = 0x23,
596 OutOfTransientStorage = 0x24,
598 InvalidSyscall = 0x25,
600 InvalidStorageFlags = 0x26,
602 ExecutionFailed = 0x27,
604 BalanceConversionFailed = 0x28,
606 InvalidImmutableAccess = 0x2A,
609 AccountUnmapped = 0x2B,
613 AccountAlreadyMapped = 0x2C,
615 InvalidGenericTransaction = 0x2D,
617 RefcountOverOrUnderflow = 0x2E,
619 UnsupportedPrecompileAddress = 0x2F,
621 CallDataTooLarge = 0x30,
623 ReturnDataTooLarge = 0x31,
625 InvalidJump = 0x32,
627 StackUnderflow = 0x33,
629 StackOverflow = 0x34,
631 TxFeeOverdraw = 0x35,
635 EvmConstructorNonEmptyData = 0x36,
639 EvmConstructedFromHash = 0x37,
644 StorageRefundNotEnoughFunds = 0x38,
648 StorageRefundLocked = 0x39,
653 PrecompileDelegateDenied = 0x40,
658 EcdsaRecoveryFailed = 0x41,
660 AutoMappingEnabled = 0x42,
662 PendingDepositCleanup = 0x43,
666 CannotTerminateDelegatedAccount = 0x44,
669 #[cfg(feature = "runtime-benchmarks")]
671 BenchmarkingError = 0xFF,
672 }
673
674 #[pallet::composite_enum]
676 pub enum HoldReason {
677 CodeUploadDepositReserve,
679 StorageDepositReserve,
681 AddressMapping,
683 }
684
685 #[pallet::composite_enum]
687 pub enum FreezeReason {
688 PGasMinBalance,
693 }
694
695 #[derive(
696 PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug,
697 )]
698 #[pallet::origin]
699 pub enum Origin<T: Config> {
700 EthTransaction(T::AccountId),
701 }
702
703 #[pallet::storage]
707 #[pallet::unbounded]
708 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, Vec<u8>>;
709
710 #[pallet::storage]
712 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
713
714 #[pallet::storage]
716 pub(crate) type AccountInfoOf<T: Config> = StorageMap<_, Identity, H160, AccountInfo<T>>;
717
718 #[pallet::storage]
729 pub(crate) type NativeDepositOf<T: Config> = StorageDoubleMap<
730 _,
731 Identity,
732 T::AccountId,
733 Identity,
734 T::AccountId,
735 BalanceOf<T>,
736 ValueQuery,
737 >;
738
739 #[pallet::storage]
741 pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
742
743 #[pallet::storage]
749 pub(crate) type DeletionQueue<T: Config> =
750 StorageMap<_, Twox64Concat, u32, crate::storage::DeletionQueueItem<T>>;
751
752 #[pallet::storage]
755 pub(crate) type DeletionQueueCounter<T: Config> =
756 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
757
758 #[pallet::storage]
765 pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
766
767 #[pallet::storage]
777 #[pallet::unbounded]
778 pub(crate) type EthereumBlock<T> = StorageValue<_, EthBlock, ValueQuery>;
779
780 #[pallet::storage]
784 pub(crate) type BlockHash<T: Config> =
785 StorageMap<_, Identity, BlockNumberFor<T>, H256, ValueQuery>;
786
787 #[pallet::storage]
794 #[pallet::unbounded]
795 pub(crate) type ReceiptInfoData<T: Config> = StorageValue<_, Vec<ReceiptGasInfo>, ValueQuery>;
796
797 #[pallet::storage]
799 #[pallet::unbounded]
800 pub(crate) type EthBlockBuilderIR<T: Config> =
801 StorageValue<_, EthereumBlockBuilderIR<T>, ValueQuery>;
802
803 #[pallet::storage]
808 #[pallet::unbounded]
809 pub(crate) type EthBlockBuilderFirstValues<T: Config> =
810 StorageValue<_, Option<(Vec<u8>, Vec<u8>)>, ValueQuery>;
811
812 #[pallet::storage]
814 pub(crate) type DebugSettingsOf<T: Config> = StorageValue<_, DebugSettings, ValueQuery>;
815
816 pub mod genesis {
817 use super::*;
818 use crate::evm::Bytes32;
819
820 #[derive(Clone, PartialEq, Debug, Default, serde::Serialize, serde::Deserialize)]
822 pub struct ContractData {
823 pub code: crate::evm::Bytes,
825 pub storage: alloc::collections::BTreeMap<Bytes32, Bytes32>,
827 }
828
829 #[derive(PartialEq, Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
831 pub struct Account<T: Config> {
832 pub address: H160,
834 #[serde(default)]
836 pub balance: U256,
837 #[serde(default)]
839 pub nonce: T::Nonce,
840 #[serde(flatten, skip_serializing_if = "Option::is_none")]
842 pub contract_data: Option<ContractData>,
843 }
844 }
845
846 #[pallet::genesis_config]
847 #[derive(Debug, PartialEq, frame_support::DefaultNoBound)]
848 pub struct GenesisConfig<T: Config> {
849 #[serde(default, skip_serializing_if = "Vec::is_empty")]
852 pub mapped_accounts: Vec<T::AccountId>,
853
854 #[serde(default, skip_serializing_if = "Vec::is_empty")]
856 pub accounts: Vec<genesis::Account<T>>,
857
858 #[serde(default, skip_serializing_if = "Option::is_none")]
860 pub debug_settings: Option<DebugSettings>,
861 }
862
863 #[pallet::genesis_build]
864 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
865 fn build(&self) {
866 use crate::{exec::Key, vm::ContractBlob};
867 use frame_support::traits::fungible::Mutate;
868
869 if !System::<T>::account_exists(&Pallet::<T>::account_id()) {
870 let _ = T::Currency::mint_into(
871 &Pallet::<T>::account_id(),
872 T::Currency::minimum_balance(),
873 );
874 }
875
876 for id in &self.mapped_accounts {
877 if let Err(err) = T::AddressMapper::map_no_deposit_unchecked(id) {
878 log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
879 }
880 }
881
882 let owner = Pallet::<T>::account_id();
883
884 for genesis::Account { address, balance, nonce, contract_data } in &self.accounts {
885 let account_id = T::AddressMapper::to_account_id(address);
886
887 if !System::<T>::account_exists(&account_id) {
888 let _ = T::Currency::mint_into(&account_id, T::Currency::minimum_balance());
889 }
890
891 frame_system::Account::<T>::mutate(&account_id, |info| {
892 info.nonce = (*nonce).into();
893 });
894
895 match contract_data {
896 None => {
897 AccountInfoOf::<T>::insert(
898 address,
899 AccountInfo { account_type: AccountType::EOA, dust: 0 },
900 );
901 },
902 Some(genesis::ContractData { code, storage }) => {
903 let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) {
904 ContractBlob::<T>::from_pvm_code(code.0.clone(), owner.clone())
905 .inspect_err(|err| {
906 log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}");
907 })
908 } else {
909 ContractBlob::<T>::from_evm_runtime_code(code.0.clone(), account_id)
910 .inspect_err(|err| {
911 log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}");
912 })
913 };
914
915 let Ok(blob) = blob else {
916 continue;
917 };
918
919 let code_hash = *blob.code_hash();
920 let Ok(info) = <ContractInfo<T>>::new(&address, 0u32.into(), code_hash)
921 .inspect_err(|err| {
922 log::error!(target: LOG_TARGET, "Failed to create ContractInfo for {address:?}: {err:?}");
923 })
924 else {
925 continue;
926 };
927
928 AccountInfoOf::<T>::insert(
929 address,
930 AccountInfo { account_type: info.clone().into(), dust: 0 },
931 );
932
933 <PristineCode<T>>::insert(blob.code_hash(), code.0.clone());
934 <CodeInfoOf<T>>::insert(blob.code_hash(), blob.code_info().clone());
935 for (k, v) in storage {
936 let _ = info.write(&Key::from_fixed(k.0), Some(v.0.to_vec()), None, false).inspect_err(|err| {
937 log::error!(target: LOG_TARGET, "Failed to write genesis storage for {address:?} at key {k:?}: {err:?}");
938 });
939 }
940 },
941 }
942
943 let _ = Pallet::<T>::set_evm_balance(address, *balance).inspect_err(|err| {
944 log::error!(target: LOG_TARGET, "Failed to set EVM balance for {address:?}: {err:?}");
945 });
946 }
947
948 block_storage::on_finalize_build_eth_block::<T>(
950 frame_system::Pallet::<T>::block_number(),
953 );
954
955 if let Some(settings) = self.debug_settings.as_ref() {
957 settings.write_to_storage::<T>()
958 }
959 }
960 }
961
962 #[pallet::hooks]
963 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
964 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
965 let mut meter = WeightMeter::with_limit(limit);
966 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
967 meter.consumed()
968 }
969
970 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
971 block_storage::on_initialize::<T>();
973
974 System::<T>::account_exists(&Pallet::<T>::account_id());
976 <T as Config>::WeightInfo::on_finalize_block_fixed()
978 }
979
980 fn on_finalize(block_number: BlockNumberFor<T>) {
981 block_storage::on_finalize_build_eth_block::<T>(block_number);
983 }
984
985 fn integrity_test() {
986 assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
987
988 assert!(T::GasScale::get() > 0u32.into(), "GasScale must not be 0");
989
990 T::FeeInfo::integrity_test();
991
992 let max_runtime_mem: u64 = T::RuntimeMemory::get().into();
994
995 const TOTAL_MEMORY_DEVIDER: u64 = 2;
998
999 let max_block_weight = T::BlockWeights::get()
1005 .get(DispatchClass::Normal)
1006 .max_total
1007 .unwrap_or_else(|| T::BlockWeights::get().max_block);
1008 let max_key_size: u64 =
1009 Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
1010 .expect("Key of maximal size shall be created")
1011 .hash()
1012 .len()
1013 .try_into()
1014 .unwrap();
1015
1016 let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
1017 let max_immutable_size: u64 = max_block_weight
1018 .checked_div_per_component(&<RuntimeCosts as WeightToken<T>>::weight(
1019 &RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
1020 ))
1021 .unwrap()
1022 .saturating_mul(
1023 u64::from(limits::IMMUTABLE_BYTES)
1024 .saturating_add(max_immutable_key_size)
1025 .into(),
1026 );
1027
1028 let max_pvf_mem: u64 = T::PVFMemory::get().into();
1029 let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
1030
1031 let max_events_size = max_block_weight
1035 .checked_div_per_component(
1036 &(<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::DepositEvent {
1037 num_topic: 0,
1038 len: limits::EVENT_BYTES,
1039 })
1040 .saturating_add(<RuntimeCosts as WeightToken<T>>::weight(
1041 &RuntimeCosts::HostFn,
1042 ))),
1043 )
1044 .unwrap()
1045 .saturating_mul(limits::EVENT_BYTES.into());
1046
1047 assert!(
1048 max_events_size <= storage_size_limit,
1049 "Maximal events size {} exceeds the events limit {}",
1050 max_events_size,
1051 storage_size_limit
1052 );
1053
1054 let max_eth_block_builder_bytes =
1089 block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());
1090
1091 log::debug!(
1092 target: LOG_TARGET,
1093 "Integrity check: max_eth_block_builder_bytes={} KB using max_events_size={} KB",
1094 max_eth_block_builder_bytes / 1024,
1095 max_events_size / 1024,
1096 );
1097
1098 let memory_left = i128::from(max_runtime_mem)
1103 .saturating_div(TOTAL_MEMORY_DEVIDER.into())
1104 .saturating_sub(limits::MEMORY_REQUIRED.into())
1105 .saturating_sub(max_eth_block_builder_bytes.into());
1106
1107 log::debug!(target: LOG_TARGET, "Integrity check: memory_left={} KB", memory_left / 1024);
1108
1109 assert!(
1110 memory_left >= 0,
1111 "Runtime does not have enough memory for current limits. Additional runtime memory required: {} KB",
1112 memory_left.saturating_mul(TOTAL_MEMORY_DEVIDER.into()).abs() / 1024
1113 );
1114
1115 let max_storage_size = max_block_weight
1118 .checked_div_per_component(
1119 &<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::SetStorage {
1120 new_bytes: limits::STORAGE_BYTES,
1121 old_bytes: 0,
1122 kind: StorageAccessKind::Persistent(Warmth::Cold { revertible: true }),
1123 })
1124 .saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
1125 )
1126 .unwrap()
1127 .saturating_add(max_immutable_size.into())
1128 .saturating_add(max_eth_block_builder_bytes.into());
1129
1130 assert!(
1131 max_storage_size <= storage_size_limit,
1132 "Maximal storage size {} exceeds the storage limit {}",
1133 max_storage_size,
1134 storage_size_limit
1135 );
1136 }
1137 }
1138
1139 #[pallet::call]
1140 impl<T: Config> Pallet<T> {
1141 #[allow(unused_variables)]
1154 #[pallet::call_index(0)]
1155 #[pallet::weight(Weight::MAX)]
1156 pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
1157 Err(frame_system::Error::CallFiltered::<T>.into())
1158 }
1159
1160 #[pallet::call_index(1)]
1177 #[pallet::weight(<T as Config>::WeightInfo::call().saturating_add(*weight_limit))]
1178 pub fn call(
1179 origin: OriginFor<T>,
1180 dest: H160,
1181 #[pallet::compact] value: BalanceOf<T>,
1182 weight_limit: Weight,
1183 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1184 data: Vec<u8>,
1185 ) -> DispatchResultWithPostInfo {
1186 Self::ensure_non_contract_if_signed(&origin)?;
1187 let mut output = Self::bare_call(
1188 origin,
1189 dest,
1190 Pallet::<T>::convert_native_to_evm(value),
1191 TransactionLimits::WeightAndDeposit {
1192 weight_limit,
1193 deposit_limit: storage_deposit_limit,
1194 },
1195 data,
1196 &ExecConfig::new_substrate_tx(),
1197 );
1198
1199 if let Ok(return_value) = &output.result &&
1200 return_value.did_revert()
1201 {
1202 output.result = Err(<Error<T>>::ContractReverted.into());
1203 }
1204 dispatch_result(
1205 output.result,
1206 output.weight_consumed,
1207 <T as Config>::WeightInfo::call(),
1208 )
1209 }
1210
1211 #[pallet::call_index(2)]
1217 #[pallet::weight(
1218 <T as Config>::WeightInfo::instantiate(data.len() as u32).saturating_add(*weight_limit)
1219 )]
1220 pub fn instantiate(
1221 origin: OriginFor<T>,
1222 #[pallet::compact] value: BalanceOf<T>,
1223 weight_limit: Weight,
1224 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1225 code_hash: sp_core::H256,
1226 data: Vec<u8>,
1227 salt: Option<[u8; 32]>,
1228 ) -> DispatchResultWithPostInfo {
1229 Self::ensure_non_contract_if_signed(&origin)?;
1230 let data_len = data.len() as u32;
1231 let mut output = Self::bare_instantiate(
1232 origin,
1233 Pallet::<T>::convert_native_to_evm(value),
1234 TransactionLimits::WeightAndDeposit {
1235 weight_limit,
1236 deposit_limit: storage_deposit_limit,
1237 },
1238 Code::Existing(code_hash),
1239 data,
1240 salt,
1241 &ExecConfig::new_substrate_tx(),
1242 );
1243 if let Ok(retval) = &output.result &&
1244 retval.result.did_revert()
1245 {
1246 output.result = Err(<Error<T>>::ContractReverted.into());
1247 }
1248 dispatch_result(
1249 output.result.map(|result| result.result),
1250 output.weight_consumed,
1251 <T as Config>::WeightInfo::instantiate(data_len),
1252 )
1253 }
1254
1255 #[pallet::call_index(3)]
1283 #[pallet::weight(
1284 <T as Config>::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
1285 .saturating_add(*weight_limit)
1286 )]
1287 pub fn instantiate_with_code(
1288 origin: OriginFor<T>,
1289 #[pallet::compact] value: BalanceOf<T>,
1290 weight_limit: Weight,
1291 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1292 code: Vec<u8>,
1293 data: Vec<u8>,
1294 salt: Option<[u8; 32]>,
1295 ) -> DispatchResultWithPostInfo {
1296 Self::ensure_non_contract_if_signed(&origin)?;
1297 let code_len = code.len() as u32;
1298 let data_len = data.len() as u32;
1299 let mut output = Self::bare_instantiate(
1300 origin,
1301 Pallet::<T>::convert_native_to_evm(value),
1302 TransactionLimits::WeightAndDeposit {
1303 weight_limit,
1304 deposit_limit: storage_deposit_limit,
1305 },
1306 Code::Upload(code),
1307 data,
1308 salt,
1309 &ExecConfig::new_substrate_tx(),
1310 );
1311 if let Ok(retval) = &output.result &&
1312 retval.result.did_revert()
1313 {
1314 output.result = Err(<Error<T>>::ContractReverted.into());
1315 }
1316 dispatch_result(
1317 output.result.map(|result| result.result),
1318 output.weight_consumed,
1319 <T as Config>::WeightInfo::instantiate_with_code(code_len, data_len),
1320 )
1321 }
1322
1323 #[pallet::call_index(10)]
1345 #[pallet::weight(
1346 <T as Config>::WeightInfo::eth_instantiate_with_code(code.len() as u32, data.len() as u32, Pallet::<T>::has_dust(*value).into())
1347 .saturating_add(*weight_limit)
1348 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1349 )]
1350 pub fn eth_instantiate_with_code(
1351 origin: OriginFor<T>,
1352 value: U256,
1353 weight_limit: Weight,
1354 eth_gas_limit: U256,
1355 code: Vec<u8>,
1356 data: Vec<u8>,
1357 transaction_encoded: Vec<u8>,
1358 effective_gas_price: U256,
1359 encoded_len: u32,
1360 ) -> DispatchResultWithPostInfo {
1361 let signer = Self::ensure_eth_signed(origin)?;
1362 let origin = OriginFor::<T>::signed(signer.clone());
1363 Self::ensure_non_contract_if_signed(&origin)?;
1364 let mut call = Call::<T>::eth_instantiate_with_code {
1365 value,
1366 weight_limit,
1367 eth_gas_limit,
1368 code: code.clone(),
1369 data: data.clone(),
1370 transaction_encoded: transaction_encoded.clone(),
1371 effective_gas_price,
1372 encoded_len,
1373 }
1374 .into();
1375 let info = T::FeeInfo::dispatch_info(&call);
1376 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1377 drop(call);
1378
1379 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1380 let extra_weight = base_info.total_weight();
1381 let output = Self::bare_instantiate(
1382 origin,
1383 value,
1384 TransactionLimits::EthereumGas {
1385 eth_gas_limit: eth_gas_limit.saturated_into(),
1386 weight_limit,
1387 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1388 authorization_deposit: Default::default(),
1389 },
1390 Code::Upload(code),
1391 data,
1392 None,
1393 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1394 );
1395
1396 block_storage::EthereumCallResult::new::<T>(
1397 signer,
1398 output.map_result(|r| r.result),
1399 base_info.call_weight,
1400 encoded_len,
1401 &info,
1402 effective_gas_price,
1403 )
1404 })
1405 }
1406
1407 #[pallet::call_index(11)]
1425 #[pallet::weight(
1426 T::WeightInfo::eth_call(Pallet::<T>::has_dust(*value).into())
1427 .saturating_add(*weight_limit)
1428 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1429 .saturating_add(evm::eip7702::worst_case_authorization_weight::<T>(authorization_list.len() as u32))
1430 )]
1431 pub fn eth_call(
1432 origin: OriginFor<T>,
1433 dest: H160,
1434 value: U256,
1435 weight_limit: Weight,
1436 eth_gas_limit: U256,
1437 data: Vec<u8>,
1438 transaction_encoded: Vec<u8>,
1439 effective_gas_price: U256,
1440 encoded_len: u32,
1441 authorization_list: Vec<evm::AuthorizationListEntry>,
1442 ) -> DispatchResultWithPostInfo {
1443 let signer = Self::ensure_eth_signed(origin)?;
1444 let origin = OriginFor::<T>::signed(signer.clone());
1445
1446 Self::ensure_non_contract_if_signed(&origin)?;
1447 let mut call = Call::<T>::eth_call {
1448 dest,
1449 value,
1450 weight_limit,
1451 eth_gas_limit,
1452 data: data.clone(),
1453 transaction_encoded: transaction_encoded.clone(),
1454 effective_gas_price,
1455 encoded_len,
1456 authorization_list: authorization_list.clone(),
1457 }
1458 .into();
1459 let info = T::FeeInfo::dispatch_info(&call);
1460 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1461 drop(call);
1462
1463 let exec_config =
1464 ExecConfig::new_eth_tx(effective_gas_price, encoded_len, base_info.total_weight());
1465 let auth_result = evm::eip7702::process_authorizations::<T>(
1466 &authorization_list,
1467 &signer,
1468 &exec_config,
1469 );
1470 let extra_weight = base_info.total_weight().saturating_sub(auth_result.weight_refund);
1471 let base_call_weight = base_info.call_weight.saturating_sub(auth_result.weight_refund);
1472
1473 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1474 let output = Self::bare_call(
1475 origin,
1476 dest,
1477 value,
1478 TransactionLimits::EthereumGas {
1479 eth_gas_limit: eth_gas_limit.saturated_into(),
1480 weight_limit,
1481 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1482 authorization_deposit: auth_result.deposit,
1483 },
1484 data,
1485 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1486 );
1487
1488 block_storage::EthereumCallResult::new::<T>(
1489 signer,
1490 output,
1491 base_call_weight,
1492 encoded_len,
1493 &info,
1494 effective_gas_price,
1495 )
1496 })
1497 }
1498
1499 #[pallet::call_index(12)]
1510 #[pallet::weight(
1511 T::WeightInfo::eth_substrate_call(transaction_encoded.len() as u32)
1512 .saturating_add(call.get_dispatch_info().call_weight)
1513 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1514 )]
1515 pub fn eth_substrate_call(
1516 origin: OriginFor<T>,
1517 call: Box<<T as Config>::RuntimeCall>,
1518 transaction_encoded: Vec<u8>,
1519 ) -> DispatchResultWithPostInfo {
1520 let signer = Self::ensure_eth_signed(origin)?;
1523 Self::ensure_non_contract_if_signed(&OriginFor::<T>::signed(signer.clone()))?;
1524 let tx_len = transaction_encoded.len() as u32;
1525 let weight_overhead = T::WeightInfo::eth_substrate_call(tx_len)
1526 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(tx_len));
1527
1528 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1529 let call_weight = call.get_dispatch_info().call_weight;
1530 let mut call_result = call.dispatch(RawOrigin::Signed(signer).into());
1531
1532 match &mut call_result {
1534 Ok(post_info) | Err(DispatchErrorWithPostInfo { post_info, .. }) => {
1535 post_info.actual_weight = Some(
1536 post_info
1537 .actual_weight
1538 .unwrap_or_else(|| call_weight)
1539 .saturating_add(weight_overhead),
1540 );
1541 },
1542 }
1543
1544 block_storage::EthereumCallResult {
1547 receipt_gas_info: ReceiptGasInfo::default(),
1548 result: call_result,
1549 }
1550 })
1551 }
1552
1553 #[pallet::call_index(4)]
1568 #[pallet::weight(<T as Config>::WeightInfo::upload_code(code.len() as u32))]
1569 pub fn upload_code(
1570 origin: OriginFor<T>,
1571 code: Vec<u8>,
1572 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1573 ) -> DispatchResult {
1574 Self::ensure_non_contract_if_signed(&origin)?;
1575 Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
1576 }
1577
1578 #[pallet::call_index(5)]
1583 #[pallet::weight(<T as Config>::WeightInfo::remove_code())]
1584 pub fn remove_code(
1585 origin: OriginFor<T>,
1586 code_hash: sp_core::H256,
1587 ) -> DispatchResultWithPostInfo {
1588 let origin = ensure_signed(origin)?;
1589 <ContractBlob<T>>::remove(&origin, code_hash)?;
1590 Ok(Pays::No.into())
1592 }
1593
1594 #[pallet::call_index(6)]
1605 #[pallet::weight(<T as Config>::WeightInfo::set_code())]
1606 pub fn set_code(
1607 origin: OriginFor<T>,
1608 dest: H160,
1609 code_hash: sp_core::H256,
1610 ) -> DispatchResult {
1611 ensure_root(origin)?;
1612 <AccountInfoOf<T>>::try_mutate(&dest, |account| {
1613 let Some(account) = account else {
1614 return Err(<Error<T>>::ContractNotFound.into());
1615 };
1616
1617 let AccountType::Contract(ref mut contract) = account.account_type else {
1618 return Err(<Error<T>>::ContractNotFound.into());
1619 };
1620
1621 <CodeInfo<T>>::increment_refcount(code_hash)?;
1622 let _ = <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
1623 contract.code_hash = code_hash;
1624
1625 Ok(())
1626 })
1627 }
1628
1629 #[pallet::call_index(7)]
1637 #[pallet::weight(<T as Config>::WeightInfo::map_account())]
1638 pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
1639 #[cfg(not(feature = "runtime-benchmarks"))]
1640 if T::AutoMap::get() {
1641 return Ok(());
1642 }
1643
1644 Self::ensure_non_contract_if_signed(&origin)?;
1645 let origin = ensure_signed(origin)?;
1646 T::AddressMapper::map(&origin)
1647 }
1648
1649 #[pallet::call_index(13)]
1651 #[pallet::weight(<T as Config>::WeightInfo::batch_map_accounts(accounts.len().saturated_into::<u32>()))]
1652 pub fn batch_map_accounts(
1653 origin: OriginFor<T>,
1654 accounts: Vec<T::AccountId>,
1655 ) -> DispatchResultWithPostInfo {
1656 ensure_signed(origin.clone())?;
1657 Self::ensure_non_contract_if_signed(&origin)?;
1658
1659 let total: u32 = accounts.len().saturated_into();
1660 let mut mapped = 0;
1661
1662 for account_id in accounts
1663 .iter()
1664 .filter(|&a| !T::AddressMapper::is_eth_derived(a))
1666 .filter(|&a| frame_system::Pallet::<T>::account_exists(a))
1669 {
1670 let mut useful = false;
1671
1672 match T::AddressMapper::map_no_deposit_unchecked(account_id) {
1673 Ok(()) => {
1674 useful = true;
1675 },
1676 Err(err) => log::debug!(
1677 target: LOG_TARGET,
1678 "Failed to map account {account_id:?}: {err:?}",
1679 ),
1680 }
1681
1682 match T::Currency::release_all(
1683 &HoldReason::AddressMapping.into(),
1684 account_id,
1685 Precision::BestEffort,
1686 ) {
1687 Ok(released) if !released.is_zero() => {
1690 useful = true;
1691 },
1692 Ok(_) => {},
1693 Err(err) => log::debug!(
1694 target: LOG_TARGET,
1695 "Failed to release mapping deposit for {account_id:?}: {err:?}",
1696 ),
1697 }
1698
1699 if useful {
1700 mapped = mapped.saturating_add(1);
1701 }
1702 }
1703
1704 if total == 0 || mapped == 0 {
1706 return Ok(Pays::Yes.into());
1707 }
1708
1709 let proportion_mapped = Perbill::from_rational(mapped, total);
1710 if proportion_mapped >= Perbill::from_percent(90) {
1711 Ok(Pays::No.into())
1712 } else {
1713 Ok(Pays::Yes.into())
1714 }
1715 }
1716
1717 #[pallet::call_index(8)]
1725 #[pallet::weight(<T as Config>::WeightInfo::unmap_account())]
1726 pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
1727 #[cfg(not(feature = "runtime-benchmarks"))]
1728 ensure!(!T::AutoMap::get(), <Error<T>>::AutoMappingEnabled);
1729 let origin = ensure_signed(origin)?;
1730 T::AddressMapper::unmap(&origin)
1731 }
1732
1733 #[pallet::call_index(9)]
1739 #[pallet::weight({
1740 let dispatch_info = call.get_dispatch_info();
1741 (
1742 <T as Config>::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
1743 dispatch_info.class
1744 )
1745 })]
1746 pub fn dispatch_as_fallback_account(
1747 mut origin: OriginFor<T>,
1748 call: Box<<T as Config>::RuntimeCall>,
1749 ) -> DispatchResultWithPostInfo {
1750 Self::ensure_non_contract_if_signed(&origin)?;
1751 let account_id = origin.as_signer().ok_or(DispatchError::BadOrigin)?;
1752 let unmapped_account = T::AddressMapper::to_fallback_account_id(
1753 &T::AddressMapper::to_address(&account_id),
1754 );
1755 origin.set_caller_from(RawOrigin::Signed(unmapped_account));
1756 call.dispatch(origin)
1757 }
1758 }
1759}
1760
1761fn dispatch_result<R>(
1763 result: Result<R, DispatchError>,
1764 weight_consumed: Weight,
1765 base_weight: Weight,
1766) -> DispatchResultWithPostInfo {
1767 let post_info = PostDispatchInfo {
1768 actual_weight: Some(weight_consumed.saturating_add(base_weight)),
1769 pays_fee: Default::default(),
1770 };
1771
1772 result
1773 .map(|_| post_info)
1774 .map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
1775}
1776
1777impl<T: Config> Pallet<T> {
1778 pub fn bare_call(
1785 origin: OriginFor<T>,
1786 dest: H160,
1787 evm_value: U256,
1788 transaction_limits: TransactionLimits<T>,
1789 data: Vec<u8>,
1790 exec_config: &ExecConfig<T>,
1791 ) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
1792 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1793 Ok(transaction_meter) => transaction_meter,
1794 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1795 };
1796 let mut storage_deposit = Default::default();
1797
1798 let try_call = || {
1799 let origin = ExecOrigin::from_runtime_origin(origin)?;
1800 let result = ExecStack::<T, ContractBlob<T>>::run_call(
1801 origin.clone(),
1802 dest,
1803 &mut transaction_meter,
1804 evm_value,
1805 data,
1806 &exec_config,
1807 )?;
1808
1809 storage_deposit = transaction_meter
1810 .execute_postponed_deposits(&origin, &exec_config)
1811 .inspect_err(|err| {
1812 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1813 })?;
1814
1815 Ok(result)
1816 };
1817 let result = Self::run_guarded(try_call);
1818
1819 log::trace!(target: LOG_TARGET, "Bare call ends: \
1820 result={result:?}, \
1821 weight_consumed={:?}, \
1822 weight_required={:?}, \
1823 storage_deposit={:?}, \
1824 gas_consumed={:?}, \
1825 max_storage_deposit={:?}",
1826 transaction_meter.weight_consumed(),
1827 transaction_meter.weight_required(),
1828 storage_deposit,
1829 transaction_meter.total_consumed_gas(),
1830 transaction_meter.deposit_required()
1831 );
1832
1833 ContractResult {
1834 result: result.map_err(|r| r.error),
1835 weight_consumed: transaction_meter.weight_consumed(),
1836 weight_required: transaction_meter.weight_required(),
1837 storage_deposit,
1838 gas_consumed: transaction_meter.total_consumed_gas(),
1839 max_storage_deposit: transaction_meter.deposit_required(),
1840 }
1841 }
1842
1843 pub fn prepare_dry_run(account: &T::AccountId) {
1849 frame_system::Pallet::<T>::inc_account_nonce(account);
1852
1853 if !T::AddressMapper::is_mapped(account) {
1856 let _ = T::AddressMapper::map_no_deposit_unchecked(account);
1857 }
1858 }
1859
1860 pub fn bare_instantiate(
1866 origin: OriginFor<T>,
1867 evm_value: U256,
1868 transaction_limits: TransactionLimits<T>,
1869 code: Code,
1870 data: Vec<u8>,
1871 salt: Option<[u8; 32]>,
1872 exec_config: &ExecConfig<T>,
1873 ) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1874 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1875 Ok(transaction_meter) => transaction_meter,
1876 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1877 };
1878
1879 let mut storage_deposit = Default::default();
1880
1881 let try_instantiate = || {
1882 let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1883
1884 if_tracing(|t| t.instantiate_code(&code, salt.as_ref()));
1885 let executable = match code {
1886 Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => {
1887 let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1888 let executable = Self::try_upload_code(
1889 upload_account,
1890 code,
1891 BytecodeType::Pvm,
1892 &mut transaction_meter,
1893 &exec_config,
1894 )?;
1895 executable
1896 },
1897 Code::Upload(code) => {
1898 if T::AllowEVMBytecode::get() {
1899 ensure!(data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
1900 let origin = T::UploadOrigin::ensure_origin(origin)?;
1901 let executable = ContractBlob::from_evm_init_code(code, origin)?;
1902 executable
1903 } else {
1904 return Err(<Error<T>>::CodeRejected.into());
1905 }
1906 },
1907 Code::Existing(code_hash) => {
1908 let executable = ContractBlob::from_storage(code_hash, &mut transaction_meter)?;
1909 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
1910 executable
1911 },
1912 };
1913 let instantiate_origin = ExecOrigin::from_account_id(instantiate_account.clone());
1914 let result = ExecStack::<T, ContractBlob<T>>::run_instantiate(
1915 instantiate_account,
1916 executable,
1917 &mut transaction_meter,
1918 evm_value,
1919 data,
1920 salt.as_ref(),
1921 &exec_config,
1922 );
1923
1924 storage_deposit = transaction_meter
1925 .execute_postponed_deposits(&instantiate_origin, &exec_config)
1926 .inspect_err(|err| {
1927 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1928 })?;
1929 result
1930 };
1931 let output = Self::run_guarded(try_instantiate);
1932
1933 log::trace!(target: LOG_TARGET, "Bare instantiate ends: weight_consumed={:?}\
1934 weight_required={:?} \
1935 storage_deposit={:?} \
1936 gas_consumed={:?} \
1937 max_storage_deposit={:?}",
1938 transaction_meter.weight_consumed(),
1939 transaction_meter.weight_required(),
1940 storage_deposit,
1941 transaction_meter.total_consumed_gas(),
1942 transaction_meter.deposit_required()
1943 );
1944
1945 ContractResult {
1946 result: output
1947 .map(|(addr, result)| InstantiateReturnValue { result, addr })
1948 .map_err(|e| e.error),
1949 weight_consumed: transaction_meter.weight_consumed(),
1950 weight_required: transaction_meter.weight_required(),
1951 storage_deposit,
1952 gas_consumed: transaction_meter.total_consumed_gas(),
1953 max_storage_deposit: transaction_meter.deposit_required(),
1954 }
1955 }
1956
1957 pub fn eth_estimate_gas(
1969 tx: GenericTransaction,
1970 timestamp_override: Option<MomentOf<T>>,
1971 state_overrides: Option<StateOverrideSet>,
1972 ) -> Result<U256, EthTransactError>
1973 where
1974 T::Nonce: Into<U256> + TryFrom<U256>,
1975 CallOf<T>: SetWeightLimit,
1976 {
1977 log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}");
1978
1979 let mut low = U256::zero();
1980 let mut high = Self::evm_block_gas_limit();
1981
1982 log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}");
1983
1984 let perform_balance_checks = if let Some(gas_limit) = tx.gas {
1988 high = gas_limit;
1989 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}");
1990 true
1991 } else {
1992 false
1993 };
1994
1995 let fee_cap = tx.max_fee_per_gas.or(tx.gas_price);
1997 if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) {
1998 let mut available_balance = Self::evm_balance(&from);
1999 if let Some(value) = tx.value {
2000 available_balance = available_balance.checked_sub(value).ok_or_else(|| {
2001 EthTransactError::Message("insufficient funds for value transfer".into())
2002 })?;
2003 }
2004 if let Some(allowance) = available_balance.checked_div(fee_cap) {
2005 if high > allowance && allowance != U256::zero() {
2006 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}");
2007 high = allowance
2008 }
2009 }
2010 }
2011
2012 let dry_run_at = |gas: U256| {
2016 let mut transaction = tx.clone();
2017 transaction.gas = Some(gas);
2018 with_transaction(|| {
2019 TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
2020 transaction,
2021 timestamp_override,
2022 perform_balance_checks,
2023 state_overrides.clone(),
2024 )))
2025 })
2026 .expect("Rollback shouldn't error out")
2027 };
2028
2029 let is_simple_transfer = with_transaction(|| {
2032 let probe = state_overrides
2033 .clone()
2034 .map_or(Ok(()), state_overrides::apply_state_overrides::<T>)
2035 .map(|()| Self::is_simple_transfer(&tx));
2036 TransactionOutcome::Rollback(Ok::<_, DispatchError>(probe))
2037 })
2038 .expect("Rollback shouldn't error out")?;
2039
2040 if is_simple_transfer {
2041 let dry_run_result = dry_run_at(high)?;
2042 log::trace!(
2043 target: LOG_TARGET,
2044 "eth_estimate_gas short-circuited simple transfer to {:?} with eth_gas={}",
2045 tx.to,
2046 dry_run_result.eth_gas,
2047 );
2048 return Ok(dry_run_result.eth_gas);
2049 }
2050
2051 let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()]
2056 .map(|gas_limit| (gas_limit, dry_run_at(gas_limit)));
2057 let (gas_limit, first_dry_run_result) = match dry_run_results {
2058 [(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => {
2059 if dry_run_result2.eth_gas >= gas_limit2 {
2060 (gas_limit1, dry_run_result1)
2061 } else {
2062 (gas_limit2, dry_run_result2)
2063 }
2064 },
2065 [(gas_limit, Ok(dry_run_result)), (_, Err(_))] |
2066 [(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result),
2067 [(_, Err(err)), (_, Err(..))] => return Err(err),
2068 };
2069 log::trace!(
2070 target: LOG_TARGET,
2071 "eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}",
2072 gas_limit,
2073 first_dry_run_result.eth_gas
2074 );
2075 low = first_dry_run_result.eth_gas;
2076 high = gas_limit;
2077
2078 while low + U256::one() < high {
2083 log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}");
2084 let error_ratio = high
2085 .checked_sub(low)
2086 .and_then(|value| value.checked_mul(U256::from(1000)))
2087 .and_then(|value| value.checked_div(high))
2088 .ok_or_else(|| {
2089 EthTransactError::Message(
2090 "failed to calculate error ratio in gas estimation".into(),
2091 )
2092 })?;
2093 if error_ratio <= U256::from(15) {
2094 log::trace!(
2095 target: LOG_TARGET,
2096 "eth_estimate_gas finished due to error ratio being less than 1.5% high={}",
2097 high
2098 );
2099 break;
2100 }
2101
2102 let mut midpoint = high
2103 .checked_sub(low)
2104 .and_then(|value| value.checked_div(U256::from(2)))
2105 .and_then(|value| value.checked_add(low))
2106 .ok_or_else(|| {
2107 EthTransactError::Message(
2108 "failed to calculate midpoint in gas estimation".into(),
2109 )
2110 })?;
2111
2112 if let Some(other_midpoint) = low.checked_mul(U256::from(2)) {
2113 if other_midpoint != U256::zero() {
2114 midpoint = midpoint.min(other_midpoint)
2115 }
2116 };
2117
2118 let dry_run_result = dry_run_at(midpoint);
2119 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}");
2120 match dry_run_result {
2121 Ok(..) => {
2122 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}");
2123 high = midpoint
2124 },
2125 Err(..) => {
2126 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}");
2127 low = midpoint
2128 },
2129 }
2130 }
2131
2132 log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}");
2133 Ok(high)
2134 }
2135
2136 pub(crate) fn is_simple_transfer(tx: &GenericTransaction) -> bool {
2138 tx.to
2139 .map(|to| tx.has_simple_transfer_fields() && Self::address_runs_no_code(&to))
2140 .unwrap_or(false)
2141 }
2142
2143 fn address_runs_no_code(address: &H160) -> bool {
2147 *address != RUNTIME_PALLETS_ADDR &&
2148 !exec::is_precompile::<T, ContractBlob<T>>(address) &&
2149 !<AccountInfo<T>>::is_contract(address) &&
2150 !<AccountInfo<T>>::is_delegated(address)
2151 }
2152
2153 pub fn eth_pre_dispatch_weight(transaction_encoded: Vec<u8>) -> Result<Weight, EthTransactError>
2161 where
2162 CallOf<T>: SetWeightLimit,
2163 {
2164 let signed_tx =
2165 crate::evm::TransactionSigned::decode(&transaction_encoded).map_err(|err| {
2166 EthTransactError::Message(format!("Failed to decode transaction: {err:?}"))
2167 })?;
2168 let signer_addr = signed_tx.recover_eth_address().map_err(|err| {
2169 EthTransactError::Message(format!("Failed to recover signer: {err:?}"))
2170 })?;
2171 let tx =
2172 GenericTransaction::from_signed(signed_tx, Self::evm_base_fee(), Some(signer_addr));
2173 let encoded_len = T::FeeInfo::encoded_len(
2174 crate::Call::<T>::eth_transact { payload: transaction_encoded.clone() }.into(),
2175 );
2176 let call_info = tx
2177 .into_call::<T>(CreateCallMode::ExtrinsicExecution(encoded_len, transaction_encoded))
2178 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2179 let info = T::FeeInfo::dispatch_info(&call_info.call);
2180
2181 Ok(frame_system::calculate_consumed_extrinsic_weight::<CallOf<T>>(
2182 &T::BlockWeights::get(),
2183 &info,
2184 call_info.encoded_len as usize,
2185 ))
2186 }
2187
2188 pub fn dry_run_eth_transact(
2200 mut tx: GenericTransaction,
2201 timestamp_override: Option<MomentOf<T>>,
2202 perform_balance_checks: bool,
2203 state_overrides: Option<StateOverrideSet>,
2204 ) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
2205 where
2206 T::Nonce: Into<U256> + TryFrom<U256>,
2207 CallOf<T>: SetWeightLimit,
2208 {
2209 log::debug!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?}");
2210
2211 if !tx.authorization_list.is_empty() && tx.from.is_none() {
2215 return Err(EthTransactError::Message(
2216 "a transaction with an authorization list requires a `from` address: \
2217 the authorization deposits are charged to it"
2218 .into(),
2219 ));
2220 }
2221
2222 let origin = T::AddressMapper::to_account_id(&tx.from.unwrap_or_default());
2223 Self::prepare_dry_run(&origin);
2224
2225 if let Some(overrides) = state_overrides {
2226 state_overrides::apply_state_overrides::<T>(overrides)?;
2227 }
2228
2229 let base_fee = Self::evm_base_fee();
2230 let effective_gas_price = tx.effective_gas_price(base_fee).unwrap_or(base_fee);
2231
2232 if effective_gas_price < base_fee {
2233 Err(EthTransactError::Message(format!(
2234 "Effective gas price {effective_gas_price:?} lower than base fee {base_fee:?}"
2235 )))?;
2236 }
2237
2238 if tx.nonce.is_none() {
2239 tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
2240 }
2241 if tx.chain_id.is_none() {
2242 tx.chain_id = Some(T::ChainId::get().into());
2243 }
2244
2245 tx.gas_price = Some(effective_gas_price);
2247 tx.max_priority_fee_per_gas = Some(0.into());
2250 if tx.max_fee_per_gas.is_none() {
2251 tx.max_fee_per_gas = Some(effective_gas_price);
2252 }
2253
2254 let gas = tx.gas;
2255 if tx.gas.is_none() {
2256 tx.gas = Some(Self::evm_block_gas_limit());
2257 }
2258 if tx.r#type.is_none() {
2259 tx.r#type = Some(
2260 if tx.authorization_list.is_empty() { TYPE_EIP1559 } else { TYPE_EIP7702 }.into(),
2261 );
2262 }
2263
2264 let authorization_list = tx.authorization_list.clone();
2266 let value = tx.value.unwrap_or_default();
2267 let input = tx.input.clone().to_vec();
2268 let from = tx.from;
2269 let to = tx.to;
2270
2271 let mut call_info = tx
2274 .into_call::<T>(CreateCallMode::DryRun)
2275 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2276
2277 let base_info = T::FeeInfo::base_dispatch_info(&mut call_info.call);
2281 let mut base_weight = base_info.total_weight();
2282
2283 let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
2285 if let Some(from) = &from {
2286 let fees = if gas.is_some() && perform_balance_checks { fees } else { Zero::zero() };
2287 let balance = Self::evm_balance(from);
2288 if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
2289 return Err(EthTransactError::Message(format!(
2290 "insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
2291 )));
2292 }
2293 }
2294
2295 T::FeeInfo::deposit_txfee(T::Currency::issue(fees));
2298
2299 let extract_error = |err| {
2300 if err == Error::<T>::StorageDepositNotEnoughFunds.into() {
2301 Err(EthTransactError::Message(format!("Not enough gas supplied: {err:?}")))
2302 } else {
2303 Err(EthTransactError::Message(format!("failed to run contract: {err:?}")))
2304 }
2305 };
2306
2307 let exec_config =
2308 ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight);
2309 let auth_result =
2310 evm::eip7702::process_authorizations::<T>(&authorization_list, &origin, &exec_config);
2311 base_weight = base_weight.saturating_sub(auth_result.weight_refund);
2312 let actual_auth_deposit = auth_result.deposit;
2313 let worst_case_auth_deposit = Self::worst_case_delegation_deposit()
2314 .saturating_mul(authorization_list.len().saturated_into());
2315
2316 let exec_config =
2317 ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight)
2318 .with_dry_run(timestamp_override);
2319
2320 let transaction_limits = TransactionLimits::EthereumGas {
2321 eth_gas_limit: call_info.eth_gas_limit.saturated_into(),
2322 weight_limit: Self::evm_max_extrinsic_weight(),
2323 eth_tx_info: EthTxInfo::new(call_info.encoded_len, base_weight),
2324 authorization_deposit: actual_auth_deposit,
2325 };
2326
2327 let mut dry_run = match to {
2329 Some(dest) => {
2331 if dest == RUNTIME_PALLETS_ADDR {
2332 let Ok(dispatch_call) = <CallOf<T>>::decode(&mut &input[..]) else {
2333 return Err(EthTransactError::Message(format!(
2334 "Failed to decode pallet-call {input:?}"
2335 )));
2336 };
2337
2338 if let Err(result) =
2339 dispatch_call.clone().dispatch(RawOrigin::Signed(origin).into())
2340 {
2341 return Err(EthTransactError::Message(format!(
2342 "Failed to dispatch call: {:?}",
2343 result.error,
2344 )));
2345 };
2346
2347 Default::default()
2348 } else {
2349 let result = crate::Pallet::<T>::bare_call(
2351 OriginFor::<T>::signed(origin),
2352 dest,
2353 value,
2354 transaction_limits,
2355 input.clone(),
2356 &exec_config,
2357 );
2358
2359 let data = match result.result {
2360 Ok(return_value) => {
2361 if return_value.did_revert() {
2362 return Err(EthTransactError::Data(return_value.data));
2363 }
2364 return_value.data
2365 },
2366 Err(err) => {
2367 log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
2368 return extract_error(err);
2369 },
2370 };
2371
2372 EthTransactInfo {
2373 weight_required: result.weight_required,
2374 storage_deposit: result.storage_deposit.charge_or_zero(),
2375 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2376 data,
2377 eth_gas: Default::default(),
2378 }
2379 }
2380 },
2381 None => {
2383 let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2385 extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default()))
2386 } else {
2387 (input, vec![])
2388 };
2389
2390 let result = crate::Pallet::<T>::bare_instantiate(
2392 OriginFor::<T>::signed(origin),
2393 value,
2394 transaction_limits,
2395 Code::Upload(code.clone()),
2396 data.clone(),
2397 None,
2398 &exec_config,
2399 );
2400
2401 let returned_data = match result.result {
2402 Ok(return_value) => {
2403 if return_value.result.did_revert() {
2404 return Err(EthTransactError::Data(return_value.result.data));
2405 }
2406 return_value.result.data
2407 },
2408 Err(err) => {
2409 log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
2410 return extract_error(err);
2411 },
2412 };
2413
2414 EthTransactInfo {
2415 weight_required: result.weight_required,
2416 storage_deposit: result.storage_deposit.charge_or_zero(),
2417 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2418 data: returned_data,
2419 eth_gas: Default::default(),
2420 }
2421 },
2422 };
2423
2424 dry_run.max_storage_deposit = dry_run.max_storage_deposit.max(worst_case_auth_deposit);
2428
2429 call_info.call.set_weight_limit(dry_run.weight_required);
2431
2432 let total_weight = T::FeeInfo::dispatch_info(&call_info.call).total_weight();
2434 let max_weight = Self::evm_max_extrinsic_weight();
2435 if total_weight.any_gt(max_weight) {
2436 log::debug!(target: LOG_TARGET, "Transaction weight estimate exceeds extrinsic maximum: \
2437 total_weight={total_weight:?} \
2438 max_weight={max_weight:?}",
2439 );
2440
2441 Err(EthTransactError::Message(format!(
2442 "\
2443 The transaction consumes more than the allowed weight. \
2444 needed={total_weight} \
2445 allowed={max_weight} \
2446 overweight_by={}\
2447 ",
2448 total_weight.saturating_sub(max_weight),
2449 )))?;
2450 }
2451
2452 let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
2454 let available_fee = T::FeeInfo::remaining_txfee();
2455 if transaction_fee > available_fee {
2456 Err(EthTransactError::Message(format!(
2457 "Not enough gas supplied: Off by: {:?}",
2458 transaction_fee.saturating_sub(available_fee),
2459 )))?;
2460 }
2461
2462 let total_cost = transaction_fee.saturating_add(dry_run.max_storage_deposit);
2463 let total_cost_wei = Pallet::<T>::convert_native_to_evm(total_cost);
2464 let (mut eth_gas, rest) = total_cost_wei.div_mod(base_fee);
2465 if !rest.is_zero() {
2466 eth_gas = eth_gas.saturating_add(1_u32.into());
2467 }
2468
2469 log::debug!(target: LOG_TARGET, "\
2470 dry_run_eth_transact finished: \
2471 weight_limit={}, \
2472 total_weight={total_weight}, \
2473 max_weight={max_weight}, \
2474 weight_left={}, \
2475 eth_gas={eth_gas}, \
2476 encoded_len={}, \
2477 tx_fee={transaction_fee:?}, \
2478 storage_deposit={:?}, \
2479 max_storage_deposit={:?}\
2480 ",
2481 dry_run.weight_required,
2482 max_weight.saturating_sub(total_weight),
2483 call_info.encoded_len,
2484 dry_run.storage_deposit,
2485 dry_run.max_storage_deposit,
2486
2487 );
2488 dry_run.eth_gas = eth_gas;
2489 Ok(dry_run)
2490 }
2491
2492 pub fn evm_balance(address: &H160) -> U256 {
2496 let balance = AccountInfo::<T>::balance_of((*address).into());
2497 Self::convert_native_to_evm(balance)
2498 }
2499
2500 pub fn eth_block() -> EthBlock {
2502 EthereumBlock::<T>::get()
2503 }
2504
2505 pub fn eth_block_hash_from_number(number: U256) -> Option<H256> {
2512 let number = BlockNumberFor::<T>::try_from(number).ok()?;
2513 let hash = <BlockHash<T>>::get(number);
2514 if hash == H256::zero() { None } else { Some(hash) }
2515 }
2516
2517 pub fn eth_receipt_data() -> Vec<ReceiptGasInfo> {
2519 ReceiptInfoData::<T>::get()
2520 }
2521
2522 pub fn set_evm_balance(address: &H160, evm_value: U256) -> Result<(), Error<T>> {
2528 let (balance, dust) = Self::new_balance_with_dust(evm_value)
2529 .map_err(|_| <Error<T>>::BalanceConversionFailed)?;
2530 let account_id = T::AddressMapper::to_account_id(&address);
2531 T::Currency::set_balance(&account_id, balance);
2532 AccountInfoOf::<T>::mutate(&address, |account| {
2533 if let Some(account) = account {
2534 account.dust = dust;
2535 } else {
2536 *account = Some(AccountInfo { dust, ..Default::default() });
2537 }
2538 });
2539
2540 Ok(())
2541 }
2542
2543 pub fn new_balance_with_dust(
2547 evm_value: U256,
2548 ) -> Result<(BalanceOf<T>, u32), BalanceConversionError> {
2549 let ed = T::Currency::minimum_balance();
2550 let balance_with_dust = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(evm_value)?;
2551 let (value, dust) = balance_with_dust.deconstruct();
2552
2553 Ok((ed.saturating_add(value), dust))
2554 }
2555
2556 pub fn evm_nonce(address: &H160) -> u32
2558 where
2559 T::Nonce: Into<u32>,
2560 {
2561 let account = T::AddressMapper::to_account_id(&address);
2562 System::<T>::account_nonce(account).into()
2563 }
2564
2565 pub fn evm_block_gas_limit() -> U256 {
2567 u64::MAX.into()
2574 }
2575
2576 pub fn evm_max_extrinsic_weight_in_gas() -> U256 {
2578 let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight());
2579 let gas_scale: BalanceOf<T> = T::GasScale::get().into();
2580 (max_extrinsic_fee / gas_scale).into()
2581 }
2582
2583 pub fn evm_max_extrinsic_weight() -> Weight {
2585 let factor = <T as Config>::MaxEthExtrinsicWeight::get();
2586 let max_weight = <T as frame_system::Config>::BlockWeights::get()
2587 .get(DispatchClass::Normal)
2588 .max_extrinsic
2589 .unwrap_or_else(|| <T as frame_system::Config>::BlockWeights::get().max_block);
2590 Weight::from_parts(
2591 factor.saturating_mul_int(max_weight.ref_time()),
2592 factor.saturating_mul_int(max_weight.proof_size()),
2593 )
2594 }
2595
2596 pub fn evm_base_fee() -> U256 {
2598 let gas_scale = <T as Config>::GasScale::get();
2599 let multiplier = T::FeeInfo::next_fee_multiplier();
2600 multiplier
2601 .saturating_mul_int::<u128>(T::NativeToEthRatio::get().into())
2602 .saturating_mul(gas_scale.saturated_into())
2603 .into()
2604 }
2605
2606 pub fn evm_tracer(tracer_type: TracerType) -> Tracer<T>
2608 where
2609 T::Nonce: Into<u32>,
2610 {
2611 match tracer_type {
2612 TracerType::CallTracer(config) => CallTracer::new(config.unwrap_or_default()).into(),
2613 TracerType::PrestateTracer(config) => {
2614 PrestateTracer::new(config.unwrap_or_default()).into()
2615 },
2616 TracerType::ExecutionTracer(config) => {
2617 ExecutionTracer::new(config.unwrap_or_default()).into()
2618 },
2619 }
2620 }
2621
2622 pub fn bare_upload_code(
2626 origin: OriginFor<T>,
2627 code: Vec<u8>,
2628 storage_deposit_limit: BalanceOf<T>,
2629 ) -> CodeUploadResult<BalanceOf<T>> {
2630 let origin = T::UploadOrigin::ensure_origin(origin)?;
2631
2632 let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2633 BytecodeType::Pvm
2634 } else {
2635 if !T::AllowEVMBytecode::get() {
2636 return Err(<Error<T>>::CodeRejected.into());
2637 }
2638 BytecodeType::Evm
2639 };
2640
2641 let mut meter = TransactionMeter::new(TransactionLimits::WeightAndDeposit {
2642 weight_limit: Default::default(),
2643 deposit_limit: storage_deposit_limit,
2644 })?;
2645
2646 let module = Self::try_upload_code(
2647 origin,
2648 code,
2649 bytecode_type,
2650 &mut meter,
2651 &ExecConfig::new_substrate_tx(),
2652 )?;
2653 Ok(CodeUploadReturnValue {
2654 code_hash: *module.code_hash(),
2655 deposit: meter.deposit_consumed().charge_or_zero(),
2656 })
2657 }
2658
2659 pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
2661 let contract_info =
2662 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2663
2664 let maybe_value = contract_info.read(&Key::from_fixed(key));
2665 Ok(maybe_value)
2666 }
2667
2668 pub fn get_immutables(address: H160) -> Option<ImmutableData> {
2672 let immutable_data = <ImmutableDataOf<T>>::get(address);
2673 immutable_data
2674 }
2675
2676 pub fn set_immutables(address: H160, data: ImmutableData) -> Result<(), ContractAccessError> {
2685 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2686 <ImmutableDataOf<T>>::insert(address, data);
2687 Ok(())
2688 }
2689
2690 pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
2692 let contract_info =
2693 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2694
2695 let maybe_value = contract_info.read(
2696 &Key::try_from_var(key)
2697 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2698 .into(),
2699 );
2700 Ok(maybe_value)
2701 }
2702
2703 pub fn convert_native_to_evm(value: impl Into<BalanceWithDust<BalanceOf<T>>>) -> U256 {
2705 let (value, dust) = value.into().deconstruct();
2706 value
2707 .into()
2708 .saturating_mul(T::NativeToEthRatio::get().into())
2709 .saturating_add(dust.into())
2710 }
2711
2712 pub fn set_storage(address: H160, key: [u8; 32], value: Option<Vec<u8>>) -> SetStorageResult {
2722 let contract_info =
2723 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2724
2725 contract_info
2726 .write(&Key::from_fixed(key), value, None, false)
2727 .map_err(ContractAccessError::StorageWriteFailed)
2728 }
2729
2730 pub fn set_storage_var_key(
2741 address: H160,
2742 key: Vec<u8>,
2743 value: Option<Vec<u8>>,
2744 ) -> SetStorageResult {
2745 let contract_info =
2746 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2747
2748 contract_info
2749 .write(
2750 &Key::try_from_var(key)
2751 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2752 .into(),
2753 value,
2754 None,
2755 false,
2756 )
2757 .map_err(ContractAccessError::StorageWriteFailed)
2758 }
2759
2760 pub fn account_id() -> T::AccountId {
2762 use frame_support::PalletId;
2763 use sp_runtime::traits::AccountIdConversion;
2764 PalletId(*b"py/reviv").into_account_truncating()
2765 }
2766
2767 pub fn block_author() -> H160 {
2769 use frame_support::traits::FindAuthor;
2770
2771 let digest = <frame_system::Pallet<T>>::digest();
2772 let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
2773
2774 T::FindAuthor::find_author(pre_runtime_digests)
2775 .map(|account_id| T::AddressMapper::to_address(&account_id))
2776 .unwrap_or_default()
2777 }
2778
2779 pub fn code(address: &H160) -> Vec<u8> {
2784 use precompiles::{All, Precompiles};
2785 if let Some(code) = <All<T>>::code(address.as_fixed_bytes()) {
2786 return code.into();
2787 }
2788
2789 let Some(info) = <AccountInfoOf<T>>::get(address) else { return Vec::new() };
2790
2791 match info.account_type {
2792 AccountType::Contract(contract) => <PristineCode<T>>::get(contract.code_hash)
2793 .map(|code| code.into())
2794 .unwrap_or_default(),
2795 AccountType::DelegatedEOA { delegate_target: Some(target), .. } => {
2796 AccountInfo::<T>::delegation_indicator(&target).to_vec()
2797 },
2798 AccountType::EOA | AccountType::DelegatedEOA { .. } => Vec::new(),
2799 }
2800 }
2801
2802 pub fn try_upload_code(
2804 origin: T::AccountId,
2805 code: Vec<u8>,
2806 code_type: BytecodeType,
2807 meter: &mut TransactionMeter<T>,
2808 exec_config: &ExecConfig<T>,
2809 ) -> Result<ContractBlob<T>, DispatchError> {
2810 let mut module = match code_type {
2811 BytecodeType::Pvm => ContractBlob::from_pvm_code(code, origin)?,
2812 BytecodeType::Evm => ContractBlob::from_evm_runtime_code(code, origin)?,
2813 };
2814 module.store_code(exec_config, meter)?;
2815 Ok(module)
2816 }
2817
2818 fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
2820 executing_contract::using_once(&mut false, || {
2821 executing_contract::with(|f| {
2822 if *f {
2824 return Err(())
2825 }
2826 *f = true;
2828 Ok(())
2829 })
2830 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
2831 .map_err(|_| <Error<T>>::ReenteredPallet.into())
2832 .map(|_| f())
2833 .and_then(|r| r)
2834 })
2835 }
2836
2837 fn charge_deposit(
2842 hold_reason: HoldReason,
2843 from: &T::AccountId,
2844 to: &T::AccountId,
2845 amount: BalanceOf<T>,
2846 exec_config: &ExecConfig<T>,
2847 ) -> DispatchResult {
2848 if amount.is_zero() {
2849 return Ok(());
2850 }
2851
2852 T::Deposit::charge_and_hold(hold_reason, exec_config.funds(from), to, amount)
2853 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
2854 Ok(())
2855 }
2856
2857 pub(crate) fn refund_deposit(
2862 hold_reason: HoldReason,
2863 from: &T::AccountId,
2864 dst: deposit_payment::Funds<T::AccountId>,
2865 amount: BalanceOf<T>,
2866 ) -> Result<(), DispatchError> {
2867 if amount.is_zero() {
2868 return Ok(());
2869 }
2870
2871 let to = match &dst {
2872 deposit_payment::Funds::Balance(to) | deposit_payment::Funds::TxFee(to) => *to,
2873 };
2874 let result = T::Deposit::refund_on_hold(hold_reason, from, dst, amount);
2875
2876 result.defensive_map_err(|err| {
2877 let available = T::Deposit::total_on_hold(hold_reason, from);
2878 if available < amount {
2879 log::error!(
2882 target: LOG_TARGET,
2883 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}. Not enough deposit: {available:?}. This is a bug.",
2884 );
2885 Error::<T>::StorageRefundNotEnoughFunds.into()
2886 } else {
2887 log::warn!(
2892 target: LOG_TARGET,
2893 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}: {err:?}. First remove locks (staking, governance) from the contracts account.",
2894 );
2895 Error::<T>::StorageRefundLocked.into()
2896 }
2897 })
2898 }
2899
2900 fn has_dust(value: U256) -> bool {
2902 value % U256::from(<T>::NativeToEthRatio::get()) != U256::zero()
2903 }
2904
2905 fn has_balance(value: U256) -> bool {
2907 value >= U256::from(<T>::NativeToEthRatio::get())
2908 }
2909
2910 #[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))]
2912 fn min_balance() -> BalanceOf<T> {
2913 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
2914 }
2915
2916 pub(crate) fn worst_case_delegation_deposit() -> BalanceOf<T> {
2920 let ed = <T as Config>::Currency::minimum_balance();
2921 let contract_deposit = T::DepositPerByte::get()
2922 .saturating_mul((<ContractInfo<T>>::max_encoded_len() as u32).into())
2923 .saturating_add(T::DepositPerItem::get());
2924 let max_code_deposit = vm::calculate_code_deposit::<T>(limits::code::BLOB_BYTES);
2925 let code_lockup = T::CodeHashLockupDepositPercent::get().mul_ceil(max_code_deposit);
2926 ed.saturating_add(contract_deposit).saturating_add(code_lockup)
2927 }
2928
2929 fn deposit_event(event: Event<T>) {
2934 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
2935 }
2936
2937 fn ensure_eth_signed(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
2939 match <T as Config>::RuntimeOrigin::from(origin).into() {
2940 Ok(Origin::EthTransaction(signer)) => Ok(signer),
2941 _ => Err(BadOrigin.into()),
2942 }
2943 }
2944
2945 fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
2949 if DebugSettings::bypass_eip_3607::<T>() {
2950 return Ok(());
2951 }
2952 let Some(address) = origin
2953 .as_system_ref()
2954 .and_then(|o| o.as_signed())
2955 .map(<T::AddressMapper as AddressMapper<T>>::to_address)
2956 else {
2957 return Ok(());
2958 };
2959 if exec::is_precompile::<T, ContractBlob<T>>(&address) ||
2960 <AccountInfo<T>>::is_contract(&address)
2961 {
2962 log::debug!(
2963 target: crate::LOG_TARGET,
2964 "EIP-3607: reject tx as pre-compile or account exist at {address:?}",
2965 );
2966 Err(DispatchError::BadOrigin)
2967 } else {
2968 Ok(())
2969 }
2970 }
2971}
2972
2973pub const RUNTIME_PALLETS_ADDR: H160 =
2978 H160(hex_literal::hex!("6d6f646c70792f70616464720000000000000000"));
2979
2980environmental!(executing_contract: bool);
2982
2983sp_api::decl_runtime_apis! {
2984 #[api_version(2)]
2986 pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber, Moment> where
2987 AccountId: Codec,
2988 Balance: Codec,
2989 Nonce: Codec,
2990 BlockNumber: Codec,
2991 Moment: Codec,
2992 {
2993 #[deprecated(note = "Use the versioned equivalent `eth_block_versioned` if available on your runtime")]
2997 fn eth_block() -> BlockV1;
2998
2999 #[deprecated(note = "Use the versioned equivalent `eth_block_hash_versioned` if available on your runtime")]
3001 fn eth_block_hash(number: U256) -> Option<H256>;
3002
3003 #[deprecated(note = "Use the versioned equivalent `eth_receipt_data_versioned` if available on your runtime")]
3009 fn eth_receipt_data() -> Vec<ReceiptGasInfoV1>;
3010
3011 #[deprecated(note = "Use the versioned equivalent `block_gas_limit_versioned` if available on your runtime")]
3013 fn block_gas_limit() -> U256;
3014
3015 #[deprecated(note = "Use the versioned equivalent `max_extrinsic_weight_in_gas_versioned` if available on your runtime")]
3017 fn max_extrinsic_weight_in_gas() -> U256;
3018
3019 #[deprecated(note = "Use the versioned equivalent `balance_versioned` if available on your runtime")]
3021 fn balance(address: H160) -> U256;
3022
3023 #[deprecated(note = "Use the versioned equivalent `gas_price_versioned` if available on your runtime")]
3025 fn gas_price() -> U256;
3026
3027 #[deprecated(note = "Use the versioned equivalent `nonce_versioned` if available on your runtime")]
3029 fn nonce(address: H160) -> Nonce;
3030
3031 #[deprecated(note = "Use the versioned equivalent `call_versioned` if available on your runtime")]
3035 fn call(
3036 origin: AccountId,
3037 dest: H160,
3038 value: Balance,
3039 gas_limit: Option<Weight>,
3040 storage_deposit_limit: Option<Balance>,
3041 input_data: Vec<u8>,
3042 ) -> ContractResultV1<ExecReturnValueV1, Balance>;
3043
3044 #[deprecated(note = "Use the versioned equivalent `instantiate_versioned` if available on your runtime")]
3048 fn instantiate(
3049 origin: AccountId,
3050 value: Balance,
3051 gas_limit: Option<Weight>,
3052 storage_deposit_limit: Option<Balance>,
3053 code: CodeV1,
3054 data: Vec<u8>,
3055 salt: Option<[u8; 32]>,
3056 ) -> ContractResultV1<InstantiateReturnValueV1, Balance>;
3057
3058
3059 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3063 fn eth_transact(tx: GenericTransactionV1) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3064
3065 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3069 fn eth_transact_with_config(
3070 tx: GenericTransactionV1,
3071 config: DryRunConfigV1<Moment>,
3072 ) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3073
3074 #[deprecated(note = "Use the versioned equivalent `eth_estimate_gas_versioned` if available on your runtime")]
3080 fn eth_estimate_gas(
3081 tx: GenericTransactionV1,
3082 config: DryRunConfigV1<Moment>
3083 ) -> Result<U256, EthTransactError>;
3084
3085 #[deprecated(note = "Use the versioned equivalent `eth_pre_dispatch_weight_versioned` if available on your runtime")]
3087 fn eth_pre_dispatch_weight(tx: Vec<u8>) -> Result<Weight, EthTransactError>;
3088
3089 #[deprecated(note = "Use the versioned equivalent `upload_code_versioned` if available on your runtime")]
3093 fn upload_code(
3094 origin: AccountId,
3095 code: Vec<u8>,
3096 storage_deposit_limit: Option<Balance>,
3097 ) -> Result<CodeUploadReturnValueV1<Balance>, DispatchError>;
3098
3099 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3105 fn get_storage(
3106 address: H160,
3107 key: [u8; 32],
3108 ) -> GetStorageResult;
3109
3110 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3116 fn get_storage_var_key(
3117 address: H160,
3118 key: Vec<u8>,
3119 ) -> GetStorageResult;
3120
3121 #[deprecated(note = "Use the versioned equivalent `trace_block_versioned` if available on your runtime")]
3128 fn trace_block(
3129 block: Block,
3130 config: TracerTypeV1
3131 ) -> Vec<(u32, TraceV1)>;
3132
3133 #[deprecated(note = "Use the versioned equivalent `trace_tx_versioned` if available on your runtime")]
3140 fn trace_tx(
3141 block: Block,
3142 tx_index: u32,
3143 config: TracerTypeV1
3144 ) -> Option<TraceV1>;
3145
3146 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3150 fn trace_call(tx: GenericTransactionV1, config: TracerTypeV1) -> Result<TraceV1, EthTransactError>;
3151
3152 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3157 fn trace_call_with_config(
3158 tx: GenericTransactionV1,
3159 tracer_type: TracerTypeV1,
3160 config: TracingConfigV1,
3161 ) -> Result<TraceV1, EthTransactError>;
3162
3163 #[deprecated(note = "Use the versioned equivalent `block_author_versioned` if available on your runtime")]
3165 fn block_author() -> H160;
3166
3167 #[deprecated(note = "Use the versioned equivalent `address_versioned` if available on your runtime")]
3169 fn address(account_id: AccountId) -> H160;
3170
3171 #[deprecated(note = "Use the versioned equivalent `account_id_versioned` if available on your runtime")]
3173 fn account_id(address: H160) -> AccountId;
3174
3175 #[deprecated(note = "Use the versioned equivalent `runtime_pallets_address_versioned` if available on your runtime")]
3177 fn runtime_pallets_address() -> H160;
3178
3179 #[deprecated(note = "Use the versioned equivalent `code_versioned` if available on your runtime")]
3181 fn code(address: H160) -> Vec<u8>;
3182
3183 #[deprecated(note = "Use the versioned equivalent `new_balance_with_dust_versioned` if available on your runtime")]
3185 fn new_balance_with_dust(balance: U256) -> Result<(Balance, u32), BalanceConversionError>;
3186
3187 #[api_version(2)]
3190 fn version_declarations() -> ReviveRuntimeApiVersionDeclarations;
3191
3192 #[api_version(2)]
3193 fn eth_block_versioned(input: BlockVersionedInputPayload) -> BlockVersionedOutputPayload;
3194
3195 #[api_version(2)]
3196 fn eth_block_hash_versioned(input: BlockHashVersionedInputPayload) -> BlockHashVersionedOutputPayload;
3197
3198 #[api_version(2)]
3199 fn eth_receipt_data_versioned(input: ReceiptDataVersionedInputPayload) -> ReceiptDataVersionedOutputPayload;
3200
3201 #[api_version(2)]
3202 fn block_gas_limit_versioned(
3203 input: BlockGasLimitVersionedInputPayload
3204 ) -> BlockGasLimitVersionedOutputPayload;
3205
3206 #[api_version(2)]
3207 fn max_extrinsic_weight_in_gas_versioned(
3208 input: MaxExtrinsicWeightInGasVersionedInputPayload
3209 ) -> MaxExtrinsicWeightInGasVersionedOutputPayload;
3210
3211 #[api_version(2)]
3212 fn balance_versioned(input: BalanceVersionedInputPayload) -> BalanceVersionedOutputPayload;
3213
3214 #[api_version(2)]
3215 fn gas_price_versioned(input: GasPriceVersionedInputPayload) -> GasPriceVersionedOutputPayload;
3216
3217 #[api_version(2)]
3218 fn nonce_versioned(input: NonceVersionedInputPayload) -> NonceVersionedOutputPayload<Nonce>;
3219
3220 #[api_version(2)]
3221 fn call_versioned(
3222 input: CallVersionedInputPayload<AccountId, Balance>
3223 ) -> CallVersionedOutputPayload<Balance>;
3224
3225 #[api_version(2)]
3226 fn instantiate_versioned(
3227 input: InstantiateVersionedInputPayload<AccountId, Balance>
3228 ) -> InstantiateVersionedOutputPayload<Balance>;
3229
3230 #[api_version(2)]
3231 fn eth_transact_versioned(
3232 input: TransactVersionedInputPayload<Moment>
3233 ) -> Result<TransactVersionedOutputPayload<Balance>, EthTransactError>;
3234
3235 #[api_version(2)]
3236 fn eth_estimate_gas_versioned(
3237 input: EstimateGasVersionedInputPayload<Moment>
3238 ) -> Result<EstimateGasVersionedOutputPayload, EthTransactError>;
3239
3240 #[api_version(2)]
3241 fn eth_pre_dispatch_weight_versioned(
3242 input: PreDispatchWeightVersionedInputPayload
3243 ) -> Result<PreDispatchWeightVersionedOutputPayload, EthTransactError>;
3244
3245 #[api_version(2)]
3246 fn upload_code_versioned(
3247 input: UploadCodeVersionedInputPayload<AccountId, Balance>
3248 ) -> Result<UploadCodeVersionedOutputPayload<Balance>, DispatchError>;
3249
3250 #[api_version(2)]
3251 fn get_storage_versioned(
3252 input: GetStorageVersionedInputPayload
3253 ) -> Result<GetStorageVersionedOutputPayload, ContractAccessError>;
3254
3255 #[api_version(2)]
3256 fn runtime_pallets_address_versioned(
3257 input: RuntimePalletsAddressVersionedInputPayload
3258 ) -> RuntimePalletsAddressVersionedOutputPayload;
3259
3260 #[api_version(2)]
3261 fn code_versioned(input: CodeVersionedInputPayload) -> CodeVersionedOutputPayload;
3262
3263 #[api_version(2)]
3264 fn account_id_versioned(input: AccountIdVersionedInputPayload) -> AccountIdVersionedOutputPayload<AccountId>;
3265
3266 #[api_version(2)]
3267 fn new_balance_with_dust_versioned(
3268 input: NewBalanceWithDustVersionedInputPayload
3269 ) -> Result<NewBalanceWithDustVersionedOutputPayload<Balance>, BalanceConversionError>;
3270
3271 #[api_version(2)]
3272 fn block_author_versioned(input: BlockAuthorVersionedInputPayload) -> BlockAuthorVersionedOutputPayload;
3273
3274 #[api_version(2)]
3275 fn address_versioned(input: AddressVersionedInputPayload<AccountId>) -> AddressVersionedOutputPayload;
3276
3277 #[api_version(2)]
3278 fn trace_block_versioned(input: TraceBlockVersionedInputPayload<Block>) -> TraceBlockVersionedOutputPayload;
3279
3280 #[api_version(2)]
3281 fn trace_tx_versioned(input: TraceTxVersionedInputPayload<Block>) -> TraceTxVersionedOutputPayload;
3282
3283 #[api_version(2)]
3284 fn trace_call_versioned(
3285 input: TraceCallVersionedInputPayload
3286 ) -> Result<TraceCallVersionedOutputPayload, EthTransactError>;
3287 }
3288}
3289
3290#[macro_export]
3304macro_rules! impl_runtime_apis_plus_revive_traits {
3305 ($Runtime: ty, $Revive: ident, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
3306
3307 type __ReviveMacroMoment = $crate::MomentOf<$Runtime>;
3308
3309 impl $crate::evm::runtime::SetWeightLimit for RuntimeCall {
3310 fn set_weight_limit(&mut self, new_weight_limit: Weight) -> Weight {
3311 use $crate::pallet::Call as ReviveCall;
3312 match self {
3313 Self::$Revive(
3314 ReviveCall::eth_call{ weight_limit, .. } |
3315 ReviveCall::eth_instantiate_with_code{ weight_limit, .. }
3316 ) => {
3317 let old = *weight_limit;
3318 *weight_limit = new_weight_limit;
3319 old
3320 },
3321 _ => Weight::default(),
3322 }
3323 }
3324 }
3325
3326 impl_runtime_apis! {
3327 $($rest)*
3328
3329 #[api_version(2)]
3330 impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber, __ReviveMacroMoment> for $Runtime
3331 {
3332 fn eth_block() -> $crate::pallet_revive_types::runtime_api::BlockV1 {
3333 use $crate::pallet_revive_types::runtime_api::*;
3334
3335 let input = BlockVersionedInputPayload::from(BlockInputPayloadV1);
3336 let output = Self::eth_block_versioned(input);
3337 BlockOutputPayloadV1::try_from(output)
3338 .expect("v1 input must produce v1 output; qed")
3339 .block
3340 }
3341
3342 fn eth_block_hash(number: $crate::U256) -> Option<$crate::H256> {
3343 use $crate::pallet_revive_types::runtime_api::*;
3344
3345 let input = BlockHashVersionedInputPayload::from(BlockHashInputPayloadV1 {
3346 block_number: number
3347 });
3348 let output = Self::eth_block_hash_versioned(input);
3349 BlockHashOutputPayloadV1::try_from(output)
3350 .expect("v1 input must produce v1 output; qed")
3351 .block_hash
3352 }
3353
3354 fn eth_receipt_data() -> Vec<$crate::pallet_revive_types::runtime_api::ReceiptGasInfoV1> {
3355 use $crate::pallet_revive_types::runtime_api::*;
3356
3357 let input = ReceiptDataVersionedInputPayload::from(ReceiptDataInputPayloadV1);
3358 let output = Self::eth_receipt_data_versioned(input);
3359 ReceiptDataOutputPayloadV1::try_from(output)
3360 .expect("v1 input must produce v1 output; qed")
3361 .receipt_data
3362 }
3363
3364 fn balance(address: $crate::H160) -> $crate::U256 {
3365 use $crate::pallet_revive_types::runtime_api::*;
3366
3367 let input = BalanceVersionedInputPayload::from(BalanceInputPayloadV1 { address });
3368 let output = Self::balance_versioned(input);
3369 BalanceOutputPayloadV1::try_from(output)
3370 .expect("v1 input must produce v1 output; qed")
3371 .balance
3372 }
3373
3374 fn block_author() -> $crate::H160 {
3375 use $crate::pallet_revive_types::runtime_api::*;
3376
3377 let input = BlockAuthorVersionedInputPayload::from(BlockAuthorInputPayloadV1);
3378 let output = Self::block_author_versioned(input);
3379 BlockAuthorOutputPayloadV1::try_from(output)
3380 .expect("v1 input must produce v1 output; qed")
3381 .block_author
3382 }
3383
3384 fn block_gas_limit() -> $crate::U256 {
3385 use $crate::pallet_revive_types::runtime_api::*;
3386
3387 let input = BlockGasLimitVersionedInputPayload::from(BlockGasLimitInputPayloadV1);
3388 let output = Self::block_gas_limit_versioned(input);
3389 BlockGasLimitOutputPayloadV1::try_from(output)
3390 .expect("v1 input must produce v1 output; qed")
3391 .block_gas_limit
3392 }
3393
3394 fn max_extrinsic_weight_in_gas() -> $crate::U256 {
3395 use $crate::pallet_revive_types::runtime_api::*;
3396
3397 let input = MaxExtrinsicWeightInGasVersionedInputPayload::from(
3398 MaxExtrinsicWeightInGasInputPayloadV1
3399 );
3400 let output = Self::max_extrinsic_weight_in_gas_versioned(input);
3401 MaxExtrinsicWeightInGasOutputPayloadV1::try_from(output)
3402 .expect("v1 input must produce v1 output; qed")
3403 .max_extrinsic_weight_in_gas
3404 }
3405
3406 fn gas_price() -> $crate::U256 {
3407 use $crate::pallet_revive_types::runtime_api::*;
3408
3409 let input = GasPriceVersionedInputPayload::from(GasPriceInputPayloadV1);
3410 let output = Self::gas_price_versioned(input);
3411 GasPriceOutputPayloadV1::try_from(output)
3412 .expect("v1 input must produce v1 output; qed")
3413 .gas_price
3414 }
3415
3416 fn nonce(address: $crate::H160) -> Nonce {
3417 use $crate::pallet_revive_types::runtime_api::*;
3418
3419 let input = NonceVersionedInputPayload::from(NonceInputPayloadV1 { address });
3420 let output = Self::nonce_versioned(input);
3421 NonceOutputPayloadV1::try_from(output)
3422 .expect("v1 input must produce v1 output; qed")
3423 .nonce
3424 }
3425
3426 fn address(account_id: AccountId) -> $crate::H160 {
3427 use $crate::pallet_revive_types::runtime_api::*;
3428
3429 let input = AddressVersionedInputPayload::from(AddressInputPayloadV1 { account_id });
3430 let output = Self::address_versioned(input);
3431 AddressOutputPayloadV1::try_from(output)
3432 .expect("v1 input must produce v1 output; qed")
3433 .address
3434 }
3435
3436 fn eth_transact(
3437 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3438 ) -> Result<
3439 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3440 $crate::EthTransactError
3441 > {
3442 use $crate::pallet_revive_types::runtime_api::*;
3443
3444 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3445 tx,
3446 timestamp_override: None,
3447 perform_balance_checks: true,
3448 state_overrides: None
3449 });
3450 let output = Self::eth_transact_versioned(input)?;
3451 Ok(TransactOutputPayloadV1::try_from(output)
3452 .expect("v1 input must produce v1 output; qed")
3453 .transact_info)
3454 }
3455
3456 fn eth_transact_with_config(
3457 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3458 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3459 ) -> Result<
3460 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3461 $crate::EthTransactError
3462 > {
3463 use $crate::pallet_revive_types::runtime_api::*;
3464
3465 let DryRunConfigV1 { timestamp_override, perform_balance_checks, state_overrides } =
3466 config;
3467
3468 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3469 tx,
3470 timestamp_override,
3471 perform_balance_checks: perform_balance_checks.unwrap_or(false),
3472 state_overrides
3473 });
3474 let output = Self::eth_transact_versioned(input)?;
3475 Ok(TransactOutputPayloadV1::try_from(output)
3476 .expect("v1 input must produce v1 output; qed")
3477 .transact_info)
3478 }
3479
3480 fn eth_estimate_gas(
3481 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3482 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3483 ) -> Result<$crate::U256, $crate::EthTransactError> {
3484 use $crate::pallet_revive_types::runtime_api::*;
3485
3486 let DryRunConfigV1 { timestamp_override, perform_balance_checks: _, state_overrides } =
3487 config;
3488
3489 let input = EstimateGasVersionedInputPayload::from(EstimateGasInputPayloadV1 {
3490 tx,
3491 timestamp_override,
3492 state_overrides
3493 });
3494 let output = Self::eth_estimate_gas_versioned(input)?;
3495 Ok(EstimateGasOutputPayloadV1::try_from(output)
3496 .expect("v1 input must produce v1 output; qed")
3497 .gas_estimate)
3498 }
3499
3500 fn eth_pre_dispatch_weight(
3501 tx: Vec<u8>,
3502 ) -> Result<$crate::Weight, $crate::EthTransactError> {
3503 use $crate::pallet_revive_types::runtime_api::*;
3504
3505 let input = PreDispatchWeightVersionedInputPayload::from(
3506 PreDispatchWeightInputPayloadV1 { tx }
3507 );
3508 let output = Self::eth_pre_dispatch_weight_versioned(input)?;
3509 Ok(PreDispatchWeightOutputPayloadV1::try_from(output)
3510 .expect("v1 input must produce v1 output; qed")
3511 .weight)
3512 }
3513
3514 fn call(
3515 origin: AccountId,
3516 dest: $crate::H160,
3517 value: Balance,
3518 weight_limit: Option<$crate::Weight>,
3519 storage_deposit_limit: Option<Balance>,
3520 input_data: Vec<u8>,
3521 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3522 $crate::pallet_revive_types::runtime_api::ExecReturnValueV1,
3523 Balance
3524 > {
3525 use $crate::pallet_revive_types::runtime_api::*;
3526
3527 let input = CallVersionedInputPayload::from(CallInputPayloadV1 {
3528 origin,
3529 dest,
3530 value,
3531 gas_limit: weight_limit,
3532 storage_deposit_limit,
3533 input_data
3534 });
3535 let output = Self::call_versioned(input);
3536 CallOutputPayloadV1::try_from(output)
3537 .expect("v1 input must produce v1 output; qed")
3538 .contract_result
3539 }
3540
3541 fn instantiate(
3542 origin: AccountId,
3543 value: Balance,
3544 weight_limit: Option<$crate::Weight>,
3545 storage_deposit_limit: Option<Balance>,
3546 code: $crate::pallet_revive_types::runtime_api::CodeV1,
3547 data: Vec<u8>,
3548 salt: Option<[u8; 32]>,
3549 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3550 $crate::pallet_revive_types::runtime_api::InstantiateReturnValueV1,
3551 Balance
3552 > {
3553 use $crate::pallet_revive_types::runtime_api::*;
3554
3555 let input = InstantiateVersionedInputPayload::from(InstantiateInputPayloadV1 {
3556 origin,
3557 value,
3558 gas_limit: weight_limit,
3559 storage_deposit_limit,
3560 code,
3561 data,
3562 salt
3563 });
3564 let output = Self::instantiate_versioned(input);
3565 InstantiateOutputPayloadV1::try_from(output)
3566 .expect("v1 input must produce v1 output; qed")
3567 .contract_result
3568 }
3569
3570 fn upload_code(
3571 origin: AccountId,
3572 code: Vec<u8>,
3573 storage_deposit_limit: Option<Balance>,
3574 ) -> Result<$crate::pallet_revive_types::runtime_api::CodeUploadReturnValueV1<Balance>, $crate::sp_runtime::DispatchError> {
3575 use $crate::pallet_revive_types::runtime_api::*;
3576
3577 let input = UploadCodeVersionedInputPayload::from(UploadCodeInputPayloadV1 {
3578 origin,
3579 code,
3580 storage_deposit_limit
3581 });
3582 let output = Self::upload_code_versioned(input)?;
3583 Ok(UploadCodeOutputPayloadV1::try_from(output)
3584 .expect("v1 input must produce v1 output; qed")
3585 .code_upload_return_value)
3586 }
3587
3588 fn get_storage_var_key(
3589 address: $crate::H160,
3590 key: Vec<u8>,
3591 ) -> $crate::GetStorageResult {
3592 use $crate::pallet_revive_types::runtime_api::*;
3593
3594 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3595 address,
3596 key: StorageKeyV1::Variable(key)
3597 });
3598 let output = Self::get_storage_versioned(input)?;
3599 Ok(GetStorageOutputPayloadV1::try_from(output)
3600 .expect("v1 input must produce v1 output; qed")
3601 .storage)
3602 }
3603
3604 fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
3605 use $crate::pallet_revive_types::runtime_api::*;
3606
3607 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3608 address,
3609 key: StorageKeyV1::Fixed(key)
3610 });
3611 let output = Self::get_storage_versioned(input)?;
3612 Ok(GetStorageOutputPayloadV1::try_from(output)
3613 .expect("v1 input must produce v1 output; qed")
3614 .storage)
3615 }
3616
3617 fn trace_block(
3618 block: Block,
3619 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3620 ) -> Vec<(u32, $crate::pallet_revive_types::runtime_api::TraceV1)> {
3621 use $crate::pallet_revive_types::runtime_api::*;
3622
3623 let input = TraceBlockVersionedInputPayload::from(TraceBlockInputPayloadV1 {
3624 block,
3625 config: tracer_type
3626 });
3627 let output = Self::trace_block_versioned(input);
3628 TraceBlockOutputPayloadV1::try_from(output)
3629 .expect("v1 input must produce v1 output; qed")
3630 .traces
3631 }
3632
3633 fn trace_tx(
3634 block: Block,
3635 tx_index: u32,
3636 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3637 ) -> Option<$crate::pallet_revive_types::runtime_api::TraceV1> {
3638 use $crate::pallet_revive_types::runtime_api::*;
3639
3640 let input = TraceTxVersionedInputPayload::from(TraceTxInputPayloadV1 {
3641 block,
3642 tx_index,
3643 config: tracer_type
3644 });
3645 let output = Self::trace_tx_versioned(input);
3646 TraceTxOutputPayloadV1::try_from(output)
3647 .expect("v1 input must produce v1 output; qed")
3648 .trace
3649 }
3650
3651 fn trace_call(
3652 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3653 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3654 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3655 use $crate::pallet_revive_types::runtime_api::*;
3656
3657 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3658 tx,
3659 config: tracer_type,
3660 state_overrides: None
3661 });
3662 let output = Self::trace_call_versioned(input)?;
3663 Ok(TraceCallOutputPayloadV1::try_from(output)
3664 .expect("v1 input must produce v1 output; qed")
3665 .trace)
3666 }
3667
3668 fn trace_call_with_config(
3669 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3670 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3671 config: $crate::pallet_revive_types::runtime_api::TracingConfigV1,
3672 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3673 use $crate::pallet_revive_types::runtime_api::*;
3674
3675 let TracingConfigV1 { state_overrides } = config;
3676
3677 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3678 tx,
3679 config: tracer_type,
3680 state_overrides
3681 });
3682 let output = Self::trace_call_versioned(input)?;
3683 Ok(TraceCallOutputPayloadV1::try_from(output)
3684 .expect("v1 input must produce v1 output; qed")
3685 .trace)
3686 }
3687
3688 fn runtime_pallets_address() -> $crate::H160 {
3689 use $crate::pallet_revive_types::runtime_api::*;
3690
3691 let input = RuntimePalletsAddressVersionedInputPayload::from(
3692 RuntimePalletsAddressInputPayloadV1
3693 );
3694 let output = Self::runtime_pallets_address_versioned(input);
3695 RuntimePalletsAddressOutputPayloadV1::try_from(output)
3696 .expect("v1 input must produce v1 output; qed")
3697 .runtime_pallets_address
3698 }
3699
3700 fn code(address: $crate::H160) -> Vec<u8> {
3701 use $crate::pallet_revive_types::runtime_api::*;
3702
3703 let input = CodeVersionedInputPayload::from(CodeInputPayloadV1 { address });
3704 let output = Self::code_versioned(input);
3705 CodeOutputPayloadV1::try_from(output)
3706 .expect("v1 input must produce v1 output; qed")
3707 .code
3708 }
3709
3710 fn account_id(address: $crate::H160) -> AccountId {
3711 use $crate::pallet_revive_types::runtime_api::*;
3712
3713 let input = AccountIdVersionedInputPayload::from(AccountIdInputPayloadV1 { address });
3714 let output = Self::account_id_versioned(input);
3715 AccountIdOutputPayloadV1::try_from(output)
3716 .expect("v1 input must produce v1 output; qed")
3717 .account_id
3718 }
3719
3720 fn new_balance_with_dust(balance: $crate::U256) -> Result<(Balance, u32), $crate::BalanceConversionError> {
3721 use $crate::pallet_revive_types::runtime_api::*;
3722
3723 let input = NewBalanceWithDustVersionedInputPayload::from(
3724 NewBalanceWithDustInputPayloadV1 { balance }
3725 );
3726 let output = Self::new_balance_with_dust_versioned(input)?;
3727 let output = NewBalanceWithDustOutputPayloadV1::try_from(output)
3728 .expect("v1 input must produce v1 output; qed");
3729 Ok((output.new_balance, output.dust))
3730 }
3731
3732 fn version_declarations()
3735 -> $crate::pallet_revive_types::runtime_api::ReviveRuntimeApiVersionDeclarations
3736 {
3737 use $crate::pallet_revive_types::runtime_api::*;
3738
3739 ReviveRuntimeApiVersionDeclarations::new()
3740 .insert("eth_block_versioned", 1)
3741 .insert("eth_block_hash_versioned", 1)
3742 .insert("eth_receipt_data_versioned", 1)
3743 .insert("block_gas_limit_versioned", 1)
3744 .insert("max_extrinsic_weight_in_gas_versioned", 1)
3745 .insert("balance_versioned", 1)
3746 .insert("gas_price_versioned", 1)
3747 .insert("nonce_versioned", 1)
3748 .insert("call_versioned", 1)
3749 .insert("instantiate_versioned", 1)
3750 .insert("eth_transact_versioned", 1)
3751 .insert("eth_estimate_gas_versioned", 1)
3752 .insert("eth_pre_dispatch_weight_versioned", 1)
3753 .insert("upload_code_versioned", 1)
3754 .insert("get_storage_versioned", 1)
3755 .insert("runtime_pallets_address_versioned", 1)
3756 .insert("code_versioned", 1)
3757 .insert("account_id_versioned", 1)
3758 .insert("new_balance_with_dust_versioned", 1)
3759 .insert("block_author_versioned", 1)
3760 .insert("address_versioned", 1)
3761 .insert("trace_block_versioned", 2)
3762 .insert("trace_tx_versioned", 2)
3763 .insert("trace_call_versioned", 2)
3764 }
3765
3766 fn eth_block_versioned(
3767 input: $crate::pallet_revive_types::runtime_api::BlockVersionedInputPayload
3768 ) -> $crate::pallet_revive_types::runtime_api::BlockVersionedOutputPayload {
3769 use $crate::pallet_revive_types::runtime_api::*;
3770 use $crate::runtime_api::*;
3771 use alloc::boxed::Box;
3772
3773 let (_input, output_wrapper): (
3774 _,
3775 Box<dyn Fn(BlockOutputPayload) -> BlockVersionedOutputPayload>,
3776 ) = match input {
3777 BlockVersionedInputPayload::V1(payload) => (
3778 BlockInputPayload::from(payload),
3779 Box::new(|output| BlockVersionedOutputPayload::V1(output.into())),
3780 ),
3781 };
3782
3783 let output = BlockOutputPayload { block: $crate::Pallet::<Self>::eth_block() };
3784 output_wrapper(output)
3785 }
3786
3787 fn eth_block_hash_versioned(
3788 input: $crate::pallet_revive_types::runtime_api::BlockHashVersionedInputPayload
3789 ) -> $crate::pallet_revive_types::runtime_api::BlockHashVersionedOutputPayload {
3790 use $crate::pallet_revive_types::runtime_api::*;
3791 use $crate::runtime_api::*;
3792 use alloc::boxed::Box;
3793
3794 let (input, output_wrapper): (
3795 _,
3796 Box<dyn Fn(BlockHashOutputPayload) -> BlockHashVersionedOutputPayload>,
3797 ) = match input {
3798 BlockHashVersionedInputPayload::V1(payload) => (
3799 BlockHashInputPayload::from(payload),
3800 Box::new(|output| BlockHashVersionedOutputPayload::V1(output.into())),
3801 ),
3802 };
3803
3804 let output = BlockHashOutputPayload {
3805 block_hash: $crate::Pallet::<Self>::eth_block_hash_from_number(input.block_number)
3806 };
3807 output_wrapper(output)
3808 }
3809
3810 fn eth_receipt_data_versioned(
3811 input: $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedInputPayload
3812 ) -> $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedOutputPayload {
3813 use $crate::pallet_revive_types::runtime_api::*;
3814 use $crate::runtime_api::*;
3815 use alloc::boxed::Box;
3816
3817 let (_input, output_wrapper): (
3818 _,
3819 Box<dyn Fn(ReceiptDataOutputPayload) -> ReceiptDataVersionedOutputPayload>,
3820 ) = match input {
3821 ReceiptDataVersionedInputPayload::V1(payload) => (
3822 ReceiptDataInputPayload::from(payload),
3823 Box::new(|output| ReceiptDataVersionedOutputPayload::V1(output.into())),
3824 ),
3825 };
3826
3827 let output = ReceiptDataOutputPayload {
3828 receipt_data: $crate::Pallet::<Self>::eth_receipt_data()
3829 };
3830 output_wrapper(output)
3831 }
3832
3833 fn block_gas_limit_versioned(
3834 input: $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedInputPayload
3835 ) -> $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedOutputPayload {
3836 use $crate::pallet_revive_types::runtime_api::*;
3837 use $crate::runtime_api::*;
3838 use alloc::boxed::Box;
3839
3840 let (_input, output_wrapper): (
3841 _,
3842 Box<dyn Fn(BlockGasLimitOutputPayload) -> BlockGasLimitVersionedOutputPayload>,
3843 ) = match input {
3844 BlockGasLimitVersionedInputPayload::V1(payload) => (
3845 BlockGasLimitInputPayload::from(payload),
3846 Box::new(|output| BlockGasLimitVersionedOutputPayload::V1(output.into())),
3847 ),
3848 };
3849
3850 let output = BlockGasLimitOutputPayload {
3851 block_gas_limit: $crate::Pallet::<Self>::evm_block_gas_limit()
3852 };
3853 output_wrapper(output)
3854 }
3855
3856 fn max_extrinsic_weight_in_gas_versioned(
3857 input: $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedInputPayload
3858 ) -> $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedOutputPayload {
3859 use $crate::pallet_revive_types::runtime_api::*;
3860 use $crate::runtime_api::*;
3861 use alloc::boxed::Box;
3862
3863 let (_input, output_wrapper): (
3864 _,
3865 Box<dyn Fn(MaxExtrinsicWeightInGasOutputPayload) -> MaxExtrinsicWeightInGasVersionedOutputPayload>,
3866 ) = match input {
3867 MaxExtrinsicWeightInGasVersionedInputPayload::V1(payload) => (
3868 MaxExtrinsicWeightInGasInputPayload::from(payload),
3869 Box::new(|output| MaxExtrinsicWeightInGasVersionedOutputPayload::V1(output.into())),
3870 ),
3871 };
3872
3873 let output = MaxExtrinsicWeightInGasOutputPayload {
3874 max_extrinsic_weight_in_gas: $crate::Pallet::<Self>::evm_max_extrinsic_weight_in_gas()
3875 };
3876 output_wrapper(output)
3877 }
3878
3879 fn balance_versioned(
3880 input: $crate::pallet_revive_types::runtime_api::BalanceVersionedInputPayload
3881 ) -> $crate::pallet_revive_types::runtime_api::BalanceVersionedOutputPayload {
3882 use $crate::pallet_revive_types::runtime_api::*;
3883 use $crate::runtime_api::*;
3884 use alloc::boxed::Box;
3885
3886 let (input, output_wrapper): (
3887 _,
3888 Box<dyn Fn(BalanceOutputPayload) -> BalanceVersionedOutputPayload>,
3889 ) = match input {
3890 BalanceVersionedInputPayload::V1(payload) => (
3891 BalanceInputPayload::from(payload),
3892 Box::new(|output| BalanceVersionedOutputPayload::V1(output.into())),
3893 ),
3894 };
3895
3896 let output = BalanceOutputPayload {
3897 balance: $crate::Pallet::<Self>::evm_balance(&input.address)
3898 };
3899 output_wrapper(output)
3900 }
3901
3902 fn gas_price_versioned(
3903 input: $crate::pallet_revive_types::runtime_api::GasPriceVersionedInputPayload
3904 ) -> $crate::pallet_revive_types::runtime_api::GasPriceVersionedOutputPayload {
3905 use $crate::pallet_revive_types::runtime_api::*;
3906 use $crate::runtime_api::*;
3907 use alloc::boxed::Box;
3908
3909 let (_input, output_wrapper): (
3910 _,
3911 Box<dyn Fn(GasPriceOutputPayload) -> GasPriceVersionedOutputPayload>,
3912 ) = match input {
3913 GasPriceVersionedInputPayload::V1(payload) => (
3914 GasPriceInputPayload::from(payload),
3915 Box::new(|output| GasPriceVersionedOutputPayload::V1(output.into())),
3916 ),
3917 };
3918
3919 let output = GasPriceOutputPayload {
3920 gas_price: $crate::Pallet::<Self>::evm_base_fee()
3921 };
3922 output_wrapper(output)
3923 }
3924
3925 fn nonce_versioned(
3926 input: $crate::pallet_revive_types::runtime_api::NonceVersionedInputPayload
3927 ) -> $crate::pallet_revive_types::runtime_api::NonceVersionedOutputPayload<Nonce> {
3928 use $crate::pallet_revive_types::runtime_api::*;
3929 use $crate::runtime_api::*;
3930 use $crate::AddressMapper;
3931 use alloc::boxed::Box;
3932
3933 let (input, output_wrapper): (
3934 _,
3935 Box<dyn Fn(NonceOutputPayload<Nonce>) -> NonceVersionedOutputPayload<Nonce>>,
3936 ) = match input {
3937 NonceVersionedInputPayload::V1(payload) => (
3938 NonceInputPayload::from(payload),
3939 Box::new(|output| NonceVersionedOutputPayload::V1(output.into())),
3940 ),
3941 };
3942
3943 let account = <Self as $crate::Config>::AddressMapper::to_account_id(&input.address);
3944 let output = NonceOutputPayload {
3945 nonce: $crate::frame_system::Pallet::<Self>::account_nonce(account)
3946 };
3947 output_wrapper(output)
3948 }
3949
3950 fn call_versioned(
3951 input: $crate::pallet_revive_types::runtime_api::CallVersionedInputPayload<AccountId, Balance>
3952 ) -> $crate::pallet_revive_types::runtime_api::CallVersionedOutputPayload<Balance> {
3953 use $crate::pallet_revive_types::runtime_api::*;
3954 use $crate::runtime_api::*;
3955 use $crate::frame_support::traits::Get;
3956 use alloc::boxed::Box;
3957
3958 let (input, output_wrapper): (
3959 _,
3960 Box<dyn Fn(CallOutputPayload<Balance>) -> CallVersionedOutputPayload<Balance>>,
3961 ) = match input {
3962 CallVersionedInputPayload::V1(payload) => (
3963 CallInputPayload::from(payload),
3964 Box::new(|output| CallVersionedOutputPayload::V1(output.into())),
3965 ),
3966 };
3967
3968 let blockweights: $crate::BlockWeights =
3969 <Self as $crate::frame_system::Config>::BlockWeights::get();
3970
3971 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
3972 let contract_result = $crate::Pallet::<Self>::bare_call(
3973 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
3974 input.dest,
3975 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
3976 $crate::TransactionLimits::WeightAndDeposit {
3977 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
3978 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
3979 },
3980 input.input_data,
3981 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
3982 );
3983
3984 let output = CallOutputPayload { contract_result };
3985 output_wrapper(output)
3986 }
3987
3988 fn instantiate_versioned(
3989 input: $crate::pallet_revive_types::runtime_api::InstantiateVersionedInputPayload<AccountId, Balance>
3990 ) -> $crate::pallet_revive_types::runtime_api::InstantiateVersionedOutputPayload<Balance> {
3991 use $crate::pallet_revive_types::runtime_api::*;
3992 use $crate::runtime_api::*;
3993 use $crate::frame_support::traits::Get;
3994 use alloc::boxed::Box;
3995
3996 let (input, output_wrapper): (
3997 _,
3998 Box<dyn Fn(InstantiateOutputPayload<Balance>) -> InstantiateVersionedOutputPayload<Balance>>,
3999 ) = match input {
4000 InstantiateVersionedInputPayload::V1(payload) => (
4001 InstantiateInputPayload::from(payload),
4002 Box::new(|output| InstantiateVersionedOutputPayload::V1(output.into())),
4003 ),
4004 };
4005
4006 let blockweights: $crate::BlockWeights =
4007 <Self as $crate::frame_system::Config>::BlockWeights::get();
4008
4009 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
4010 let contract_result = $crate::Pallet::<Self>::bare_instantiate(
4011 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
4012 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
4013 $crate::TransactionLimits::WeightAndDeposit {
4014 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
4015 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
4016 },
4017 input.code,
4018 input.data,
4019 input.salt,
4020 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
4021 );
4022
4023 let output = InstantiateOutputPayload { contract_result };
4024 output_wrapper(output)
4025 }
4026
4027 fn eth_transact_versioned(
4028 input: $crate::pallet_revive_types::runtime_api::TransactVersionedInputPayload<__ReviveMacroMoment>
4029 ) -> Result<
4030 $crate::pallet_revive_types::runtime_api::TransactVersionedOutputPayload<Balance>,
4031 $crate::EthTransactError
4032 > {
4033 use $crate::pallet_revive_types::runtime_api::*;
4034 use $crate::runtime_api::*;
4035 use $crate::{
4036 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4037 sp_runtime::traits::TransactionExtension,
4038 sp_runtime::traits::Block as BlockT
4039 };
4040 use alloc::boxed::Box;
4041
4042 let (input, output_wrapper): (
4043 _,
4044 Box<dyn Fn(TransactOutputPayload<Balance>) -> TransactVersionedOutputPayload<Balance>>,
4045 ) = match input {
4046 TransactVersionedInputPayload::V1(payload) => (
4047 TransactInputPayload::from(payload),
4048 Box::new(|output| TransactVersionedOutputPayload::V1(output.into())),
4049 ),
4050 };
4051
4052 let transact_info = $crate::Pallet::<Self>::dry_run_eth_transact(
4053 input.tx,
4054 input.timestamp_override,
4055 input.perform_balance_checks,
4056 input.state_overrides,
4057 )?;
4058 let output = TransactOutputPayload { transact_info };
4059 Ok(output_wrapper(output))
4060 }
4061
4062 fn eth_estimate_gas_versioned(
4063 input: $crate::pallet_revive_types::runtime_api::EstimateGasVersionedInputPayload<__ReviveMacroMoment>
4064 ) -> Result<
4065 $crate::pallet_revive_types::runtime_api::EstimateGasVersionedOutputPayload,
4066 $crate::EthTransactError
4067 > {
4068 use $crate::pallet_revive_types::runtime_api::*;
4069 use $crate::runtime_api::*;
4070 use $crate::{
4071 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4072 sp_runtime::traits::TransactionExtension,
4073 sp_runtime::traits::Block as BlockT
4074 };
4075 use alloc::boxed::Box;
4076
4077 let (input, output_wrapper): (
4078 _,
4079 Box<dyn Fn(EstimateGasOutputPayload) -> EstimateGasVersionedOutputPayload>,
4080 ) = match input {
4081 EstimateGasVersionedInputPayload::V1(payload) => (
4082 EstimateGasInputPayload::from(payload),
4083 Box::new(|output| EstimateGasVersionedOutputPayload::V1(output.into())),
4084 ),
4085 };
4086
4087 let gas_estimate = $crate::Pallet::<Self>::eth_estimate_gas(
4088 input.tx,
4089 input.timestamp_override,
4090 input.state_overrides,
4091 )?;
4092 let output = EstimateGasOutputPayload { gas_estimate };
4093 Ok(output_wrapper(output))
4094 }
4095
4096 fn eth_pre_dispatch_weight_versioned(
4097 input: $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedInputPayload
4098 ) -> Result<
4099 $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedOutputPayload,
4100 $crate::EthTransactError
4101 > {
4102 use $crate::pallet_revive_types::runtime_api::*;
4103 use $crate::runtime_api::*;
4104 use alloc::boxed::Box;
4105
4106 let (input, output_wrapper): (
4107 _,
4108 Box<dyn Fn(PreDispatchWeightOutputPayload) -> PreDispatchWeightVersionedOutputPayload>,
4109 ) = match input {
4110 PreDispatchWeightVersionedInputPayload::V1(payload) => (
4111 PreDispatchWeightInputPayload::from(payload),
4112 Box::new(|output| PreDispatchWeightVersionedOutputPayload::V1(output.into())),
4113 ),
4114 };
4115
4116 let output = PreDispatchWeightOutputPayload {
4117 weight: $crate::Pallet::<Self>::eth_pre_dispatch_weight(input.tx)?
4118 };
4119 Ok(output_wrapper(output))
4120 }
4121
4122 fn upload_code_versioned(
4123 input: $crate::pallet_revive_types::runtime_api::UploadCodeVersionedInputPayload<AccountId, Balance>
4124 ) -> Result<
4125 $crate::pallet_revive_types::runtime_api::UploadCodeVersionedOutputPayload<Balance>,
4126 $crate::sp_runtime::DispatchError
4127 > {
4128 use $crate::pallet_revive_types::runtime_api::*;
4129 use $crate::runtime_api::*;
4130 use alloc::boxed::Box;
4131
4132 let (input, output_wrapper): (
4133 _,
4134 Box<dyn Fn(UploadCodeOutputPayload<Balance>) -> UploadCodeVersionedOutputPayload<Balance>>,
4135 ) = match input {
4136 UploadCodeVersionedInputPayload::V1(payload) => (
4137 UploadCodeInputPayload::from(payload),
4138 Box::new(|output| UploadCodeVersionedOutputPayload::V1(output.into())),
4139 ),
4140 };
4141
4142 let origin =
4143 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin);
4144 let code_upload_return_value = $crate::Pallet::<Self>::bare_upload_code(
4145 origin,
4146 input.code,
4147 input.storage_deposit_limit.unwrap_or(u128::MAX),
4148 )?;
4149 let output = UploadCodeOutputPayload { code_upload_return_value };
4150 Ok(output_wrapper(output))
4151 }
4152
4153 fn get_storage_versioned(
4154 input: $crate::pallet_revive_types::runtime_api::GetStorageVersionedInputPayload
4155 ) -> Result<
4156 $crate::pallet_revive_types::runtime_api::GetStorageVersionedOutputPayload,
4157 $crate::ContractAccessError
4158 > {
4159 use $crate::pallet_revive_types::runtime_api::*;
4160 use $crate::runtime_api::*;
4161 use alloc::boxed::Box;
4162
4163 let (input, output_wrapper): (
4164 _,
4165 Box<dyn Fn(GetStorageOutputPayload) -> GetStorageVersionedOutputPayload>,
4166 ) = match input {
4167 GetStorageVersionedInputPayload::V1(payload) => (
4168 GetStorageInputPayload::from(payload),
4169 Box::new(|output| GetStorageVersionedOutputPayload::V1(output.into())),
4170 ),
4171 };
4172
4173 let storage = match input.key {
4174 StorageKey::Fixed(key) => $crate::Pallet::<Self>::get_storage(input.address, key)?,
4175 StorageKey::Variable(key) => $crate::Pallet::<Self>::get_storage_var_key(input.address, key)?,
4176 };
4177 let output = GetStorageOutputPayload { storage };
4178 Ok(output_wrapper(output))
4179 }
4180
4181 fn runtime_pallets_address_versioned(
4182 input: $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedInputPayload
4183 ) -> $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedOutputPayload {
4184 use $crate::pallet_revive_types::runtime_api::*;
4185 use $crate::runtime_api::*;
4186 use alloc::boxed::Box;
4187
4188 let (_input, output_wrapper): (
4189 _,
4190 Box<dyn Fn(RuntimePalletsAddressOutputPayload) -> RuntimePalletsAddressVersionedOutputPayload>,
4191 ) = match input {
4192 RuntimePalletsAddressVersionedInputPayload::V1(payload) => (
4193 RuntimePalletsAddressInputPayload::from(payload),
4194 Box::new(|output| RuntimePalletsAddressVersionedOutputPayload::V1(output.into())),
4195 ),
4196 };
4197
4198 let output = RuntimePalletsAddressOutputPayload {
4199 runtime_pallets_address: $crate::RUNTIME_PALLETS_ADDR
4200 };
4201 output_wrapper(output)
4202 }
4203
4204 fn code_versioned(
4205 input: $crate::pallet_revive_types::runtime_api::CodeVersionedInputPayload
4206 ) -> $crate::pallet_revive_types::runtime_api::CodeVersionedOutputPayload {
4207 use $crate::pallet_revive_types::runtime_api::*;
4208 use $crate::runtime_api::*;
4209 use alloc::boxed::Box;
4210
4211 let (input, output_wrapper): (
4212 _,
4213 Box<dyn Fn(CodeOutputPayload) -> CodeVersionedOutputPayload>,
4214 ) = match input {
4215 CodeVersionedInputPayload::V1(payload) => (
4216 CodeInputPayload::from(payload),
4217 Box::new(|output| CodeVersionedOutputPayload::V1(output.into())),
4218 ),
4219 };
4220
4221 let output = CodeOutputPayload {
4222 code: $crate::Pallet::<Self>::code(&input.address)
4223 };
4224 output_wrapper(output)
4225 }
4226
4227 fn account_id_versioned(
4228 input: $crate::pallet_revive_types::runtime_api::AccountIdVersionedInputPayload
4229 ) -> $crate::pallet_revive_types::runtime_api::AccountIdVersionedOutputPayload<AccountId> {
4230 use $crate::pallet_revive_types::runtime_api::*;
4231 use $crate::runtime_api::*;
4232 use $crate::AddressMapper;
4233 use alloc::boxed::Box;
4234
4235 let (input, output_wrapper): (
4236 _,
4237 Box<dyn Fn(AccountIdOutputPayload<AccountId>) -> AccountIdVersionedOutputPayload<AccountId>>,
4238 ) = match input {
4239 AccountIdVersionedInputPayload::V1(payload) => (
4240 AccountIdInputPayload::from(payload),
4241 Box::new(|output| AccountIdVersionedOutputPayload::V1(output.into())),
4242 ),
4243 };
4244
4245 let output = AccountIdOutputPayload {
4246 account_id: <Self as $crate::Config>::AddressMapper::to_account_id(&input.address)
4247 };
4248 output_wrapper(output)
4249 }
4250
4251 fn new_balance_with_dust_versioned(
4252 input: $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedInputPayload
4253 ) -> Result<
4254 $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedOutputPayload<Balance>,
4255 $crate::BalanceConversionError
4256 > {
4257 use $crate::pallet_revive_types::runtime_api::*;
4258 use $crate::runtime_api::*;
4259 use alloc::boxed::Box;
4260
4261 let (input, output_wrapper): (
4262 _,
4263 Box<
4264 dyn Fn(NewBalanceWithDustOutputPayload<Balance>) -> NewBalanceWithDustVersionedOutputPayload<Balance>,
4265 >,
4266 ) = match input {
4267 NewBalanceWithDustVersionedInputPayload::V1(payload) => (
4268 NewBalanceWithDustInputPayload::from(payload),
4269 Box::new(|output| NewBalanceWithDustVersionedOutputPayload::V1(output.into())),
4270 ),
4271 };
4272
4273 let (new_balance, dust) = $crate::Pallet::<Self>::new_balance_with_dust(input.balance)?;
4274 let output = NewBalanceWithDustOutputPayload { new_balance, dust };
4275 Ok(output_wrapper(output))
4276 }
4277
4278 fn block_author_versioned(
4279 input: $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedInputPayload
4280 ) -> $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedOutputPayload {
4281 use $crate::pallet_revive_types::runtime_api::*;
4282 use $crate::runtime_api::*;
4283 use alloc::boxed::Box;
4284
4285 let (_input, output_wrapper): (
4286 _,
4287 Box<dyn Fn(BlockAuthorOutputPayload) -> BlockAuthorVersionedOutputPayload>,
4288 ) = match input {
4289 BlockAuthorVersionedInputPayload::V1(payload) => (
4290 BlockAuthorInputPayload::from(payload),
4291 Box::new(|output| BlockAuthorVersionedOutputPayload::V1(output.into())),
4292 ),
4293 };
4294
4295 let output = BlockAuthorOutputPayload {
4296 block_author: $crate::Pallet::<Self>::block_author()
4297 };
4298 output_wrapper(output)
4299 }
4300
4301 fn address_versioned(
4302 input: $crate::pallet_revive_types::runtime_api::AddressVersionedInputPayload<AccountId>
4303 ) -> $crate::pallet_revive_types::runtime_api::AddressVersionedOutputPayload {
4304 use $crate::pallet_revive_types::runtime_api::*;
4305 use $crate::runtime_api::*;
4306 use $crate::AddressMapper;
4307 use alloc::boxed::Box;
4308
4309 let (input, output_wrapper): (
4310 _,
4311 Box<dyn Fn(AddressOutputPayload) -> AddressVersionedOutputPayload>,
4312 ) = match input {
4313 AddressVersionedInputPayload::V1(payload) => (
4314 AddressInputPayload::from(payload),
4315 Box::new(|output| AddressVersionedOutputPayload::V1(output.into())),
4316 ),
4317 };
4318
4319 let output = AddressOutputPayload {
4320 address: <Self as $crate::Config>::AddressMapper::to_address(&input.account_id)
4321 };
4322 output_wrapper(output)
4323 }
4324
4325 fn trace_block_versioned(
4326 input: $crate::pallet_revive_types::runtime_api::TraceBlockVersionedInputPayload<Block>
4327 ) -> $crate::pallet_revive_types::runtime_api::TraceBlockVersionedOutputPayload {
4328 use $crate::{
4329 sp_runtime::traits::Block,
4330 tracing::trace,
4331 evm::TraceEntry,
4332 runtime_api::*,
4333 pallet_revive_types::runtime_api::*
4334 };
4335 use alloc::boxed::Box;
4336
4337 let (input, output_wrapper): (_, Box<dyn Fn(TraceBlockOutputPayload) -> TraceBlockVersionedOutputPayload>) = match input {
4338 TraceBlockVersionedInputPayload::V1(payload) => (
4339 TraceBlockInputPayload::from(payload),
4340 Box::new(|output| TraceBlockVersionedOutputPayload::V1(output.into()))
4341 ),
4342 TraceBlockVersionedInputPayload::V2(payload) => (
4343 TraceBlockInputPayload::from(payload),
4344 Box::new(|output| TraceBlockVersionedOutputPayload::V2(output.into()))
4345 ),
4346 };
4347
4348 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4349 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4350 {
4351 return output_wrapper(Default::default())
4352 }
4353
4354 let mut entries = vec![];
4358 let (header, extrinsics) = input.block.deconstruct();
4359 <$Executive>::initialize_block(&header);
4360 for (index, ext) in extrinsics.into_iter().enumerate() {
4361 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4362 let t = tracer.as_tracing();
4363 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4364
4365 if let Some(tx_trace) = tracer.collect_trace() {
4366 entries.push((index as u32, TraceEntry::Traced(tx_trace)));
4367 } else if let Some(entry) = TraceEntry::for_untraced(&result) {
4368 entries.push((index as u32, entry));
4369 }
4370 }
4371
4372 let output = TraceBlockOutputPayload { entries };
4373 output_wrapper(output)
4374 }
4375
4376 fn trace_tx_versioned(
4377 input: $crate::pallet_revive_types::runtime_api::TraceTxVersionedInputPayload<Block>
4378 ) -> $crate::pallet_revive_types::runtime_api::TraceTxVersionedOutputPayload {
4379 use $crate::pallet_revive_types::runtime_api::*;
4380 use $crate::runtime_api::*;
4381 use $crate::{evm::TraceEntry, sp_runtime::traits::Block, tracing::trace};
4382 use alloc::boxed::Box;
4383
4384 let (input, output_wrapper): (
4385 _,
4386 Box<dyn Fn(TraceTxOutputPayload) -> TraceTxVersionedOutputPayload>,
4387 ) = match input {
4388 TraceTxVersionedInputPayload::V1(payload) => (
4389 TraceTxInputPayload::from(payload),
4390 Box::new(|output| TraceTxVersionedOutputPayload::V1(output.into())),
4391 ),
4392 TraceTxVersionedInputPayload::V2(payload) => (
4393 TraceTxInputPayload::from(payload),
4394 Box::new(|output| TraceTxVersionedOutputPayload::V2(output.into())),
4395 ),
4396 };
4397
4398 if matches!(&input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4399 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4400 {
4401 return output_wrapper(TraceTxOutputPayload { entry: None })
4402 }
4403
4404 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config);
4408 let (header, extrinsics) = input.block.deconstruct();
4409
4410 <$Executive>::initialize_block(&header);
4411 let mut entry = None;
4412 for (index, ext) in extrinsics.into_iter().enumerate() {
4413 if index as u32 == input.tx_index {
4414 let t = tracer.as_tracing();
4415 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4416 entry = match tracer.collect_trace() {
4417 Some(tx_trace) => Some(TraceEntry::Traced(tx_trace)),
4418 None => TraceEntry::for_untraced(&result),
4419 };
4420 break;
4421 } else {
4422 let _ = <$Executive>::apply_extrinsic(ext);
4423 }
4424 }
4425
4426 let output = TraceTxOutputPayload { entry };
4427 output_wrapper(output)
4428 }
4429
4430 fn trace_call_versioned(
4431 input: $crate::pallet_revive_types::runtime_api::TraceCallVersionedInputPayload
4432 ) -> Result<
4433 $crate::pallet_revive_types::runtime_api::TraceCallVersionedOutputPayload,
4434 $crate::EthTransactError
4435 > {
4436 use $crate::pallet_revive_types::runtime_api::*;
4437 use $crate::runtime_api::*;
4438 use $crate::tracing::trace;
4439 use alloc::boxed::Box;
4440
4441 let (input, output_wrapper): (
4442 _,
4443 Box<dyn Fn(TraceCallOutputPayload) -> TraceCallVersionedOutputPayload>,
4444 ) = match input {
4445 TraceCallVersionedInputPayload::V1(payload) => (
4446 TraceCallInputPayload::from(payload),
4447 Box::new(|output| TraceCallVersionedOutputPayload::V1(output.into())),
4448 ),
4449 TraceCallVersionedInputPayload::V2(payload) => (
4450 TraceCallInputPayload::from(payload),
4451 Box::new(|output| TraceCallVersionedOutputPayload::V2(output.into())),
4452 ),
4453 };
4454
4455 if let Some(overrides) = input.state_overrides {
4456 $crate::state_overrides::apply_state_overrides::<Runtime>(overrides)?;
4457 }
4458
4459 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4460 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4461 {
4462 return Err($crate::EthTransactError::Message("Execution Tracing is disabled".into()))
4463 }
4464
4465 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4466 let t = tracer.as_tracing();
4467
4468 t.watch_address(&input.tx.from.unwrap_or_default());
4469 t.watch_address(&$crate::Pallet::<Self>::block_author());
4470 let result = trace(t, || {
4471 $crate::Pallet::<Self>::dry_run_eth_transact(input.tx, None, true, None)
4472 });
4473
4474 let trace = if let Some(trace) = tracer.collect_trace() {
4475 Ok(trace)
4476 } else if let Err(err) = result {
4477 Err(err)
4478 } else {
4479 Ok($crate::Pallet::<Self>::evm_tracer(input.config).empty_trace())
4480 }?;
4481
4482 let output = TraceCallOutputPayload { trace };
4483 Ok(output_wrapper(output))
4484 }
4485 }
4486 }
4487 };
4488}