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::{CommittedReceiptLogs, EthereumBlockBuilderIR},
62 block_storage,
63 fees::InfoT as FeeInfo,
64 runtime::SetWeightLimit,
65 },
66 exec::{AccountIdOf, ExecError, Stack as ExecStack},
67 sp_runtime::TransactionOutcome,
68 storage::{AccountType, DeletionQueueManager},
69 tracing::if_tracing,
70 vm::{CodeInfo, RuntimeCosts, StorageAccessKind, pvm::extract_code_and_data},
71 weightinfo_extension::OnFinalizeBlockParts,
72};
73use alloc::{boxed::Box, format, vec};
74use codec::{Codec, Decode, Encode, MaxEncodedLen};
75use environmental::*;
76use frame_support::{
77 BoundedVec,
78 dispatch::{
79 DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
80 Pays, PostDispatchInfo, RawOrigin,
81 },
82 ensure,
83 pallet_prelude::DispatchClass,
84 storage::with_transaction,
85 traits::{
86 ConstU32, ConstU64, DefensiveResult, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced,
87 OriginTrait,
88 fungible::{Balanced, Credit, Inspect, Mutate, MutateHold},
89 tokens::Balance,
90 },
91 weights::WeightMeter,
92};
93use frame_system::{
94 Pallet as System, ensure_signed,
95 pallet_prelude::{BlockNumberFor, OriginFor},
96};
97use pallet_revive_types::runtime_api::*;
98use scale_info::TypeInfo;
99use sp_runtime::{
100 AccountId32, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion,
101 traits::{
102 BadOrigin, Bounded, Convert, Dispatchable, Saturating, UniqueSaturatedFrom,
103 UniqueSaturatedInto, Zero,
104 },
105};
106
107pub use crate::{
108 address::{AccountId32Mapper, AddressMapper, AutoMapper, TestAccountMapper, create1, create2},
109 debug::DebugSettings,
110 deposit_payment::{Deposit, PGasDeposit},
111 evm::{
112 Address as EthAddress, Block as EthBlock,
113 block_hash::{OutsideFrameLog, ReceiptGasInfo, SyntheticTransactionInfo},
114 },
115 exec::{
116 CallResources, DelegateInfo, Executable, Key, MomentOf, Origin as ExecOrigin,
117 ReentrancyProtection,
118 },
119 limits::TRANSIENT_STORAGE_BYTES as TRANSIENT_STORAGE_LIMIT,
120 metering::{
121 EthTxInfo, FrameMeter, ResourceMeter, Token as WeightToken, TransactionLimits,
122 TransactionMeter,
123 },
124 pallet::{genesis, *},
125 storage::{AccountInfo, ContractInfo},
126 transient_storage::{MeterEntry, StorageMeter as TransientStorageMeter, TransientStorage},
127 vm::{BytecodeType, ContractBlob},
128};
129pub use codec;
130use frame_support::traits::tokens::Precision;
131pub use frame_support::{self, dispatch::DispatchInfo, traits::Time, weights::Weight};
132pub use frame_system::{self, limits::BlockWeights};
133pub use primitives::*;
134pub use sp_core::{H160, H256, U256};
135pub use sp_crypto_hashing::keccak_256;
136pub use sp_runtime;
137pub use weights::WeightInfo;
138
139pub extern crate pallet_revive_types;
141
142#[cfg(doc)]
143pub use crate::vm::pvm::SyscallDoc;
144
145pub type BalanceOf<T> = <T as Config>::Balance;
146pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
147type TrieId = BoundedVec<u8, ConstU32<128>>;
148type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
149type CallOf<T> = <T as Config>::RuntimeCall;
150
151pub type ContractLogTopics = BoundedVec<H256, ConstU32<{ limits::NUM_EVENT_TOPICS }>>;
153pub type ContractLogData = BoundedVec<u8, ConstU32<{ limits::EVENT_BYTES }>>;
155
156const SENTINEL: u32 = u32::MAX;
163
164const LOG_TARGET: &str = "runtime::revive";
170
171#[frame_support::pallet]
172pub mod pallet {
173 use super::*;
174 use frame_support::{pallet_prelude::*, traits::FindAuthor};
175 use frame_system::pallet_prelude::*;
176 use sp_core::U256;
177 use sp_runtime::Perbill;
178
179 pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
181
182 #[pallet::pallet]
183 #[pallet::storage_version(STORAGE_VERSION)]
184 pub struct Pallet<T>(_);
185
186 #[pallet::config(with_default)]
187 pub trait Config: frame_system::Config {
188 type Time: Time<Moment: Into<U256>>;
190
191 #[pallet::no_default]
195 type Balance: Balance
196 + TryFrom<U256>
197 + Into<U256>
198 + Bounded
199 + UniqueSaturatedInto<u64>
200 + UniqueSaturatedFrom<u64>
201 + UniqueSaturatedInto<u128>;
202
203 #[pallet::no_default]
205 type Currency: Inspect<Self::AccountId, Balance = Self::Balance>
206 + Mutate<Self::AccountId>
207 + MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>
208 + Balanced<Self::AccountId>;
209
210 #[pallet::no_default_bounds]
217 type OnBurn: OnUnbalanced<CreditOf<Self>>;
218
219 #[pallet::no_default_bounds]
221 #[allow(deprecated)]
222 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
223
224 #[pallet::no_default_bounds]
226 type RuntimeCall: Parameter
227 + Dispatchable<
228 RuntimeOrigin = OriginFor<Self>,
229 Info = DispatchInfo,
230 PostInfo = PostDispatchInfo,
231 > + IsType<<Self as frame_system::Config>::RuntimeCall>
232 + From<Call<Self>>
233 + IsSubType<Call<Self>>
234 + GetDispatchInfo;
235
236 #[pallet::no_default_bounds]
238 type RuntimeOrigin: IsType<OriginFor<Self>>
239 + From<Origin<Self>>
240 + Into<Result<Origin<Self>, OriginFor<Self>>>;
241
242 #[pallet::no_default_bounds]
244 type RuntimeHoldReason: From<HoldReason>;
245
246 type WeightInfo: WeightInfo;
249
250 #[pallet::no_default_bounds]
254 #[allow(private_bounds)]
255 type Precompiles: precompiles::Precompiles<Self>;
256
257 type FindAuthor: FindAuthor<Self::AccountId>;
259
260 #[pallet::constant]
266 #[pallet::no_default_bounds]
267 type DepositPerByte: Get<BalanceOf<Self>>;
268
269 #[pallet::constant]
275 #[pallet::no_default_bounds]
276 type DepositPerItem: Get<BalanceOf<Self>>;
277
278 #[pallet::constant]
288 #[pallet::no_default_bounds]
289 type DepositPerChildTrieItem: Get<BalanceOf<Self>>;
290
291 #[pallet::constant]
295 type CodeHashLockupDepositPercent: Get<Perbill>;
296
297 #[pallet::no_default]
299 type AddressMapper: AddressMapper<Self>;
300
301 #[pallet::constant]
303 type AllowEVMBytecode: Get<bool>;
304
305 #[pallet::no_default_bounds]
310 type UploadOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
311
312 #[pallet::no_default_bounds]
323 type InstantiateOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
324
325 type RuntimeMemory: Get<u32>;
330
331 type PVFMemory: Get<u32>;
339
340 #[pallet::constant]
345 type ChainId: Get<u64>;
346
347 #[pallet::constant]
349 type NativeToEthRatio: Get<u32>;
350
351 #[pallet::no_default_bounds]
356 type FeeInfo: FeeInfo<Self>;
357
358 #[pallet::no_default_bounds]
361 type Deposit: Deposit<Self>;
362
363 #[pallet::constant]
376 type MaxEthExtrinsicWeight: Get<FixedU128>;
377
378 #[pallet::constant]
380 type DebugEnabled: Get<bool>;
381
382 #[pallet::constant]
389 type AutoMap: Get<bool>;
390
391 #[pallet::constant]
409 #[pallet::no_default_bounds]
410 type GasScale: Get<u32>;
411
412 #[pallet::constant]
419 type MaxOutsideFrameLogs: Get<u32>;
420 }
421
422 pub mod config_preludes {
424 use super::*;
425 use frame_support::{
426 derive_impl,
427 traits::{ConstBool, ConstU32},
428 };
429 use frame_system::EnsureSigned;
430 use sp_core::parameter_types;
431
432 type Balance = u64;
433
434 pub const DOLLARS: Balance = 1_000_000_000_000;
435 pub const CENTS: Balance = DOLLARS / 100;
436 pub const MILLICENTS: Balance = CENTS / 1_000;
437
438 pub const fn deposit(items: u32, bytes: u32) -> Balance {
439 items as Balance * 20 * CENTS + (bytes as Balance) * MILLICENTS
440 }
441
442 parameter_types! {
443 pub const DepositPerItem: Balance = deposit(1, 0);
444 pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
445 pub const DepositPerByte: Balance = deposit(0, 1);
446 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
447 pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(9, 10);
448 pub const GasScale: u32 = 10u32;
449 }
450
451 pub struct TestDefaultConfig;
453
454 impl Time for TestDefaultConfig {
455 type Moment = u64;
456 fn now() -> Self::Moment {
457 0u64
458 }
459 }
460
461 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
462 fn convert(w: Weight) -> T {
463 w.ref_time().into()
464 }
465 }
466
467 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
468 impl frame_system::DefaultConfig for TestDefaultConfig {}
469
470 #[frame_support::register_default_impl(TestDefaultConfig)]
471 impl DefaultConfig for TestDefaultConfig {
472 #[inject_runtime_type]
473 type RuntimeEvent = ();
474
475 #[inject_runtime_type]
476 type RuntimeHoldReason = ();
477
478 #[inject_runtime_type]
479 type RuntimeCall = ();
480
481 #[inject_runtime_type]
482 type RuntimeOrigin = ();
483
484 type Precompiles = ();
485 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
486 type DepositPerByte = DepositPerByte;
487 type DepositPerItem = DepositPerItem;
488 type DepositPerChildTrieItem = DepositPerChildTrieItem;
489 type Time = Self;
490 type AllowEVMBytecode = ConstBool<true>;
491 type UploadOrigin = EnsureSigned<Self::AccountId>;
492 type InstantiateOrigin = EnsureSigned<Self::AccountId>;
493 type WeightInfo = ();
494 type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
495 type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
496 type ChainId = ConstU64<42>;
497 type NativeToEthRatio = ConstU32<1_000_000>;
498 type FindAuthor = ();
499 type FeeInfo = ();
500 type Deposit = ();
501 type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
502 type DebugEnabled = ConstBool<false>;
503 type AutoMap = ConstBool<false>;
504 type GasScale = GasScale;
505 type OnBurn = ();
506 type MaxOutsideFrameLogs = ConstU32<1024>;
507 }
508 }
509
510 #[pallet::event]
511 pub enum Event<T: Config> {
512 ContractEmitted {
514 contract: H160,
516 data: Vec<u8>,
519 topics: Vec<H256>,
522 },
523
524 Instantiated { deployer: H160, contract: H160 },
526
527 EthExtrinsicRevert { dispatch_error: DispatchError },
534 }
535
536 #[pallet::error]
537 #[repr(u8)]
538 pub enum Error<T> {
539 InvalidSchedule = 0x01,
541 InvalidCallFlags = 0x02,
543 OutOfGas = 0x03,
545 TransferFailed = 0x04,
548 MaxCallDepthReached = 0x05,
551 ContractNotFound = 0x06,
553 CodeNotFound = 0x07,
555 CodeInfoNotFound = 0x08,
557 OutOfBounds = 0x09,
559 DecodingFailed = 0x0A,
561 ContractTrapped = 0x0B,
563 ValueTooLarge = 0x0C,
565 TerminatedWhileReentrant = 0x0D,
568 InputForwarded = 0x0E,
570 TooManyTopics = 0x0F,
572 DuplicateContract = 0x12,
574 TerminatedInConstructor = 0x13,
578 ReentranceDenied = 0x14,
580 ReenteredPallet = 0x15,
582 StateChangeDenied = 0x16,
584 StorageDepositNotEnoughFunds = 0x17,
586 StorageDepositLimitExhausted = 0x18,
588 CodeInUse = 0x19,
590 ContractReverted = 0x1A,
595 CodeRejected = 0x1B,
600 BlobTooLarge = 0x1C,
602 StaticMemoryTooLarge = 0x1D,
604 BasicBlockTooLarge = 0x1E,
606 InvalidInstruction = 0x1F,
608 MaxDelegateDependenciesReached = 0x20,
610 DelegateDependencyNotFound = 0x21,
612 DelegateDependencyAlreadyExists = 0x22,
614 CannotAddSelfAsDelegateDependency = 0x23,
616 OutOfTransientStorage = 0x24,
618 InvalidSyscall = 0x25,
620 InvalidStorageFlags = 0x26,
622 ExecutionFailed = 0x27,
624 BalanceConversionFailed = 0x28,
626 InvalidImmutableAccess = 0x2A,
629 AccountUnmapped = 0x2B,
633 AccountAlreadyMapped = 0x2C,
635 InvalidGenericTransaction = 0x2D,
637 RefcountOverOrUnderflow = 0x2E,
639 UnsupportedPrecompileAddress = 0x2F,
641 CallDataTooLarge = 0x30,
643 ReturnDataTooLarge = 0x31,
645 InvalidJump = 0x32,
647 StackUnderflow = 0x33,
649 StackOverflow = 0x34,
651 TxFeeOverdraw = 0x35,
655 EvmConstructorNonEmptyData = 0x36,
659 EvmConstructedFromHash = 0x37,
664 StorageRefundNotEnoughFunds = 0x38,
668 StorageRefundLocked = 0x39,
673 PrecompileDelegateDenied = 0x40,
678 EcdsaRecoveryFailed = 0x41,
680 AutoMappingEnabled = 0x42,
682 PendingDepositCleanup = 0x43,
686 CannotTerminateDelegatedAccount = 0x44,
689 #[cfg(feature = "runtime-benchmarks")]
691 BenchmarkingError = 0xFF,
692 }
693
694 #[pallet::composite_enum]
696 pub enum HoldReason {
697 CodeUploadDepositReserve,
699 StorageDepositReserve,
701 AddressMapping,
703 }
704
705 #[pallet::composite_enum]
707 pub enum FreezeReason {
708 PGasMinBalance,
713 }
714
715 #[derive(
716 PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug,
717 )]
718 #[pallet::origin]
719 pub enum Origin<T: Config> {
720 EthTransaction(T::AccountId),
721 }
722
723 #[pallet::storage]
727 #[pallet::unbounded]
728 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, Vec<u8>>;
729
730 #[pallet::storage]
732 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
733
734 #[pallet::storage]
736 pub(crate) type AccountInfoOf<T: Config> = StorageMap<_, Identity, H160, AccountInfo<T>>;
737
738 #[pallet::storage]
749 pub(crate) type NativeDepositOf<T: Config> = StorageDoubleMap<
750 _,
751 Identity,
752 T::AccountId,
753 Identity,
754 T::AccountId,
755 BalanceOf<T>,
756 ValueQuery,
757 >;
758
759 #[pallet::storage]
761 pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
762
763 #[pallet::storage]
769 pub(crate) type DeletionQueue<T: Config> =
770 StorageMap<_, Twox64Concat, u32, crate::storage::DeletionQueueItem<T>>;
771
772 #[pallet::storage]
775 pub(crate) type DeletionQueueCounter<T: Config> =
776 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
777
778 #[pallet::storage]
785 pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
786
787 #[pallet::storage]
797 #[pallet::unbounded]
798 pub(crate) type EthereumBlock<T> = StorageValue<_, EthBlock, ValueQuery>;
799
800 #[pallet::storage]
804 pub(crate) type BlockHash<T: Config> =
805 StorageMap<_, Identity, BlockNumberFor<T>, H256, ValueQuery>;
806
807 #[pallet::storage]
814 #[pallet::unbounded]
815 pub(crate) type ReceiptInfoData<T: Config> = StorageValue<_, Vec<ReceiptGasInfo>, ValueQuery>;
816
817 #[pallet::storage]
823 #[pallet::unbounded]
824 type SyntheticReceiptInfo<T: Config> = StorageValue<_, SyntheticTransactionInfo, OptionQuery>;
825
826 #[pallet::storage]
835 #[pallet::whitelist_storage]
836 pub(crate) type ReceiptLogsCommitted<T: Config> =
837 StorageValue<_, CommittedReceiptLogs, ValueQuery>;
838
839 #[pallet::storage]
841 #[pallet::unbounded]
842 pub(crate) type EthBlockBuilderIR<T: Config> =
843 StorageValue<_, EthereumBlockBuilderIR<T>, ValueQuery>;
844
845 #[pallet::storage]
850 #[pallet::unbounded]
851 pub(crate) type EthBlockBuilderFirstValues<T: Config> =
852 StorageValue<_, Option<(Vec<u8>, Vec<u8>)>, ValueQuery>;
853
854 #[pallet::storage]
870 #[pallet::unbounded]
871 #[pallet::whitelist_storage]
872 type OutsideFrameLogs<T: Config> = StorageValue<_, Vec<OutsideFrameLog>, ValueQuery>;
873
874 #[pallet::storage]
876 pub(crate) type DebugSettingsOf<T: Config> = StorageValue<_, DebugSettings, ValueQuery>;
877
878 pub mod genesis {
879 use super::*;
880 use crate::evm::Bytes32;
881
882 #[derive(Clone, PartialEq, Debug, Default, serde::Serialize, serde::Deserialize)]
884 pub struct ContractData {
885 pub code: crate::evm::Bytes,
887 pub storage: alloc::collections::BTreeMap<Bytes32, Bytes32>,
889 }
890
891 #[derive(PartialEq, Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
893 pub struct Account<T: Config> {
894 pub address: H160,
896 #[serde(default)]
898 pub balance: U256,
899 #[serde(default)]
901 pub nonce: T::Nonce,
902 #[serde(flatten, skip_serializing_if = "Option::is_none")]
904 pub contract_data: Option<ContractData>,
905 }
906 }
907
908 #[pallet::genesis_config]
909 #[derive(Debug, PartialEq, frame_support::DefaultNoBound)]
910 pub struct GenesisConfig<T: Config> {
911 #[serde(default, skip_serializing_if = "Vec::is_empty")]
914 pub mapped_accounts: Vec<T::AccountId>,
915
916 #[serde(default, skip_serializing_if = "Vec::is_empty")]
918 pub accounts: Vec<genesis::Account<T>>,
919
920 #[serde(default, skip_serializing_if = "Option::is_none")]
922 pub debug_settings: Option<DebugSettings>,
923 }
924
925 #[pallet::genesis_build]
926 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
927 fn build(&self) {
928 use crate::{exec::Key, vm::ContractBlob};
929 use frame_support::traits::fungible::Mutate;
930
931 if !System::<T>::account_exists(&Pallet::<T>::account_id()) {
932 let _ = T::Currency::mint_into(
933 &Pallet::<T>::account_id(),
934 T::Currency::minimum_balance(),
935 );
936 }
937
938 for id in &self.mapped_accounts {
939 if let Err(err) = T::AddressMapper::map_no_deposit_unchecked(id) {
940 log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
941 }
942 }
943
944 let owner = Pallet::<T>::account_id();
945
946 for genesis::Account { address, balance, nonce, contract_data } in &self.accounts {
947 let account_id = T::AddressMapper::to_account_id(address);
948
949 if !System::<T>::account_exists(&account_id) {
950 let _ = T::Currency::mint_into(&account_id, T::Currency::minimum_balance());
951 }
952
953 frame_system::Account::<T>::mutate(&account_id, |info| {
954 info.nonce = (*nonce).into();
955 });
956
957 match contract_data {
958 None => {
959 AccountInfoOf::<T>::insert(
960 address,
961 AccountInfo { account_type: AccountType::EOA, dust: 0 },
962 );
963 },
964 Some(genesis::ContractData { code, storage }) => {
965 let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) {
966 ContractBlob::<T>::from_pvm_code(code.0.clone(), owner.clone())
967 .inspect_err(|err| {
968 log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}");
969 })
970 } else {
971 ContractBlob::<T>::from_evm_runtime_code(code.0.clone(), account_id)
972 .inspect_err(|err| {
973 log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}");
974 })
975 };
976
977 let Ok(blob) = blob else {
978 continue;
979 };
980
981 let code_hash = *blob.code_hash();
982 let Ok(info) = <ContractInfo<T>>::new(&address, 0u32.into(), code_hash)
983 .inspect_err(|err| {
984 log::error!(target: LOG_TARGET, "Failed to create ContractInfo for {address:?}: {err:?}");
985 })
986 else {
987 continue;
988 };
989
990 AccountInfoOf::<T>::insert(
991 address,
992 AccountInfo { account_type: info.clone().into(), dust: 0 },
993 );
994
995 <PristineCode<T>>::insert(blob.code_hash(), code.0.clone());
996 <CodeInfoOf<T>>::insert(blob.code_hash(), blob.code_info().clone());
997 for (k, v) in storage {
998 let _ = info.write(&Key::from_fixed(k.0), Some(v.0.to_vec()), None, false).inspect_err(|err| {
999 log::error!(target: LOG_TARGET, "Failed to write genesis storage for {address:?} at key {k:?}: {err:?}");
1000 });
1001 }
1002 },
1003 }
1004
1005 let _ = Pallet::<T>::set_evm_balance(address, *balance).inspect_err(|err| {
1006 log::error!(target: LOG_TARGET, "Failed to set EVM balance for {address:?}: {err:?}");
1007 });
1008 }
1009
1010 Pallet::<T>::finalize_eth_block(
1012 frame_system::Pallet::<T>::block_number(),
1015 );
1016
1017 if let Some(settings) = self.debug_settings.as_ref() {
1019 settings.write_to_storage::<T>()
1020 }
1021 }
1022 }
1023
1024 impl<T: Config> Pallet<T> {
1025 pub fn eth_synthetic_transaction() -> Option<SyntheticTransactionInfo> {
1027 SyntheticReceiptInfo::<T>::get()
1028 }
1029
1030 pub fn emit_contract_log_outside_frame(
1046 contract: H160,
1047 topics: ContractLogTopics,
1048 data: ContractLogData,
1049 ) {
1050 if_tracing(|tracer| {
1051 let log_index = frame_system::Pallet::<T>::event_count();
1052 tracer.log_event_outside_frame(contract, &topics, &data, log_index);
1053 });
1054
1055 if !block_storage::capture_into_receipt::<T>(&contract, &data, &topics) {
1056 Self::buffer_outside_frame_log(&contract, &topics, &data);
1057 }
1058
1059 Self::deposit_event(Event::ContractEmitted {
1060 contract,
1061 data: data.into_inner(),
1062 topics: topics.into_inner(),
1063 });
1064 }
1065
1066 #[cfg(feature = "runtime-benchmarks")]
1069 pub fn clear_outside_frame_logs() {
1070 OutsideFrameLogs::<T>::kill();
1071 }
1072
1073 #[cfg(feature = "runtime-benchmarks")]
1077 pub fn bench_buffer_outside_frame_log(contract: H160, topics: Vec<H256>, data: Vec<u8>) {
1078 OutsideFrameLogs::<T>::append(OutsideFrameLog {
1079 event_index: frame_system::Pallet::<T>::event_count(),
1080 contract,
1081 topics,
1082 data,
1083 });
1084 }
1085
1086 fn buffer_outside_frame_log(contract: &H160, topics: &[H256], data: &[u8]) {
1090 let cap = T::MaxOutsideFrameLogs::get();
1091 if cap.is_zero() {
1092 return;
1093 }
1094 let index = OutsideFrameLogs::<T>::decode_len().unwrap_or(0) as u32;
1095 if index >= cap {
1096 log::warn!(
1098 target: LOG_TARGET,
1099 "outside-of-frame log buffer full ({index} logs); log for {contract:?} stays substrate-only",
1100 );
1101 return;
1102 }
1103
1104 if index.is_zero() &&
1111 BlockHash::<T>::contains_key(frame_system::Pallet::<T>::block_number())
1112 {
1113 log::warn!(
1114 target: LOG_TARGET,
1115 "outside-of-frame log for {contract:?} emitted after the block's drain stays substrate-only",
1116 );
1117 return;
1118 }
1119
1120 let entry = OutsideFrameLog {
1123 event_index: frame_system::Pallet::<T>::event_count(),
1124 contract: *contract,
1125 topics: topics.to_vec(),
1126 data: data.to_vec(),
1127 };
1128 let entry_bytes = Weight::from_parts(0, entry.encoded_size() as u64);
1129 OutsideFrameLogs::<T>::append(entry);
1130
1131 frame_system::Pallet::<T>::register_extra_weight_unchecked(
1142 T::WeightInfo::per_outside_frame_log(data.len() as u32).max(entry_bytes),
1143 DispatchClass::Normal,
1144 );
1145
1146 if index.is_zero() {
1151 frame_system::Pallet::<T>::register_extra_weight_unchecked(
1152 T::WeightInfo::on_finalize_block_per_tx(
1153 block_storage::SYNTHETIC_LOG_TX_MAX_LEN,
1154 ),
1155 DispatchClass::Normal,
1156 );
1157 }
1158 }
1159
1160 fn finalize_eth_block(block_number: BlockNumberFor<T>) {
1163 let outside_frame_logs = OutsideFrameLogs::<T>::take();
1164 if let Some(synthetic) =
1165 block_storage::on_finalize_build_eth_block::<T>(block_number, outside_frame_logs)
1166 {
1167 SyntheticReceiptInfo::<T>::put(synthetic);
1170 }
1171 }
1172 }
1173
1174 #[pallet::hooks]
1175 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1176 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
1177 let mut meter = WeightMeter::with_limit(limit);
1178 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
1179 meter.consumed()
1180 }
1181
1182 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
1183 block_storage::on_initialize::<T>();
1185 SyntheticReceiptInfo::<T>::kill();
1186
1187 System::<T>::account_exists(&Pallet::<T>::account_id());
1189 <T as Config>::WeightInfo::on_finalize_block_fixed()
1194 }
1195
1196 fn on_finalize(block_number: BlockNumberFor<T>) {
1197 Self::finalize_eth_block(block_number);
1198 }
1199
1200 fn integrity_test() {
1201 assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
1202
1203 assert!(T::GasScale::get() > 0u32.into(), "GasScale must not be 0");
1204
1205 T::FeeInfo::integrity_test();
1206
1207 let max_runtime_mem: u64 = T::RuntimeMemory::get().into();
1209
1210 const TOTAL_MEMORY_DEVIDER: u64 = 2;
1213
1214 let max_block_weight = T::BlockWeights::get()
1220 .get(DispatchClass::Normal)
1221 .max_total
1222 .unwrap_or_else(|| T::BlockWeights::get().max_block);
1223 let max_key_size: u64 =
1224 Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
1225 .expect("Key of maximal size shall be created")
1226 .hash()
1227 .len()
1228 .try_into()
1229 .unwrap();
1230
1231 let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
1232 let max_immutable_size: u64 = max_block_weight
1233 .checked_div_per_component(&<RuntimeCosts as WeightToken<T>>::weight(
1234 &RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
1235 ))
1236 .unwrap()
1237 .saturating_mul(
1238 u64::from(limits::IMMUTABLE_BYTES)
1239 .saturating_add(max_immutable_key_size)
1240 .into(),
1241 );
1242
1243 let max_pvf_mem: u64 = T::PVFMemory::get().into();
1244 let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
1245
1246 let max_events_size = max_block_weight
1250 .checked_div_per_component(
1251 &(<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::DepositEvent {
1252 num_topic: 0,
1253 len: limits::EVENT_BYTES,
1254 })
1255 .saturating_add(<RuntimeCosts as WeightToken<T>>::weight(
1256 &RuntimeCosts::HostFn,
1257 ))),
1258 )
1259 .unwrap()
1260 .saturating_mul(limits::EVENT_BYTES.into());
1261
1262 assert!(
1263 max_events_size <= storage_size_limit,
1264 "Maximal events size {} exceeds the events limit {}",
1265 max_events_size,
1266 storage_size_limit
1267 );
1268
1269 let max_eth_block_builder_bytes =
1304 block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());
1305
1306 log::debug!(
1307 target: LOG_TARGET,
1308 "Integrity check: max_eth_block_builder_bytes={} KB using max_events_size={} KB",
1309 max_eth_block_builder_bytes / 1024,
1310 max_events_size / 1024,
1311 );
1312
1313 let memory_left = i128::from(max_runtime_mem)
1318 .saturating_div(TOTAL_MEMORY_DEVIDER.into())
1319 .saturating_sub(limits::MEMORY_REQUIRED.into())
1320 .saturating_sub(max_eth_block_builder_bytes.into());
1321
1322 log::debug!(target: LOG_TARGET, "Integrity check: memory_left={} KB", memory_left / 1024);
1323
1324 assert!(
1325 memory_left >= 0,
1326 "Runtime does not have enough memory for current limits. Additional runtime memory required: {} KB",
1327 memory_left.saturating_mul(TOTAL_MEMORY_DEVIDER.into()).abs() / 1024
1328 );
1329
1330 let max_storage_size = max_block_weight
1333 .checked_div_per_component(
1334 &<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::SetStorage {
1335 new_bytes: limits::STORAGE_BYTES,
1336 old_bytes: 0,
1337 kind: StorageAccessKind::Persistent(Warmth::Cold { revertible: true }),
1338 })
1339 .saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
1340 )
1341 .unwrap()
1342 .saturating_add(max_immutable_size.into())
1343 .saturating_add(max_eth_block_builder_bytes.into());
1344
1345 assert!(
1346 max_storage_size <= storage_size_limit,
1347 "Maximal storage size {} exceeds the storage limit {}",
1348 max_storage_size,
1349 storage_size_limit
1350 );
1351 }
1352 }
1353
1354 #[pallet::call]
1355 impl<T: Config> Pallet<T> {
1356 #[allow(unused_variables)]
1369 #[pallet::call_index(0)]
1370 #[pallet::weight(Weight::MAX)]
1371 pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
1372 Err(frame_system::Error::CallFiltered::<T>.into())
1373 }
1374
1375 #[pallet::call_index(1)]
1392 #[pallet::weight(<T as Config>::WeightInfo::call().saturating_add(*weight_limit))]
1393 pub fn call(
1394 origin: OriginFor<T>,
1395 dest: H160,
1396 #[pallet::compact] value: BalanceOf<T>,
1397 weight_limit: Weight,
1398 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1399 data: Vec<u8>,
1400 ) -> DispatchResultWithPostInfo {
1401 Self::ensure_non_contract_if_signed(&origin)?;
1402 let mut output = Self::bare_call(
1403 origin,
1404 dest,
1405 Pallet::<T>::convert_native_to_evm(value),
1406 TransactionLimits::WeightAndDeposit {
1407 weight_limit,
1408 deposit_limit: storage_deposit_limit,
1409 },
1410 data,
1411 &ExecConfig::new_substrate_tx(),
1412 );
1413
1414 if let Ok(return_value) = &output.result &&
1415 return_value.did_revert()
1416 {
1417 output.result = Err(<Error<T>>::ContractReverted.into());
1418 }
1419 dispatch_result(
1420 output.result,
1421 output.weight_consumed,
1422 <T as Config>::WeightInfo::call(),
1423 )
1424 }
1425
1426 #[pallet::call_index(2)]
1432 #[pallet::weight(
1433 <T as Config>::WeightInfo::instantiate(data.len() as u32).saturating_add(*weight_limit)
1434 )]
1435 pub fn instantiate(
1436 origin: OriginFor<T>,
1437 #[pallet::compact] value: BalanceOf<T>,
1438 weight_limit: Weight,
1439 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1440 code_hash: sp_core::H256,
1441 data: Vec<u8>,
1442 salt: Option<[u8; 32]>,
1443 ) -> DispatchResultWithPostInfo {
1444 Self::ensure_non_contract_if_signed(&origin)?;
1445 let data_len = data.len() as u32;
1446 let mut output = Self::bare_instantiate(
1447 origin,
1448 Pallet::<T>::convert_native_to_evm(value),
1449 TransactionLimits::WeightAndDeposit {
1450 weight_limit,
1451 deposit_limit: storage_deposit_limit,
1452 },
1453 Code::Existing(code_hash),
1454 data,
1455 salt,
1456 &ExecConfig::new_substrate_tx(),
1457 );
1458 if let Ok(retval) = &output.result &&
1459 retval.result.did_revert()
1460 {
1461 output.result = Err(<Error<T>>::ContractReverted.into());
1462 }
1463 dispatch_result(
1464 output.result.map(|result| result.result),
1465 output.weight_consumed,
1466 <T as Config>::WeightInfo::instantiate(data_len),
1467 )
1468 }
1469
1470 #[pallet::call_index(3)]
1498 #[pallet::weight(
1499 <T as Config>::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
1500 .saturating_add(*weight_limit)
1501 )]
1502 pub fn instantiate_with_code(
1503 origin: OriginFor<T>,
1504 #[pallet::compact] value: BalanceOf<T>,
1505 weight_limit: Weight,
1506 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1507 code: Vec<u8>,
1508 data: Vec<u8>,
1509 salt: Option<[u8; 32]>,
1510 ) -> DispatchResultWithPostInfo {
1511 Self::ensure_non_contract_if_signed(&origin)?;
1512 let code_len = code.len() as u32;
1513 let data_len = data.len() as u32;
1514 let mut output = Self::bare_instantiate(
1515 origin,
1516 Pallet::<T>::convert_native_to_evm(value),
1517 TransactionLimits::WeightAndDeposit {
1518 weight_limit,
1519 deposit_limit: storage_deposit_limit,
1520 },
1521 Code::Upload(code),
1522 data,
1523 salt,
1524 &ExecConfig::new_substrate_tx(),
1525 );
1526 if let Ok(retval) = &output.result &&
1527 retval.result.did_revert()
1528 {
1529 output.result = Err(<Error<T>>::ContractReverted.into());
1530 }
1531 dispatch_result(
1532 output.result.map(|result| result.result),
1533 output.weight_consumed,
1534 <T as Config>::WeightInfo::instantiate_with_code(code_len, data_len),
1535 )
1536 }
1537
1538 #[pallet::call_index(10)]
1560 #[pallet::weight(
1561 <T as Config>::WeightInfo::eth_instantiate_with_code(code.len() as u32, data.len() as u32, Pallet::<T>::has_dust(*value).into())
1562 .saturating_add(*weight_limit)
1563 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1564 )]
1565 pub fn eth_instantiate_with_code(
1566 origin: OriginFor<T>,
1567 value: U256,
1568 weight_limit: Weight,
1569 eth_gas_limit: U256,
1570 code: Vec<u8>,
1571 data: Vec<u8>,
1572 transaction_encoded: Vec<u8>,
1573 effective_gas_price: U256,
1574 encoded_len: u32,
1575 ) -> DispatchResultWithPostInfo {
1576 let signer = Self::ensure_eth_signed(origin)?;
1577 let origin = OriginFor::<T>::signed(signer.clone());
1578 Self::ensure_non_contract_if_signed(&origin)?;
1579 let mut call = Call::<T>::eth_instantiate_with_code {
1580 value,
1581 weight_limit,
1582 eth_gas_limit,
1583 code: code.clone(),
1584 data: data.clone(),
1585 transaction_encoded: transaction_encoded.clone(),
1586 effective_gas_price,
1587 encoded_len,
1588 }
1589 .into();
1590 let info = T::FeeInfo::dispatch_info(&call);
1591 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1592 drop(call);
1593
1594 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1595 let extra_weight = base_info.total_weight();
1596 let output = Self::bare_instantiate(
1597 origin,
1598 value,
1599 TransactionLimits::EthereumGas {
1600 eth_gas_limit: eth_gas_limit.saturated_into(),
1601 weight_limit,
1602 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1603 authorization_deposit: Default::default(),
1604 },
1605 Code::Upload(code),
1606 data,
1607 None,
1608 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1609 );
1610
1611 block_storage::EthereumCallResult::new::<T>(
1612 signer,
1613 output.map_result(|r| r.result),
1614 base_info.call_weight,
1615 encoded_len,
1616 &info,
1617 effective_gas_price,
1618 )
1619 })
1620 }
1621
1622 #[pallet::call_index(11)]
1640 #[pallet::weight(
1641 T::WeightInfo::eth_call(Pallet::<T>::has_dust(*value).into())
1642 .saturating_add(*weight_limit)
1643 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1644 .saturating_add(evm::eip7702::worst_case_authorization_weight::<T>(authorization_list.len() as u32))
1645 )]
1646 pub fn eth_call(
1647 origin: OriginFor<T>,
1648 dest: H160,
1649 value: U256,
1650 weight_limit: Weight,
1651 eth_gas_limit: U256,
1652 data: Vec<u8>,
1653 transaction_encoded: Vec<u8>,
1654 effective_gas_price: U256,
1655 encoded_len: u32,
1656 authorization_list: Vec<evm::AuthorizationListEntry>,
1657 ) -> DispatchResultWithPostInfo {
1658 let signer = Self::ensure_eth_signed(origin)?;
1659 let origin = OriginFor::<T>::signed(signer.clone());
1660
1661 Self::ensure_non_contract_if_signed(&origin)?;
1662 let mut call = Call::<T>::eth_call {
1663 dest,
1664 value,
1665 weight_limit,
1666 eth_gas_limit,
1667 data: data.clone(),
1668 transaction_encoded: transaction_encoded.clone(),
1669 effective_gas_price,
1670 encoded_len,
1671 authorization_list: authorization_list.clone(),
1672 }
1673 .into();
1674 let info = T::FeeInfo::dispatch_info(&call);
1675 let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1676 drop(call);
1677
1678 let exec_config =
1679 ExecConfig::new_eth_tx(effective_gas_price, encoded_len, base_info.total_weight());
1680 let auth_result = evm::eip7702::process_authorizations::<T>(
1681 &authorization_list,
1682 &signer,
1683 &exec_config,
1684 );
1685 let extra_weight = base_info.total_weight().saturating_sub(auth_result.weight_refund);
1686 let base_call_weight = base_info.call_weight.saturating_sub(auth_result.weight_refund);
1687
1688 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1689 let output = Self::bare_call(
1690 origin,
1691 dest,
1692 value,
1693 TransactionLimits::EthereumGas {
1694 eth_gas_limit: eth_gas_limit.saturated_into(),
1695 weight_limit,
1696 eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1697 authorization_deposit: auth_result.deposit,
1698 },
1699 data,
1700 &ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1701 );
1702
1703 block_storage::EthereumCallResult::new::<T>(
1704 signer,
1705 output,
1706 base_call_weight,
1707 encoded_len,
1708 &info,
1709 effective_gas_price,
1710 )
1711 })
1712 }
1713
1714 #[pallet::call_index(12)]
1725 #[pallet::weight(
1726 T::WeightInfo::eth_substrate_call(transaction_encoded.len() as u32)
1727 .saturating_add(call.get_dispatch_info().call_weight)
1728 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1729 )]
1730 pub fn eth_substrate_call(
1731 origin: OriginFor<T>,
1732 call: Box<<T as Config>::RuntimeCall>,
1733 transaction_encoded: Vec<u8>,
1734 ) -> DispatchResultWithPostInfo {
1735 let signer = Self::ensure_eth_signed(origin)?;
1738 Self::ensure_non_contract_if_signed(&OriginFor::<T>::signed(signer.clone()))?;
1739 let tx_len = transaction_encoded.len() as u32;
1740 let weight_overhead = T::WeightInfo::eth_substrate_call(tx_len)
1741 .saturating_add(T::WeightInfo::on_finalize_block_per_tx(tx_len));
1742
1743 block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1744 let call_weight = call.get_dispatch_info().call_weight;
1745 let mut call_result = call.dispatch(RawOrigin::Signed(signer).into());
1746
1747 match &mut call_result {
1749 Ok(post_info) | Err(DispatchErrorWithPostInfo { post_info, .. }) => {
1750 post_info.actual_weight = Some(
1751 post_info
1752 .actual_weight
1753 .unwrap_or_else(|| call_weight)
1754 .saturating_add(weight_overhead),
1755 );
1756 },
1757 }
1758
1759 block_storage::EthereumCallResult {
1762 receipt_gas_info: ReceiptGasInfo::default(),
1763 result: call_result,
1764 }
1765 })
1766 }
1767
1768 #[pallet::call_index(4)]
1783 #[pallet::weight(<T as Config>::WeightInfo::upload_code(code.len() as u32))]
1784 pub fn upload_code(
1785 origin: OriginFor<T>,
1786 code: Vec<u8>,
1787 #[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1788 ) -> DispatchResult {
1789 Self::ensure_non_contract_if_signed(&origin)?;
1790 Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
1791 }
1792
1793 #[pallet::call_index(5)]
1798 #[pallet::weight(<T as Config>::WeightInfo::remove_code())]
1799 pub fn remove_code(
1800 origin: OriginFor<T>,
1801 code_hash: sp_core::H256,
1802 ) -> DispatchResultWithPostInfo {
1803 let origin = ensure_signed(origin)?;
1804 <ContractBlob<T>>::remove(&origin, code_hash)?;
1805 Ok(Pays::No.into())
1807 }
1808
1809 #[pallet::call_index(6)]
1820 #[pallet::weight(<T as Config>::WeightInfo::set_code())]
1821 pub fn set_code(
1822 origin: OriginFor<T>,
1823 dest: H160,
1824 code_hash: sp_core::H256,
1825 ) -> DispatchResult {
1826 ensure_root(origin)?;
1827 <AccountInfoOf<T>>::try_mutate(&dest, |account| {
1828 let Some(account) = account else {
1829 return Err(<Error<T>>::ContractNotFound.into());
1830 };
1831
1832 let AccountType::Contract(ref mut contract) = account.account_type else {
1833 return Err(<Error<T>>::ContractNotFound.into());
1834 };
1835
1836 <CodeInfo<T>>::increment_refcount(code_hash)?;
1837 let _ = <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
1838 contract.code_hash = code_hash;
1839
1840 Ok(())
1841 })
1842 }
1843
1844 #[pallet::call_index(7)]
1852 #[pallet::weight(<T as Config>::WeightInfo::map_account())]
1853 pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
1854 #[cfg(not(feature = "runtime-benchmarks"))]
1855 if T::AutoMap::get() {
1856 return Ok(());
1857 }
1858
1859 Self::ensure_non_contract_if_signed(&origin)?;
1860 let origin = ensure_signed(origin)?;
1861 T::AddressMapper::map(&origin)
1862 }
1863
1864 #[pallet::call_index(13)]
1866 #[pallet::weight(<T as Config>::WeightInfo::batch_map_accounts(accounts.len().saturated_into::<u32>()))]
1867 pub fn batch_map_accounts(
1868 origin: OriginFor<T>,
1869 accounts: Vec<T::AccountId>,
1870 ) -> DispatchResultWithPostInfo {
1871 ensure_signed(origin.clone())?;
1872 Self::ensure_non_contract_if_signed(&origin)?;
1873
1874 let total: u32 = accounts.len().saturated_into();
1875 let mut mapped = 0;
1876
1877 for account_id in accounts
1878 .iter()
1879 .filter(|&a| !T::AddressMapper::is_eth_derived(a))
1881 .filter(|&a| frame_system::Pallet::<T>::account_exists(a))
1884 {
1885 let mut useful = false;
1886
1887 match T::AddressMapper::map_no_deposit_unchecked(account_id) {
1888 Ok(()) => {
1889 useful = true;
1890 },
1891 Err(err) => log::debug!(
1892 target: LOG_TARGET,
1893 "Failed to map account {account_id:?}: {err:?}",
1894 ),
1895 }
1896
1897 match T::Currency::release_all(
1898 &HoldReason::AddressMapping.into(),
1899 account_id,
1900 Precision::BestEffort,
1901 ) {
1902 Ok(released) if !released.is_zero() => {
1905 useful = true;
1906 },
1907 Ok(_) => {},
1908 Err(err) => log::debug!(
1909 target: LOG_TARGET,
1910 "Failed to release mapping deposit for {account_id:?}: {err:?}",
1911 ),
1912 }
1913
1914 if useful {
1915 mapped = mapped.saturating_add(1);
1916 }
1917 }
1918
1919 if total == 0 || mapped == 0 {
1921 return Ok(Pays::Yes.into());
1922 }
1923
1924 let proportion_mapped = Perbill::from_rational(mapped, total);
1925 if proportion_mapped >= Perbill::from_percent(90) {
1926 Ok(Pays::No.into())
1927 } else {
1928 Ok(Pays::Yes.into())
1929 }
1930 }
1931
1932 #[pallet::call_index(8)]
1940 #[pallet::weight(<T as Config>::WeightInfo::unmap_account())]
1941 pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
1942 #[cfg(not(feature = "runtime-benchmarks"))]
1943 ensure!(!T::AutoMap::get(), <Error<T>>::AutoMappingEnabled);
1944 let origin = ensure_signed(origin)?;
1945 T::AddressMapper::unmap(&origin)
1946 }
1947
1948 #[pallet::call_index(9)]
1954 #[pallet::weight({
1955 let dispatch_info = call.get_dispatch_info();
1956 (
1957 <T as Config>::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
1958 dispatch_info.class
1959 )
1960 })]
1961 pub fn dispatch_as_fallback_account(
1962 mut origin: OriginFor<T>,
1963 call: Box<<T as Config>::RuntimeCall>,
1964 ) -> DispatchResultWithPostInfo {
1965 Self::ensure_non_contract_if_signed(&origin)?;
1966 let account_id = origin.as_signer().ok_or(DispatchError::BadOrigin)?;
1967 let unmapped_account = T::AddressMapper::to_fallback_account_id(
1968 &T::AddressMapper::to_address(&account_id),
1969 );
1970 origin.set_caller_from(RawOrigin::Signed(unmapped_account));
1971 call.dispatch(origin)
1972 }
1973 }
1974}
1975
1976fn dispatch_result<R>(
1978 result: Result<R, DispatchError>,
1979 weight_consumed: Weight,
1980 base_weight: Weight,
1981) -> DispatchResultWithPostInfo {
1982 let post_info = PostDispatchInfo {
1983 actual_weight: Some(weight_consumed.saturating_add(base_weight)),
1984 pays_fee: Default::default(),
1985 };
1986
1987 result
1988 .map(|_| post_info)
1989 .map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
1990}
1991
1992impl<T: Config> Pallet<T> {
1993 pub fn bare_call(
2000 origin: OriginFor<T>,
2001 dest: H160,
2002 evm_value: U256,
2003 transaction_limits: TransactionLimits<T>,
2004 data: Vec<u8>,
2005 exec_config: &ExecConfig<T>,
2006 ) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
2007 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
2008 Ok(transaction_meter) => transaction_meter,
2009 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
2010 };
2011 let mut storage_deposit = Default::default();
2012
2013 let try_call = || {
2014 let origin = ExecOrigin::from_runtime_origin(origin)?;
2015 let result = ExecStack::<T, ContractBlob<T>>::run_call(
2016 origin.clone(),
2017 dest,
2018 &mut transaction_meter,
2019 evm_value,
2020 data,
2021 &exec_config,
2022 )?;
2023
2024 storage_deposit = transaction_meter
2025 .execute_postponed_deposits(&origin, &exec_config)
2026 .inspect_err(|err| {
2027 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
2028 })?;
2029
2030 Ok(result)
2031 };
2032 let result = Self::run_guarded(try_call);
2033
2034 log::trace!(target: LOG_TARGET, "Bare call ends: \
2035 result={result:?}, \
2036 weight_consumed={:?}, \
2037 weight_required={:?}, \
2038 storage_deposit={:?}, \
2039 gas_consumed={:?}, \
2040 max_storage_deposit={:?}",
2041 transaction_meter.weight_consumed(),
2042 transaction_meter.weight_required(),
2043 storage_deposit,
2044 transaction_meter.total_consumed_gas(),
2045 transaction_meter.deposit_required()
2046 );
2047
2048 ContractResult {
2049 result: result.map_err(|r| r.error),
2050 weight_consumed: transaction_meter.weight_consumed(),
2051 weight_required: transaction_meter.weight_required(),
2052 storage_deposit,
2053 gas_consumed: transaction_meter.total_consumed_gas(),
2054 max_storage_deposit: transaction_meter.deposit_required(),
2055 }
2056 }
2057
2058 pub fn prepare_dry_run(account: &T::AccountId) {
2064 frame_system::Pallet::<T>::inc_account_nonce(account);
2067
2068 if !T::AddressMapper::is_mapped(account) {
2071 let _ = T::AddressMapper::map_no_deposit_unchecked(account);
2072 }
2073 }
2074
2075 pub fn bare_instantiate(
2081 origin: OriginFor<T>,
2082 evm_value: U256,
2083 transaction_limits: TransactionLimits<T>,
2084 code: Code,
2085 data: Vec<u8>,
2086 salt: Option<[u8; 32]>,
2087 exec_config: &ExecConfig<T>,
2088 ) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
2089 let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
2090 Ok(transaction_meter) => transaction_meter,
2091 Err(error) => return ContractResult { result: Err(error), ..Default::default() },
2092 };
2093
2094 let mut storage_deposit = Default::default();
2095
2096 let try_instantiate = || {
2097 let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
2098
2099 if_tracing(|t| t.instantiate_code(&code, salt.as_ref()));
2100 let executable = match code {
2101 Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => {
2102 let upload_account = T::UploadOrigin::ensure_origin(origin)?;
2103 let executable = Self::try_upload_code(
2104 upload_account,
2105 code,
2106 BytecodeType::Pvm,
2107 &mut transaction_meter,
2108 &exec_config,
2109 )?;
2110 executable
2111 },
2112 Code::Upload(code) => {
2113 if T::AllowEVMBytecode::get() {
2114 ensure!(data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
2115 let origin = T::UploadOrigin::ensure_origin(origin)?;
2116 let executable = ContractBlob::from_evm_init_code(code, origin)?;
2117 executable
2118 } else {
2119 return Err(<Error<T>>::CodeRejected.into());
2120 }
2121 },
2122 Code::Existing(code_hash) => {
2123 let executable = ContractBlob::from_storage(code_hash, &mut transaction_meter)?;
2124 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
2125 executable
2126 },
2127 };
2128 let instantiate_origin = ExecOrigin::from_account_id(instantiate_account.clone());
2129 let result = ExecStack::<T, ContractBlob<T>>::run_instantiate(
2130 instantiate_account,
2131 executable,
2132 &mut transaction_meter,
2133 evm_value,
2134 data,
2135 salt.as_ref(),
2136 &exec_config,
2137 );
2138
2139 storage_deposit = transaction_meter
2140 .execute_postponed_deposits(&instantiate_origin, &exec_config)
2141 .inspect_err(|err| {
2142 log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
2143 })?;
2144 result
2145 };
2146 let output = Self::run_guarded(try_instantiate);
2147
2148 log::trace!(target: LOG_TARGET, "Bare instantiate ends: weight_consumed={:?}\
2149 weight_required={:?} \
2150 storage_deposit={:?} \
2151 gas_consumed={:?} \
2152 max_storage_deposit={:?}",
2153 transaction_meter.weight_consumed(),
2154 transaction_meter.weight_required(),
2155 storage_deposit,
2156 transaction_meter.total_consumed_gas(),
2157 transaction_meter.deposit_required()
2158 );
2159
2160 ContractResult {
2161 result: output
2162 .map(|(addr, result)| InstantiateReturnValue { result, addr })
2163 .map_err(|e| e.error),
2164 weight_consumed: transaction_meter.weight_consumed(),
2165 weight_required: transaction_meter.weight_required(),
2166 storage_deposit,
2167 gas_consumed: transaction_meter.total_consumed_gas(),
2168 max_storage_deposit: transaction_meter.deposit_required(),
2169 }
2170 }
2171
2172 pub fn eth_estimate_gas(
2184 tx: GenericTransaction,
2185 timestamp_override: Option<MomentOf<T>>,
2186 state_overrides: Option<StateOverrideSet>,
2187 ) -> Result<U256, EthTransactError>
2188 where
2189 T::Nonce: Into<U256> + TryFrom<U256>,
2190 CallOf<T>: SetWeightLimit,
2191 {
2192 log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}");
2193
2194 let mut low = U256::zero();
2195 let mut high = Self::evm_block_gas_limit();
2196
2197 log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}");
2198
2199 let perform_balance_checks = if let Some(gas_limit) = tx.gas {
2203 high = gas_limit;
2204 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}");
2205 true
2206 } else {
2207 false
2208 };
2209
2210 let fee_cap = tx.max_fee_per_gas.or(tx.gas_price);
2212 if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) {
2213 let mut available_balance = Self::evm_balance(&from);
2214 if let Some(value) = tx.value {
2215 available_balance = available_balance.checked_sub(value).ok_or_else(|| {
2216 EthTransactError::Message("insufficient funds for value transfer".into())
2217 })?;
2218 }
2219 if let Some(allowance) = available_balance.checked_div(fee_cap) {
2220 if high > allowance && allowance != U256::zero() {
2221 log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}");
2222 high = allowance
2223 }
2224 }
2225 }
2226
2227 let dry_run_at = |gas: U256| {
2231 let mut transaction = tx.clone();
2232 transaction.gas = Some(gas);
2233 with_transaction(|| {
2234 TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
2235 transaction,
2236 timestamp_override,
2237 perform_balance_checks,
2238 state_overrides.clone(),
2239 )))
2240 })
2241 .expect("Rollback shouldn't error out")
2242 };
2243
2244 let is_simple_transfer = with_transaction(|| {
2247 let probe = state_overrides
2248 .clone()
2249 .map_or(Ok(()), state_overrides::apply_state_overrides::<T>)
2250 .map(|()| Self::is_simple_transfer(&tx));
2251 TransactionOutcome::Rollback(Ok::<_, DispatchError>(probe))
2252 })
2253 .expect("Rollback shouldn't error out")?;
2254
2255 if is_simple_transfer {
2256 let dry_run_result = dry_run_at(high)?;
2257 log::trace!(
2258 target: LOG_TARGET,
2259 "eth_estimate_gas short-circuited simple transfer to {:?} with eth_gas={}",
2260 tx.to,
2261 dry_run_result.eth_gas,
2262 );
2263 return Ok(dry_run_result.eth_gas);
2264 }
2265
2266 let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()]
2271 .map(|gas_limit| (gas_limit, dry_run_at(gas_limit)));
2272 let (gas_limit, first_dry_run_result) = match dry_run_results {
2273 [(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => {
2274 if dry_run_result2.eth_gas >= gas_limit2 {
2275 (gas_limit1, dry_run_result1)
2276 } else {
2277 (gas_limit2, dry_run_result2)
2278 }
2279 },
2280 [(gas_limit, Ok(dry_run_result)), (_, Err(_))] |
2281 [(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result),
2282 [(_, Err(err)), (_, Err(..))] => return Err(err),
2283 };
2284 log::trace!(
2285 target: LOG_TARGET,
2286 "eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}",
2287 gas_limit,
2288 first_dry_run_result.eth_gas
2289 );
2290 low = first_dry_run_result.eth_gas;
2291 high = gas_limit;
2292
2293 while low + U256::one() < high {
2298 log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}");
2299 let error_ratio = high
2300 .checked_sub(low)
2301 .and_then(|value| value.checked_mul(U256::from(1000)))
2302 .and_then(|value| value.checked_div(high))
2303 .ok_or_else(|| {
2304 EthTransactError::Message(
2305 "failed to calculate error ratio in gas estimation".into(),
2306 )
2307 })?;
2308 if error_ratio <= U256::from(15) {
2309 log::trace!(
2310 target: LOG_TARGET,
2311 "eth_estimate_gas finished due to error ratio being less than 1.5% high={}",
2312 high
2313 );
2314 break;
2315 }
2316
2317 let mut midpoint = high
2318 .checked_sub(low)
2319 .and_then(|value| value.checked_div(U256::from(2)))
2320 .and_then(|value| value.checked_add(low))
2321 .ok_or_else(|| {
2322 EthTransactError::Message(
2323 "failed to calculate midpoint in gas estimation".into(),
2324 )
2325 })?;
2326
2327 if let Some(other_midpoint) = low.checked_mul(U256::from(2)) {
2328 if other_midpoint != U256::zero() {
2329 midpoint = midpoint.min(other_midpoint)
2330 }
2331 };
2332
2333 let dry_run_result = dry_run_at(midpoint);
2334 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}");
2335 match dry_run_result {
2336 Ok(..) => {
2337 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}");
2338 high = midpoint
2339 },
2340 Err(..) => {
2341 log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}");
2342 low = midpoint
2343 },
2344 }
2345 }
2346
2347 log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}");
2348 Ok(high)
2349 }
2350
2351 pub(crate) fn is_simple_transfer(tx: &GenericTransaction) -> bool {
2353 tx.to
2354 .map(|to| tx.has_simple_transfer_fields() && Self::address_runs_no_code(&to))
2355 .unwrap_or(false)
2356 }
2357
2358 fn address_runs_no_code(address: &H160) -> bool {
2362 *address != RUNTIME_PALLETS_ADDR &&
2363 !exec::is_precompile::<T, ContractBlob<T>>(address) &&
2364 !<AccountInfo<T>>::is_contract(address) &&
2365 !<AccountInfo<T>>::is_delegated(address)
2366 }
2367
2368 pub fn eth_pre_dispatch_weight(transaction_encoded: Vec<u8>) -> Result<Weight, EthTransactError>
2376 where
2377 CallOf<T>: SetWeightLimit,
2378 {
2379 let signed_tx =
2380 crate::evm::TransactionSigned::decode(&transaction_encoded).map_err(|err| {
2381 EthTransactError::Message(format!("Failed to decode transaction: {err:?}"))
2382 })?;
2383 let signer_addr = signed_tx.recover_eth_address().map_err(|err| {
2384 EthTransactError::Message(format!("Failed to recover signer: {err:?}"))
2385 })?;
2386 let tx =
2387 GenericTransaction::from_signed(signed_tx, Self::evm_base_fee(), Some(signer_addr));
2388 let encoded_len = T::FeeInfo::encoded_len(
2389 crate::Call::<T>::eth_transact { payload: transaction_encoded.clone() }.into(),
2390 );
2391 let call_info = tx
2392 .into_call::<T>(CreateCallMode::ExtrinsicExecution(encoded_len, transaction_encoded))
2393 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2394 let info = T::FeeInfo::dispatch_info(&call_info.call);
2395
2396 Ok(frame_system::calculate_consumed_extrinsic_weight::<CallOf<T>>(
2397 &T::BlockWeights::get(),
2398 &info,
2399 call_info.encoded_len as usize,
2400 ))
2401 }
2402
2403 pub fn dry_run_eth_transact(
2415 mut tx: GenericTransaction,
2416 timestamp_override: Option<MomentOf<T>>,
2417 perform_balance_checks: bool,
2418 state_overrides: Option<StateOverrideSet>,
2419 ) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
2420 where
2421 T::Nonce: Into<U256> + TryFrom<U256>,
2422 CallOf<T>: SetWeightLimit,
2423 {
2424 log::debug!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?}");
2425
2426 if !tx.authorization_list.is_empty() && tx.from.is_none() {
2430 return Err(EthTransactError::Message(
2431 "a transaction with an authorization list requires a `from` address: \
2432 the authorization deposits are charged to it"
2433 .into(),
2434 ));
2435 }
2436
2437 let origin = T::AddressMapper::to_account_id(&tx.from.unwrap_or_default());
2438 Self::prepare_dry_run(&origin);
2439
2440 if let Some(overrides) = state_overrides {
2441 state_overrides::apply_state_overrides::<T>(overrides)?;
2442 }
2443
2444 let base_fee = Self::evm_base_fee();
2445 let effective_gas_price = tx.effective_gas_price(base_fee).unwrap_or(base_fee);
2446
2447 if effective_gas_price < base_fee {
2448 Err(EthTransactError::Message(format!(
2449 "Effective gas price {effective_gas_price:?} lower than base fee {base_fee:?}"
2450 )))?;
2451 }
2452
2453 if tx.nonce.is_none() {
2454 tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
2455 }
2456 if tx.chain_id.is_none() {
2457 tx.chain_id = Some(T::ChainId::get().into());
2458 }
2459
2460 tx.gas_price = Some(effective_gas_price);
2462 tx.max_priority_fee_per_gas = Some(0.into());
2465 if tx.max_fee_per_gas.is_none() {
2466 tx.max_fee_per_gas = Some(effective_gas_price);
2467 }
2468
2469 let gas = tx.gas;
2470 if tx.gas.is_none() {
2471 tx.gas = Some(Self::evm_block_gas_limit());
2472 }
2473 if tx.r#type.is_none() {
2474 tx.r#type = Some(
2475 if tx.authorization_list.is_empty() { TYPE_EIP1559 } else { TYPE_EIP7702 }.into(),
2476 );
2477 }
2478
2479 let authorization_list = tx.authorization_list.clone();
2481 let value = tx.value.unwrap_or_default();
2482 let input = tx.input.clone().to_vec();
2483 let from = tx.from;
2484 let to = tx.to;
2485
2486 let mut call_info = tx
2489 .into_call::<T>(CreateCallMode::DryRun)
2490 .map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2491
2492 let base_info = T::FeeInfo::base_dispatch_info(&mut call_info.call);
2496 let mut base_weight = base_info.total_weight();
2497
2498 let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
2500 if let Some(from) = &from {
2501 let fees = if gas.is_some() && perform_balance_checks { fees } else { Zero::zero() };
2502 let balance = Self::evm_balance(from);
2503 if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
2504 return Err(EthTransactError::Message(format!(
2505 "insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
2506 )));
2507 }
2508 }
2509
2510 T::FeeInfo::deposit_txfee(T::Currency::issue(fees));
2513
2514 let extract_error = |err| {
2515 if err == Error::<T>::StorageDepositNotEnoughFunds.into() {
2516 Err(EthTransactError::Message(format!("Not enough gas supplied: {err:?}")))
2517 } else {
2518 Err(EthTransactError::Message(format!("failed to run contract: {err:?}")))
2519 }
2520 };
2521
2522 let exec_config =
2523 ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight);
2524 let auth_result =
2525 evm::eip7702::process_authorizations::<T>(&authorization_list, &origin, &exec_config);
2526 base_weight = base_weight.saturating_sub(auth_result.weight_refund);
2527 let actual_auth_deposit = auth_result.deposit;
2528 let worst_case_auth_deposit = Self::worst_case_delegation_deposit()
2529 .saturating_mul(authorization_list.len().saturated_into());
2530
2531 let exec_config =
2532 ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight)
2533 .with_dry_run(timestamp_override);
2534
2535 let transaction_limits = TransactionLimits::EthereumGas {
2536 eth_gas_limit: call_info.eth_gas_limit.saturated_into(),
2537 weight_limit: Self::evm_max_extrinsic_weight(),
2538 eth_tx_info: EthTxInfo::new(call_info.encoded_len, base_weight),
2539 authorization_deposit: actual_auth_deposit,
2540 };
2541
2542 let mut dry_run = match to {
2544 Some(dest) => {
2546 if dest == RUNTIME_PALLETS_ADDR {
2547 let Ok(dispatch_call) = <CallOf<T>>::decode(&mut &input[..]) else {
2548 return Err(EthTransactError::Message(format!(
2549 "Failed to decode pallet-call {input:?}"
2550 )));
2551 };
2552
2553 if let Err(result) =
2554 dispatch_call.clone().dispatch(RawOrigin::Signed(origin).into())
2555 {
2556 return Err(EthTransactError::Message(format!(
2557 "Failed to dispatch call: {:?}",
2558 result.error,
2559 )));
2560 };
2561
2562 Default::default()
2563 } else {
2564 let result = crate::Pallet::<T>::bare_call(
2566 OriginFor::<T>::signed(origin),
2567 dest,
2568 value,
2569 transaction_limits,
2570 input.clone(),
2571 &exec_config,
2572 );
2573
2574 let data = match result.result {
2575 Ok(return_value) => {
2576 if return_value.did_revert() {
2577 return Err(EthTransactError::Data(return_value.data));
2578 }
2579 return_value.data
2580 },
2581 Err(err) => {
2582 log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
2583 return extract_error(err);
2584 },
2585 };
2586
2587 EthTransactInfo {
2588 weight_required: result.weight_required,
2589 storage_deposit: result.storage_deposit.charge_or_zero(),
2590 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2591 data,
2592 eth_gas: Default::default(),
2593 }
2594 }
2595 },
2596 None => {
2598 let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2600 extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default()))
2601 } else {
2602 (input, vec![])
2603 };
2604
2605 let result = crate::Pallet::<T>::bare_instantiate(
2607 OriginFor::<T>::signed(origin),
2608 value,
2609 transaction_limits,
2610 Code::Upload(code.clone()),
2611 data.clone(),
2612 None,
2613 &exec_config,
2614 );
2615
2616 let returned_data = match result.result {
2617 Ok(return_value) => {
2618 if return_value.result.did_revert() {
2619 return Err(EthTransactError::Data(return_value.result.data));
2620 }
2621 return_value.result.data
2622 },
2623 Err(err) => {
2624 log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
2625 return extract_error(err);
2626 },
2627 };
2628
2629 EthTransactInfo {
2630 weight_required: result.weight_required,
2631 storage_deposit: result.storage_deposit.charge_or_zero(),
2632 max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2633 data: returned_data,
2634 eth_gas: Default::default(),
2635 }
2636 },
2637 };
2638
2639 dry_run.max_storage_deposit = dry_run.max_storage_deposit.max(worst_case_auth_deposit);
2643
2644 call_info.call.set_weight_limit(dry_run.weight_required);
2646
2647 let total_weight = T::FeeInfo::dispatch_info(&call_info.call).total_weight();
2649 let max_weight = Self::evm_max_extrinsic_weight();
2650 if total_weight.any_gt(max_weight) {
2651 log::debug!(target: LOG_TARGET, "Transaction weight estimate exceeds extrinsic maximum: \
2652 total_weight={total_weight:?} \
2653 max_weight={max_weight:?}",
2654 );
2655
2656 Err(EthTransactError::Message(format!(
2657 "\
2658 The transaction consumes more than the allowed weight. \
2659 needed={total_weight} \
2660 allowed={max_weight} \
2661 overweight_by={}\
2662 ",
2663 total_weight.saturating_sub(max_weight),
2664 )))?;
2665 }
2666
2667 let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
2669 let available_fee = T::FeeInfo::remaining_txfee();
2670 if transaction_fee > available_fee {
2671 Err(EthTransactError::Message(format!(
2672 "Not enough gas supplied: Off by: {:?}",
2673 transaction_fee.saturating_sub(available_fee),
2674 )))?;
2675 }
2676
2677 let total_cost = transaction_fee.saturating_add(dry_run.max_storage_deposit);
2678 let total_cost_wei = Pallet::<T>::convert_native_to_evm(total_cost);
2679 let (mut eth_gas, rest) = total_cost_wei.div_mod(base_fee);
2680 if !rest.is_zero() {
2681 eth_gas = eth_gas.saturating_add(1_u32.into());
2682 }
2683
2684 log::debug!(target: LOG_TARGET, "\
2685 dry_run_eth_transact finished: \
2686 weight_limit={}, \
2687 total_weight={total_weight}, \
2688 max_weight={max_weight}, \
2689 weight_left={}, \
2690 eth_gas={eth_gas}, \
2691 encoded_len={}, \
2692 tx_fee={transaction_fee:?}, \
2693 storage_deposit={:?}, \
2694 max_storage_deposit={:?}\
2695 ",
2696 dry_run.weight_required,
2697 max_weight.saturating_sub(total_weight),
2698 call_info.encoded_len,
2699 dry_run.storage_deposit,
2700 dry_run.max_storage_deposit,
2701
2702 );
2703 dry_run.eth_gas = eth_gas;
2704 Ok(dry_run)
2705 }
2706
2707 pub fn evm_balance(address: &H160) -> U256 {
2711 let balance = AccountInfo::<T>::balance_of((*address).into());
2712 Self::convert_native_to_evm(balance)
2713 }
2714
2715 pub fn eth_block() -> EthBlock {
2717 EthereumBlock::<T>::get()
2718 }
2719
2720 pub fn eth_block_hash_from_number(number: U256) -> Option<H256> {
2727 let number = BlockNumberFor::<T>::try_from(number).ok()?;
2728 let hash = <BlockHash<T>>::get(number);
2729 if hash == H256::zero() { None } else { Some(hash) }
2730 }
2731
2732 pub fn eth_receipt_data() -> Vec<ReceiptGasInfo> {
2734 ReceiptInfoData::<T>::get()
2735 }
2736
2737 pub fn set_evm_balance(address: &H160, evm_value: U256) -> Result<(), Error<T>> {
2743 let (balance, dust) = Self::new_balance_with_dust(evm_value)
2744 .map_err(|_| <Error<T>>::BalanceConversionFailed)?;
2745 let account_id = T::AddressMapper::to_account_id(&address);
2746 T::Currency::set_balance(&account_id, balance);
2747 AccountInfoOf::<T>::mutate(&address, |account| {
2748 if let Some(account) = account {
2749 account.dust = dust;
2750 } else {
2751 *account = Some(AccountInfo { dust, ..Default::default() });
2752 }
2753 });
2754
2755 Ok(())
2756 }
2757
2758 pub fn new_balance_with_dust(
2762 evm_value: U256,
2763 ) -> Result<(BalanceOf<T>, u32), BalanceConversionError> {
2764 let ed = T::Currency::minimum_balance();
2765 let balance_with_dust = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(evm_value)?;
2766 let (value, dust) = balance_with_dust.deconstruct();
2767
2768 Ok((ed.saturating_add(value), dust))
2769 }
2770
2771 pub fn evm_nonce(address: &H160) -> u32
2773 where
2774 T::Nonce: Into<u32>,
2775 {
2776 let account = T::AddressMapper::to_account_id(&address);
2777 System::<T>::account_nonce(account).into()
2778 }
2779
2780 pub fn evm_block_gas_limit() -> U256 {
2782 u64::MAX.into()
2789 }
2790
2791 pub fn evm_max_extrinsic_weight_in_gas() -> U256 {
2793 let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight());
2794 let gas_scale: BalanceOf<T> = T::GasScale::get().into();
2795 (max_extrinsic_fee / gas_scale).into()
2796 }
2797
2798 pub fn evm_max_extrinsic_weight() -> Weight {
2800 let factor = <T as Config>::MaxEthExtrinsicWeight::get();
2801 let max_weight = <T as frame_system::Config>::BlockWeights::get()
2802 .get(DispatchClass::Normal)
2803 .max_extrinsic
2804 .unwrap_or_else(|| <T as frame_system::Config>::BlockWeights::get().max_block);
2805 Weight::from_parts(
2806 factor.saturating_mul_int(max_weight.ref_time()),
2807 factor.saturating_mul_int(max_weight.proof_size()),
2808 )
2809 }
2810
2811 pub fn evm_base_fee() -> U256 {
2813 let gas_scale = <T as Config>::GasScale::get();
2814 let multiplier = T::FeeInfo::next_fee_multiplier();
2815 multiplier
2816 .saturating_mul_int::<u128>(T::NativeToEthRatio::get().into())
2817 .saturating_mul(gas_scale.saturated_into())
2818 .into()
2819 }
2820
2821 pub fn evm_tracer(tracer_type: TracerType) -> Tracer<T>
2823 where
2824 T::Nonce: Into<u32>,
2825 {
2826 match tracer_type {
2827 TracerType::CallTracer(config) => CallTracer::new(config.unwrap_or_default()).into(),
2828 TracerType::PrestateTracer(config) => {
2829 PrestateTracer::new(config.unwrap_or_default()).into()
2830 },
2831 TracerType::ExecutionTracer(config) => {
2832 ExecutionTracer::new(config.unwrap_or_default()).into()
2833 },
2834 }
2835 }
2836
2837 pub fn bare_upload_code(
2841 origin: OriginFor<T>,
2842 code: Vec<u8>,
2843 storage_deposit_limit: BalanceOf<T>,
2844 ) -> CodeUploadResult<BalanceOf<T>> {
2845 let origin = T::UploadOrigin::ensure_origin(origin)?;
2846
2847 let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2848 BytecodeType::Pvm
2849 } else {
2850 if !T::AllowEVMBytecode::get() {
2851 return Err(<Error<T>>::CodeRejected.into());
2852 }
2853 BytecodeType::Evm
2854 };
2855
2856 let mut meter = TransactionMeter::new(TransactionLimits::WeightAndDeposit {
2857 weight_limit: Default::default(),
2858 deposit_limit: storage_deposit_limit,
2859 })?;
2860
2861 let module = Self::try_upload_code(
2862 origin,
2863 code,
2864 bytecode_type,
2865 &mut meter,
2866 &ExecConfig::new_substrate_tx(),
2867 )?;
2868 Ok(CodeUploadReturnValue {
2869 code_hash: *module.code_hash(),
2870 deposit: meter.deposit_consumed().charge_or_zero(),
2871 })
2872 }
2873
2874 pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
2876 let contract_info =
2877 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2878
2879 let maybe_value = contract_info.read(&Key::from_fixed(key));
2880 Ok(maybe_value)
2881 }
2882
2883 pub fn get_immutables(address: H160) -> Option<ImmutableData> {
2887 let immutable_data = <ImmutableDataOf<T>>::get(address);
2888 immutable_data
2889 }
2890
2891 pub fn set_immutables(address: H160, data: ImmutableData) -> Result<(), ContractAccessError> {
2900 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2901 <ImmutableDataOf<T>>::insert(address, data);
2902 Ok(())
2903 }
2904
2905 pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
2907 let contract_info =
2908 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2909
2910 let maybe_value = contract_info.read(
2911 &Key::try_from_var(key)
2912 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2913 .into(),
2914 );
2915 Ok(maybe_value)
2916 }
2917
2918 pub fn convert_native_to_evm(value: impl Into<BalanceWithDust<BalanceOf<T>>>) -> U256 {
2920 let (value, dust) = value.into().deconstruct();
2921 value
2922 .into()
2923 .saturating_mul(T::NativeToEthRatio::get().into())
2924 .saturating_add(dust.into())
2925 }
2926
2927 pub fn set_storage(address: H160, key: [u8; 32], value: Option<Vec<u8>>) -> SetStorageResult {
2937 let contract_info =
2938 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2939
2940 contract_info
2941 .write(&Key::from_fixed(key), value, None, false)
2942 .map_err(ContractAccessError::StorageWriteFailed)
2943 }
2944
2945 pub fn set_storage_var_key(
2956 address: H160,
2957 key: Vec<u8>,
2958 value: Option<Vec<u8>>,
2959 ) -> SetStorageResult {
2960 let contract_info =
2961 AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2962
2963 contract_info
2964 .write(
2965 &Key::try_from_var(key)
2966 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
2967 .into(),
2968 value,
2969 None,
2970 false,
2971 )
2972 .map_err(ContractAccessError::StorageWriteFailed)
2973 }
2974
2975 pub fn account_id() -> T::AccountId {
2977 use frame_support::PalletId;
2978 use sp_runtime::traits::AccountIdConversion;
2979 PalletId(*b"py/reviv").into_account_truncating()
2980 }
2981
2982 pub fn block_author() -> H160 {
2984 use frame_support::traits::FindAuthor;
2985
2986 let digest = <frame_system::Pallet<T>>::digest();
2987 let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
2988
2989 T::FindAuthor::find_author(pre_runtime_digests)
2990 .map(|account_id| T::AddressMapper::to_address(&account_id))
2991 .unwrap_or_default()
2992 }
2993
2994 pub fn code(address: &H160) -> Vec<u8> {
2999 use precompiles::{All, Precompiles};
3000 if let Some(code) = <All<T>>::code(address.as_fixed_bytes()) {
3001 return code.into();
3002 }
3003
3004 let Some(info) = <AccountInfoOf<T>>::get(address) else { return Vec::new() };
3005
3006 match info.account_type {
3007 AccountType::Contract(contract) => <PristineCode<T>>::get(contract.code_hash)
3008 .map(|code| code.into())
3009 .unwrap_or_default(),
3010 AccountType::DelegatedEOA { delegate_target: Some(target), .. } => {
3011 AccountInfo::<T>::delegation_indicator(&target).to_vec()
3012 },
3013 AccountType::EOA | AccountType::DelegatedEOA { .. } => Vec::new(),
3014 }
3015 }
3016
3017 pub fn try_upload_code(
3019 origin: T::AccountId,
3020 code: Vec<u8>,
3021 code_type: BytecodeType,
3022 meter: &mut TransactionMeter<T>,
3023 exec_config: &ExecConfig<T>,
3024 ) -> Result<ContractBlob<T>, DispatchError> {
3025 let mut module = match code_type {
3026 BytecodeType::Pvm => ContractBlob::from_pvm_code(code, origin)?,
3027 BytecodeType::Evm => ContractBlob::from_evm_runtime_code(code, origin)?,
3028 };
3029 module.store_code(exec_config, meter)?;
3030 Ok(module)
3031 }
3032
3033 fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
3035 executing_contract::using_once(&mut false, || {
3036 executing_contract::with(|f| {
3037 if *f {
3039 return Err(())
3040 }
3041 *f = true;
3043 Ok(())
3044 })
3045 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
3046 .map_err(|_| <Error<T>>::ReenteredPallet.into())
3047 .map(|_| f())
3048 .and_then(|r| r)
3049 })
3050 }
3051
3052 fn charge_deposit(
3057 hold_reason: HoldReason,
3058 from: &T::AccountId,
3059 to: &T::AccountId,
3060 amount: BalanceOf<T>,
3061 exec_config: &ExecConfig<T>,
3062 ) -> DispatchResult {
3063 if amount.is_zero() {
3064 return Ok(());
3065 }
3066
3067 T::Deposit::charge_and_hold(hold_reason, exec_config.funds(from), to, amount)
3068 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
3069 Ok(())
3070 }
3071
3072 pub(crate) fn refund_deposit(
3077 hold_reason: HoldReason,
3078 from: &T::AccountId,
3079 dst: deposit_payment::Funds<T::AccountId>,
3080 amount: BalanceOf<T>,
3081 ) -> Result<(), DispatchError> {
3082 if amount.is_zero() {
3083 return Ok(());
3084 }
3085
3086 let to = match &dst {
3087 deposit_payment::Funds::Balance(to) | deposit_payment::Funds::TxFee(to) => *to,
3088 };
3089 let result = T::Deposit::refund_on_hold(hold_reason, from, dst, amount);
3090
3091 result.defensive_map_err(|err| {
3092 let available = T::Deposit::total_on_hold(hold_reason, from);
3093 if available < amount {
3094 log::error!(
3097 target: LOG_TARGET,
3098 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}. Not enough deposit: {available:?}. This is a bug.",
3099 );
3100 Error::<T>::StorageRefundNotEnoughFunds.into()
3101 } else {
3102 log::warn!(
3107 target: LOG_TARGET,
3108 "Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}: {err:?}. First remove locks (staking, governance) from the contracts account.",
3109 );
3110 Error::<T>::StorageRefundLocked.into()
3111 }
3112 })
3113 }
3114
3115 fn has_dust(value: U256) -> bool {
3117 value % U256::from(<T>::NativeToEthRatio::get()) != U256::zero()
3118 }
3119
3120 fn has_balance(value: U256) -> bool {
3122 value >= U256::from(<T>::NativeToEthRatio::get())
3123 }
3124
3125 #[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))]
3127 fn min_balance() -> BalanceOf<T> {
3128 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
3129 }
3130
3131 pub(crate) fn worst_case_delegation_deposit() -> BalanceOf<T> {
3135 let ed = <T as Config>::Currency::minimum_balance();
3136 let contract_deposit = T::DepositPerByte::get()
3137 .saturating_mul((<ContractInfo<T>>::max_encoded_len() as u32).into())
3138 .saturating_add(T::DepositPerItem::get());
3139 let max_code_deposit = vm::calculate_code_deposit::<T>(limits::code::BLOB_BYTES);
3140 let code_lockup = T::CodeHashLockupDepositPercent::get().mul_ceil(max_code_deposit);
3141 ed.saturating_add(contract_deposit).saturating_add(code_lockup)
3142 }
3143
3144 fn deposit_event(event: Event<T>) {
3149 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
3150 }
3151
3152 fn ensure_eth_signed(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
3154 match <T as Config>::RuntimeOrigin::from(origin).into() {
3155 Ok(Origin::EthTransaction(signer)) => Ok(signer),
3156 _ => Err(BadOrigin.into()),
3157 }
3158 }
3159
3160 fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
3164 if DebugSettings::bypass_eip_3607::<T>() {
3165 return Ok(());
3166 }
3167 let Some(address) = origin
3168 .as_system_ref()
3169 .and_then(|o| o.as_signed())
3170 .map(<T::AddressMapper as AddressMapper<T>>::to_address)
3171 else {
3172 return Ok(());
3173 };
3174 if exec::is_precompile::<T, ContractBlob<T>>(&address) ||
3175 <AccountInfo<T>>::is_contract(&address)
3176 {
3177 log::debug!(
3178 target: crate::LOG_TARGET,
3179 "EIP-3607: reject tx as pre-compile or account exist at {address:?}",
3180 );
3181 Err(DispatchError::BadOrigin)
3182 } else {
3183 Ok(())
3184 }
3185 }
3186}
3187
3188pub const RUNTIME_PALLETS_ADDR: H160 =
3193 H160(hex_literal::hex!("6d6f646c70792f70616464720000000000000000"));
3194
3195environmental!(executing_contract: bool);
3197
3198sp_api::decl_runtime_apis! {
3199 #[api_version(2)]
3201 pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber, Moment> where
3202 AccountId: Codec,
3203 Balance: Codec,
3204 Nonce: Codec,
3205 BlockNumber: Codec,
3206 Moment: Codec,
3207 {
3208 #[deprecated(note = "Use the versioned equivalent `eth_block_versioned` if available on your runtime")]
3212 fn eth_block() -> BlockV1;
3213
3214 #[deprecated(note = "Use the versioned equivalent `eth_block_hash_versioned` if available on your runtime")]
3216 fn eth_block_hash(number: U256) -> Option<H256>;
3217
3218 #[deprecated(note = "Use the versioned equivalent `eth_receipt_data_versioned` if available on your runtime")]
3227 fn eth_receipt_data() -> Vec<ReceiptGasInfoV1>;
3228
3229 #[deprecated(note = "Use the versioned equivalent `block_gas_limit_versioned` if available on your runtime")]
3231 fn block_gas_limit() -> U256;
3232
3233 #[deprecated(note = "Use the versioned equivalent `max_extrinsic_weight_in_gas_versioned` if available on your runtime")]
3235 fn max_extrinsic_weight_in_gas() -> U256;
3236
3237 #[deprecated(note = "Use the versioned equivalent `balance_versioned` if available on your runtime")]
3239 fn balance(address: H160) -> U256;
3240
3241 #[deprecated(note = "Use the versioned equivalent `gas_price_versioned` if available on your runtime")]
3243 fn gas_price() -> U256;
3244
3245 #[deprecated(note = "Use the versioned equivalent `nonce_versioned` if available on your runtime")]
3247 fn nonce(address: H160) -> Nonce;
3248
3249 #[deprecated(note = "Use the versioned equivalent `call_versioned` if available on your runtime")]
3253 fn call(
3254 origin: AccountId,
3255 dest: H160,
3256 value: Balance,
3257 gas_limit: Option<Weight>,
3258 storage_deposit_limit: Option<Balance>,
3259 input_data: Vec<u8>,
3260 ) -> ContractResultV1<ExecReturnValueV1, Balance>;
3261
3262 #[deprecated(note = "Use the versioned equivalent `instantiate_versioned` if available on your runtime")]
3266 fn instantiate(
3267 origin: AccountId,
3268 value: Balance,
3269 gas_limit: Option<Weight>,
3270 storage_deposit_limit: Option<Balance>,
3271 code: CodeV1,
3272 data: Vec<u8>,
3273 salt: Option<[u8; 32]>,
3274 ) -> ContractResultV1<InstantiateReturnValueV1, Balance>;
3275
3276
3277 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3281 fn eth_transact(tx: GenericTransactionV1) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3282
3283 #[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3287 fn eth_transact_with_config(
3288 tx: GenericTransactionV1,
3289 config: DryRunConfigV1<Moment>,
3290 ) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3291
3292 #[deprecated(note = "Use the versioned equivalent `eth_estimate_gas_versioned` if available on your runtime")]
3298 fn eth_estimate_gas(
3299 tx: GenericTransactionV1,
3300 config: DryRunConfigV1<Moment>
3301 ) -> Result<U256, EthTransactError>;
3302
3303 #[deprecated(note = "Use the versioned equivalent `eth_pre_dispatch_weight_versioned` if available on your runtime")]
3305 fn eth_pre_dispatch_weight(tx: Vec<u8>) -> Result<Weight, EthTransactError>;
3306
3307 #[deprecated(note = "Use the versioned equivalent `upload_code_versioned` if available on your runtime")]
3311 fn upload_code(
3312 origin: AccountId,
3313 code: Vec<u8>,
3314 storage_deposit_limit: Option<Balance>,
3315 ) -> Result<CodeUploadReturnValueV1<Balance>, DispatchError>;
3316
3317 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3323 fn get_storage(
3324 address: H160,
3325 key: [u8; 32],
3326 ) -> GetStorageResult;
3327
3328 #[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3334 fn get_storage_var_key(
3335 address: H160,
3336 key: Vec<u8>,
3337 ) -> GetStorageResult;
3338
3339 #[deprecated(note = "Use the versioned equivalent `trace_block_versioned` if available on your runtime")]
3346 fn trace_block(
3347 block: Block,
3348 config: TracerTypeV1
3349 ) -> Vec<(u32, TraceV1)>;
3350
3351 #[deprecated(note = "Use the versioned equivalent `trace_tx_versioned` if available on your runtime")]
3358 fn trace_tx(
3359 block: Block,
3360 tx_index: u32,
3361 config: TracerTypeV1
3362 ) -> Option<TraceV1>;
3363
3364 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3368 fn trace_call(tx: GenericTransactionV1, config: TracerTypeV1) -> Result<TraceV1, EthTransactError>;
3369
3370 #[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3375 fn trace_call_with_config(
3376 tx: GenericTransactionV1,
3377 tracer_type: TracerTypeV1,
3378 config: TracingConfigV1,
3379 ) -> Result<TraceV1, EthTransactError>;
3380
3381 #[deprecated(note = "Use the versioned equivalent `block_author_versioned` if available on your runtime")]
3383 fn block_author() -> H160;
3384
3385 #[deprecated(note = "Use the versioned equivalent `address_versioned` if available on your runtime")]
3387 fn address(account_id: AccountId) -> H160;
3388
3389 #[deprecated(note = "Use the versioned equivalent `account_id_versioned` if available on your runtime")]
3391 fn account_id(address: H160) -> AccountId;
3392
3393 #[deprecated(note = "Use the versioned equivalent `runtime_pallets_address_versioned` if available on your runtime")]
3395 fn runtime_pallets_address() -> H160;
3396
3397 #[deprecated(note = "Use the versioned equivalent `code_versioned` if available on your runtime")]
3399 fn code(address: H160) -> Vec<u8>;
3400
3401 #[deprecated(note = "Use the versioned equivalent `new_balance_with_dust_versioned` if available on your runtime")]
3403 fn new_balance_with_dust(balance: U256) -> Result<(Balance, u32), BalanceConversionError>;
3404
3405 #[api_version(2)]
3408 fn version_declarations() -> ReviveRuntimeApiVersionDeclarations;
3409
3410 #[api_version(2)]
3411 fn eth_block_versioned(input: BlockVersionedInputPayload) -> BlockVersionedOutputPayload;
3412
3413 #[api_version(2)]
3414 fn eth_block_hash_versioned(input: BlockHashVersionedInputPayload) -> BlockHashVersionedOutputPayload;
3415
3416 #[api_version(2)]
3417 fn eth_receipt_data_versioned(input: ReceiptDataVersionedInputPayload) -> ReceiptDataVersionedOutputPayload;
3418
3419 #[api_version(2)]
3420 fn block_gas_limit_versioned(
3421 input: BlockGasLimitVersionedInputPayload
3422 ) -> BlockGasLimitVersionedOutputPayload;
3423
3424 #[api_version(2)]
3425 fn max_extrinsic_weight_in_gas_versioned(
3426 input: MaxExtrinsicWeightInGasVersionedInputPayload
3427 ) -> MaxExtrinsicWeightInGasVersionedOutputPayload;
3428
3429 #[api_version(2)]
3430 fn balance_versioned(input: BalanceVersionedInputPayload) -> BalanceVersionedOutputPayload;
3431
3432 #[api_version(2)]
3433 fn gas_price_versioned(input: GasPriceVersionedInputPayload) -> GasPriceVersionedOutputPayload;
3434
3435 #[api_version(2)]
3436 fn nonce_versioned(input: NonceVersionedInputPayload) -> NonceVersionedOutputPayload<Nonce>;
3437
3438 #[api_version(2)]
3439 fn call_versioned(
3440 input: CallVersionedInputPayload<AccountId, Balance>
3441 ) -> CallVersionedOutputPayload<Balance>;
3442
3443 #[api_version(2)]
3444 fn instantiate_versioned(
3445 input: InstantiateVersionedInputPayload<AccountId, Balance>
3446 ) -> InstantiateVersionedOutputPayload<Balance>;
3447
3448 #[api_version(2)]
3449 fn eth_transact_versioned(
3450 input: TransactVersionedInputPayload<Moment>
3451 ) -> Result<TransactVersionedOutputPayload<Balance>, EthTransactError>;
3452
3453 #[api_version(2)]
3454 fn eth_estimate_gas_versioned(
3455 input: EstimateGasVersionedInputPayload<Moment>
3456 ) -> Result<EstimateGasVersionedOutputPayload, EthTransactError>;
3457
3458 #[api_version(2)]
3459 fn eth_pre_dispatch_weight_versioned(
3460 input: PreDispatchWeightVersionedInputPayload
3461 ) -> Result<PreDispatchWeightVersionedOutputPayload, EthTransactError>;
3462
3463 #[api_version(2)]
3464 fn upload_code_versioned(
3465 input: UploadCodeVersionedInputPayload<AccountId, Balance>
3466 ) -> Result<UploadCodeVersionedOutputPayload<Balance>, DispatchError>;
3467
3468 #[api_version(2)]
3469 fn get_storage_versioned(
3470 input: GetStorageVersionedInputPayload
3471 ) -> Result<GetStorageVersionedOutputPayload, ContractAccessError>;
3472
3473 #[api_version(2)]
3474 fn runtime_pallets_address_versioned(
3475 input: RuntimePalletsAddressVersionedInputPayload
3476 ) -> RuntimePalletsAddressVersionedOutputPayload;
3477
3478 #[api_version(2)]
3479 fn code_versioned(input: CodeVersionedInputPayload) -> CodeVersionedOutputPayload;
3480
3481 #[api_version(2)]
3482 fn account_id_versioned(input: AccountIdVersionedInputPayload) -> AccountIdVersionedOutputPayload<AccountId>;
3483
3484 #[api_version(2)]
3485 fn new_balance_with_dust_versioned(
3486 input: NewBalanceWithDustVersionedInputPayload
3487 ) -> Result<NewBalanceWithDustVersionedOutputPayload<Balance>, BalanceConversionError>;
3488
3489 #[api_version(2)]
3490 fn block_author_versioned(input: BlockAuthorVersionedInputPayload) -> BlockAuthorVersionedOutputPayload;
3491
3492 #[api_version(2)]
3493 fn address_versioned(input: AddressVersionedInputPayload<AccountId>) -> AddressVersionedOutputPayload;
3494
3495 #[api_version(2)]
3496 fn trace_block_versioned(input: TraceBlockVersionedInputPayload<Block>) -> TraceBlockVersionedOutputPayload;
3497
3498 #[api_version(2)]
3499 fn trace_tx_versioned(input: TraceTxVersionedInputPayload<Block>) -> TraceTxVersionedOutputPayload;
3500
3501 #[api_version(2)]
3502 fn trace_call_versioned(
3503 input: TraceCallVersionedInputPayload
3504 ) -> Result<TraceCallVersionedOutputPayload, EthTransactError>;
3505 }
3506}
3507
3508#[macro_export]
3522macro_rules! impl_runtime_apis_plus_revive_traits {
3523 ($Runtime: ty, $Revive: ident, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
3524
3525 type __ReviveMacroMoment = $crate::MomentOf<$Runtime>;
3526
3527 impl $crate::evm::runtime::SetWeightLimit for RuntimeCall {
3528 fn set_weight_limit(&mut self, new_weight_limit: Weight) -> Weight {
3529 use $crate::pallet::Call as ReviveCall;
3530 match self {
3531 Self::$Revive(
3532 ReviveCall::eth_call{ weight_limit, .. } |
3533 ReviveCall::eth_instantiate_with_code{ weight_limit, .. }
3534 ) => {
3535 let old = *weight_limit;
3536 *weight_limit = new_weight_limit;
3537 old
3538 },
3539 _ => Weight::default(),
3540 }
3541 }
3542 }
3543
3544 impl_runtime_apis! {
3545 $($rest)*
3546
3547 #[api_version(2)]
3548 impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber, __ReviveMacroMoment> for $Runtime
3549 {
3550 fn eth_block() -> $crate::pallet_revive_types::runtime_api::BlockV1 {
3551 use $crate::pallet_revive_types::runtime_api::*;
3552
3553 let input = BlockVersionedInputPayload::from(BlockInputPayloadV1);
3554 let output = Self::eth_block_versioned(input);
3555 BlockOutputPayloadV1::try_from(output)
3556 .expect("v1 input must produce v1 output; qed")
3557 .block
3558 }
3559
3560 fn eth_block_hash(number: $crate::U256) -> Option<$crate::H256> {
3561 use $crate::pallet_revive_types::runtime_api::*;
3562
3563 let input = BlockHashVersionedInputPayload::from(BlockHashInputPayloadV1 {
3564 block_number: number
3565 });
3566 let output = Self::eth_block_hash_versioned(input);
3567 BlockHashOutputPayloadV1::try_from(output)
3568 .expect("v1 input must produce v1 output; qed")
3569 .block_hash
3570 }
3571
3572 fn eth_receipt_data() -> Vec<$crate::pallet_revive_types::runtime_api::ReceiptGasInfoV1> {
3573 use $crate::pallet_revive_types::runtime_api::*;
3574
3575 let input = ReceiptDataVersionedInputPayload::from(ReceiptDataInputPayloadV1);
3576 let output = Self::eth_receipt_data_versioned(input);
3577 ReceiptDataOutputPayloadV1::try_from(output)
3578 .expect("v1 input must produce v1 output; qed")
3579 .receipt_data
3580 }
3581
3582 fn balance(address: $crate::H160) -> $crate::U256 {
3583 use $crate::pallet_revive_types::runtime_api::*;
3584
3585 let input = BalanceVersionedInputPayload::from(BalanceInputPayloadV1 { address });
3586 let output = Self::balance_versioned(input);
3587 BalanceOutputPayloadV1::try_from(output)
3588 .expect("v1 input must produce v1 output; qed")
3589 .balance
3590 }
3591
3592 fn block_author() -> $crate::H160 {
3593 use $crate::pallet_revive_types::runtime_api::*;
3594
3595 let input = BlockAuthorVersionedInputPayload::from(BlockAuthorInputPayloadV1);
3596 let output = Self::block_author_versioned(input);
3597 BlockAuthorOutputPayloadV1::try_from(output)
3598 .expect("v1 input must produce v1 output; qed")
3599 .block_author
3600 }
3601
3602 fn block_gas_limit() -> $crate::U256 {
3603 use $crate::pallet_revive_types::runtime_api::*;
3604
3605 let input = BlockGasLimitVersionedInputPayload::from(BlockGasLimitInputPayloadV1);
3606 let output = Self::block_gas_limit_versioned(input);
3607 BlockGasLimitOutputPayloadV1::try_from(output)
3608 .expect("v1 input must produce v1 output; qed")
3609 .block_gas_limit
3610 }
3611
3612 fn max_extrinsic_weight_in_gas() -> $crate::U256 {
3613 use $crate::pallet_revive_types::runtime_api::*;
3614
3615 let input = MaxExtrinsicWeightInGasVersionedInputPayload::from(
3616 MaxExtrinsicWeightInGasInputPayloadV1
3617 );
3618 let output = Self::max_extrinsic_weight_in_gas_versioned(input);
3619 MaxExtrinsicWeightInGasOutputPayloadV1::try_from(output)
3620 .expect("v1 input must produce v1 output; qed")
3621 .max_extrinsic_weight_in_gas
3622 }
3623
3624 fn gas_price() -> $crate::U256 {
3625 use $crate::pallet_revive_types::runtime_api::*;
3626
3627 let input = GasPriceVersionedInputPayload::from(GasPriceInputPayloadV1);
3628 let output = Self::gas_price_versioned(input);
3629 GasPriceOutputPayloadV1::try_from(output)
3630 .expect("v1 input must produce v1 output; qed")
3631 .gas_price
3632 }
3633
3634 fn nonce(address: $crate::H160) -> Nonce {
3635 use $crate::pallet_revive_types::runtime_api::*;
3636
3637 let input = NonceVersionedInputPayload::from(NonceInputPayloadV1 { address });
3638 let output = Self::nonce_versioned(input);
3639 NonceOutputPayloadV1::try_from(output)
3640 .expect("v1 input must produce v1 output; qed")
3641 .nonce
3642 }
3643
3644 fn address(account_id: AccountId) -> $crate::H160 {
3645 use $crate::pallet_revive_types::runtime_api::*;
3646
3647 let input = AddressVersionedInputPayload::from(AddressInputPayloadV1 { account_id });
3648 let output = Self::address_versioned(input);
3649 AddressOutputPayloadV1::try_from(output)
3650 .expect("v1 input must produce v1 output; qed")
3651 .address
3652 }
3653
3654 fn eth_transact(
3655 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3656 ) -> Result<
3657 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3658 $crate::EthTransactError
3659 > {
3660 use $crate::pallet_revive_types::runtime_api::*;
3661
3662 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3663 tx,
3664 timestamp_override: None,
3665 perform_balance_checks: true,
3666 state_overrides: None
3667 });
3668 let output = Self::eth_transact_versioned(input)?;
3669 Ok(TransactOutputPayloadV1::try_from(output)
3670 .expect("v1 input must produce v1 output; qed")
3671 .transact_info)
3672 }
3673
3674 fn eth_transact_with_config(
3675 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3676 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3677 ) -> Result<
3678 $crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3679 $crate::EthTransactError
3680 > {
3681 use $crate::pallet_revive_types::runtime_api::*;
3682
3683 let DryRunConfigV1 { timestamp_override, perform_balance_checks, state_overrides } =
3684 config;
3685
3686 let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3687 tx,
3688 timestamp_override,
3689 perform_balance_checks: perform_balance_checks.unwrap_or(false),
3690 state_overrides
3691 });
3692 let output = Self::eth_transact_versioned(input)?;
3693 Ok(TransactOutputPayloadV1::try_from(output)
3694 .expect("v1 input must produce v1 output; qed")
3695 .transact_info)
3696 }
3697
3698 fn eth_estimate_gas(
3699 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3700 config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3701 ) -> Result<$crate::U256, $crate::EthTransactError> {
3702 use $crate::pallet_revive_types::runtime_api::*;
3703
3704 let DryRunConfigV1 { timestamp_override, perform_balance_checks: _, state_overrides } =
3705 config;
3706
3707 let input = EstimateGasVersionedInputPayload::from(EstimateGasInputPayloadV1 {
3708 tx,
3709 timestamp_override,
3710 state_overrides
3711 });
3712 let output = Self::eth_estimate_gas_versioned(input)?;
3713 Ok(EstimateGasOutputPayloadV1::try_from(output)
3714 .expect("v1 input must produce v1 output; qed")
3715 .gas_estimate)
3716 }
3717
3718 fn eth_pre_dispatch_weight(
3719 tx: Vec<u8>,
3720 ) -> Result<$crate::Weight, $crate::EthTransactError> {
3721 use $crate::pallet_revive_types::runtime_api::*;
3722
3723 let input = PreDispatchWeightVersionedInputPayload::from(
3724 PreDispatchWeightInputPayloadV1 { tx }
3725 );
3726 let output = Self::eth_pre_dispatch_weight_versioned(input)?;
3727 Ok(PreDispatchWeightOutputPayloadV1::try_from(output)
3728 .expect("v1 input must produce v1 output; qed")
3729 .weight)
3730 }
3731
3732 fn call(
3733 origin: AccountId,
3734 dest: $crate::H160,
3735 value: Balance,
3736 weight_limit: Option<$crate::Weight>,
3737 storage_deposit_limit: Option<Balance>,
3738 input_data: Vec<u8>,
3739 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3740 $crate::pallet_revive_types::runtime_api::ExecReturnValueV1,
3741 Balance
3742 > {
3743 use $crate::pallet_revive_types::runtime_api::*;
3744
3745 let input = CallVersionedInputPayload::from(CallInputPayloadV1 {
3746 origin,
3747 dest,
3748 value,
3749 gas_limit: weight_limit,
3750 storage_deposit_limit,
3751 input_data
3752 });
3753 let output = Self::call_versioned(input);
3754 CallOutputPayloadV1::try_from(output)
3755 .expect("v1 input must produce v1 output; qed")
3756 .contract_result
3757 }
3758
3759 fn instantiate(
3760 origin: AccountId,
3761 value: Balance,
3762 weight_limit: Option<$crate::Weight>,
3763 storage_deposit_limit: Option<Balance>,
3764 code: $crate::pallet_revive_types::runtime_api::CodeV1,
3765 data: Vec<u8>,
3766 salt: Option<[u8; 32]>,
3767 ) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3768 $crate::pallet_revive_types::runtime_api::InstantiateReturnValueV1,
3769 Balance
3770 > {
3771 use $crate::pallet_revive_types::runtime_api::*;
3772
3773 let input = InstantiateVersionedInputPayload::from(InstantiateInputPayloadV1 {
3774 origin,
3775 value,
3776 gas_limit: weight_limit,
3777 storage_deposit_limit,
3778 code,
3779 data,
3780 salt
3781 });
3782 let output = Self::instantiate_versioned(input);
3783 InstantiateOutputPayloadV1::try_from(output)
3784 .expect("v1 input must produce v1 output; qed")
3785 .contract_result
3786 }
3787
3788 fn upload_code(
3789 origin: AccountId,
3790 code: Vec<u8>,
3791 storage_deposit_limit: Option<Balance>,
3792 ) -> Result<$crate::pallet_revive_types::runtime_api::CodeUploadReturnValueV1<Balance>, $crate::sp_runtime::DispatchError> {
3793 use $crate::pallet_revive_types::runtime_api::*;
3794
3795 let input = UploadCodeVersionedInputPayload::from(UploadCodeInputPayloadV1 {
3796 origin,
3797 code,
3798 storage_deposit_limit
3799 });
3800 let output = Self::upload_code_versioned(input)?;
3801 Ok(UploadCodeOutputPayloadV1::try_from(output)
3802 .expect("v1 input must produce v1 output; qed")
3803 .code_upload_return_value)
3804 }
3805
3806 fn get_storage_var_key(
3807 address: $crate::H160,
3808 key: Vec<u8>,
3809 ) -> $crate::GetStorageResult {
3810 use $crate::pallet_revive_types::runtime_api::*;
3811
3812 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3813 address,
3814 key: StorageKeyV1::Variable(key)
3815 });
3816 let output = Self::get_storage_versioned(input)?;
3817 Ok(GetStorageOutputPayloadV1::try_from(output)
3818 .expect("v1 input must produce v1 output; qed")
3819 .storage)
3820 }
3821
3822 fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
3823 use $crate::pallet_revive_types::runtime_api::*;
3824
3825 let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3826 address,
3827 key: StorageKeyV1::Fixed(key)
3828 });
3829 let output = Self::get_storage_versioned(input)?;
3830 Ok(GetStorageOutputPayloadV1::try_from(output)
3831 .expect("v1 input must produce v1 output; qed")
3832 .storage)
3833 }
3834
3835 fn trace_block(
3836 block: Block,
3837 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3838 ) -> Vec<(u32, $crate::pallet_revive_types::runtime_api::TraceV1)> {
3839 use $crate::pallet_revive_types::runtime_api::*;
3840
3841 let input = TraceBlockVersionedInputPayload::from(TraceBlockInputPayloadV1 {
3842 block,
3843 config: tracer_type
3844 });
3845 let output = Self::trace_block_versioned(input);
3846 TraceBlockOutputPayloadV1::try_from(output)
3847 .expect("v1 input must produce v1 output; qed")
3848 .traces
3849 }
3850
3851 fn trace_tx(
3852 block: Block,
3853 tx_index: u32,
3854 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3855 ) -> Option<$crate::pallet_revive_types::runtime_api::TraceV1> {
3856 use $crate::pallet_revive_types::runtime_api::*;
3857
3858 let input = TraceTxVersionedInputPayload::from(TraceTxInputPayloadV1 {
3859 block,
3860 tx_index,
3861 config: tracer_type
3862 });
3863 let output = Self::trace_tx_versioned(input);
3864 TraceTxOutputPayloadV1::try_from(output)
3865 .expect("v1 input must produce v1 output; qed")
3866 .trace
3867 }
3868
3869 fn trace_call(
3870 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3871 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3872 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3873 use $crate::pallet_revive_types::runtime_api::*;
3874
3875 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3876 tx,
3877 config: tracer_type,
3878 state_overrides: None
3879 });
3880 let output = Self::trace_call_versioned(input)?;
3881 Ok(TraceCallOutputPayloadV1::try_from(output)
3882 .expect("v1 input must produce v1 output; qed")
3883 .trace)
3884 }
3885
3886 fn trace_call_with_config(
3887 tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3888 tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3889 config: $crate::pallet_revive_types::runtime_api::TracingConfigV1,
3890 ) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3891 use $crate::pallet_revive_types::runtime_api::*;
3892
3893 let TracingConfigV1 { state_overrides } = config;
3894
3895 let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3896 tx,
3897 config: tracer_type,
3898 state_overrides
3899 });
3900 let output = Self::trace_call_versioned(input)?;
3901 Ok(TraceCallOutputPayloadV1::try_from(output)
3902 .expect("v1 input must produce v1 output; qed")
3903 .trace)
3904 }
3905
3906 fn runtime_pallets_address() -> $crate::H160 {
3907 use $crate::pallet_revive_types::runtime_api::*;
3908
3909 let input = RuntimePalletsAddressVersionedInputPayload::from(
3910 RuntimePalletsAddressInputPayloadV1
3911 );
3912 let output = Self::runtime_pallets_address_versioned(input);
3913 RuntimePalletsAddressOutputPayloadV1::try_from(output)
3914 .expect("v1 input must produce v1 output; qed")
3915 .runtime_pallets_address
3916 }
3917
3918 fn code(address: $crate::H160) -> Vec<u8> {
3919 use $crate::pallet_revive_types::runtime_api::*;
3920
3921 let input = CodeVersionedInputPayload::from(CodeInputPayloadV1 { address });
3922 let output = Self::code_versioned(input);
3923 CodeOutputPayloadV1::try_from(output)
3924 .expect("v1 input must produce v1 output; qed")
3925 .code
3926 }
3927
3928 fn account_id(address: $crate::H160) -> AccountId {
3929 use $crate::pallet_revive_types::runtime_api::*;
3930
3931 let input = AccountIdVersionedInputPayload::from(AccountIdInputPayloadV1 { address });
3932 let output = Self::account_id_versioned(input);
3933 AccountIdOutputPayloadV1::try_from(output)
3934 .expect("v1 input must produce v1 output; qed")
3935 .account_id
3936 }
3937
3938 fn new_balance_with_dust(balance: $crate::U256) -> Result<(Balance, u32), $crate::BalanceConversionError> {
3939 use $crate::pallet_revive_types::runtime_api::*;
3940
3941 let input = NewBalanceWithDustVersionedInputPayload::from(
3942 NewBalanceWithDustInputPayloadV1 { balance }
3943 );
3944 let output = Self::new_balance_with_dust_versioned(input)?;
3945 let output = NewBalanceWithDustOutputPayloadV1::try_from(output)
3946 .expect("v1 input must produce v1 output; qed");
3947 Ok((output.new_balance, output.dust))
3948 }
3949
3950 fn version_declarations()
3953 -> $crate::pallet_revive_types::runtime_api::ReviveRuntimeApiVersionDeclarations
3954 {
3955 use $crate::pallet_revive_types::runtime_api::*;
3956
3957 ReviveRuntimeApiVersionDeclarations::new()
3958 .insert("eth_block_versioned", 1)
3959 .insert("eth_block_hash_versioned", 1)
3960 .insert("eth_receipt_data_versioned", 2)
3961 .insert("block_gas_limit_versioned", 1)
3962 .insert("max_extrinsic_weight_in_gas_versioned", 1)
3963 .insert("balance_versioned", 1)
3964 .insert("gas_price_versioned", 1)
3965 .insert("nonce_versioned", 1)
3966 .insert("call_versioned", 1)
3967 .insert("instantiate_versioned", 1)
3968 .insert("eth_transact_versioned", 1)
3969 .insert("eth_estimate_gas_versioned", 1)
3970 .insert("eth_pre_dispatch_weight_versioned", 1)
3971 .insert("upload_code_versioned", 1)
3972 .insert("get_storage_versioned", 1)
3973 .insert("runtime_pallets_address_versioned", 1)
3974 .insert("code_versioned", 1)
3975 .insert("account_id_versioned", 1)
3976 .insert("new_balance_with_dust_versioned", 1)
3977 .insert("block_author_versioned", 1)
3978 .insert("address_versioned", 1)
3979 .insert("trace_block_versioned", 2)
3980 .insert("trace_tx_versioned", 2)
3981 .insert("trace_call_versioned", 2)
3982 }
3983
3984 fn eth_block_versioned(
3985 input: $crate::pallet_revive_types::runtime_api::BlockVersionedInputPayload
3986 ) -> $crate::pallet_revive_types::runtime_api::BlockVersionedOutputPayload {
3987 use $crate::pallet_revive_types::runtime_api::*;
3988 use $crate::runtime_api::*;
3989 use alloc::boxed::Box;
3990
3991 let (_input, output_wrapper): (
3992 _,
3993 Box<dyn Fn(BlockOutputPayload) -> BlockVersionedOutputPayload>,
3994 ) = match input {
3995 BlockVersionedInputPayload::V1(payload) => (
3996 BlockInputPayload::from(payload),
3997 Box::new(|output| BlockVersionedOutputPayload::V1(output.into())),
3998 ),
3999 };
4000
4001 let output = BlockOutputPayload { block: $crate::Pallet::<Self>::eth_block() };
4002 output_wrapper(output)
4003 }
4004
4005 fn eth_block_hash_versioned(
4006 input: $crate::pallet_revive_types::runtime_api::BlockHashVersionedInputPayload
4007 ) -> $crate::pallet_revive_types::runtime_api::BlockHashVersionedOutputPayload {
4008 use $crate::pallet_revive_types::runtime_api::*;
4009 use $crate::runtime_api::*;
4010 use alloc::boxed::Box;
4011
4012 let (input, output_wrapper): (
4013 _,
4014 Box<dyn Fn(BlockHashOutputPayload) -> BlockHashVersionedOutputPayload>,
4015 ) = match input {
4016 BlockHashVersionedInputPayload::V1(payload) => (
4017 BlockHashInputPayload::from(payload),
4018 Box::new(|output| BlockHashVersionedOutputPayload::V1(output.into())),
4019 ),
4020 };
4021
4022 let output = BlockHashOutputPayload {
4023 block_hash: $crate::Pallet::<Self>::eth_block_hash_from_number(input.block_number)
4024 };
4025 output_wrapper(output)
4026 }
4027
4028 fn eth_receipt_data_versioned(
4029 input: $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedInputPayload
4030 ) -> $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedOutputPayload {
4031 use $crate::pallet_revive_types::runtime_api::*;
4032 use $crate::runtime_api::*;
4033 use alloc::boxed::Box;
4034
4035 let (_input, output_wrapper): (
4036 _,
4037 Box<dyn Fn(ReceiptDataOutputPayload) -> ReceiptDataVersionedOutputPayload>,
4038 ) = match input {
4039 ReceiptDataVersionedInputPayload::V1(payload) => (
4040 ReceiptDataInputPayload::from(payload),
4041 Box::new(|output| ReceiptDataVersionedOutputPayload::V1(output.into())),
4042 ),
4043 ReceiptDataVersionedInputPayload::V2(payload) => (
4044 ReceiptDataInputPayload::from(payload),
4045 Box::new(|output| ReceiptDataVersionedOutputPayload::V2(output.into())),
4046 ),
4047 };
4048
4049 let output = ReceiptDataOutputPayload {
4050 receipt_data: $crate::Pallet::<Self>::eth_receipt_data(),
4051 synthetic: $crate::Pallet::<Self>::eth_synthetic_transaction(),
4052 };
4053 output_wrapper(output)
4054 }
4055
4056 fn block_gas_limit_versioned(
4057 input: $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedInputPayload
4058 ) -> $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedOutputPayload {
4059 use $crate::pallet_revive_types::runtime_api::*;
4060 use $crate::runtime_api::*;
4061 use alloc::boxed::Box;
4062
4063 let (_input, output_wrapper): (
4064 _,
4065 Box<dyn Fn(BlockGasLimitOutputPayload) -> BlockGasLimitVersionedOutputPayload>,
4066 ) = match input {
4067 BlockGasLimitVersionedInputPayload::V1(payload) => (
4068 BlockGasLimitInputPayload::from(payload),
4069 Box::new(|output| BlockGasLimitVersionedOutputPayload::V1(output.into())),
4070 ),
4071 };
4072
4073 let output = BlockGasLimitOutputPayload {
4074 block_gas_limit: $crate::Pallet::<Self>::evm_block_gas_limit()
4075 };
4076 output_wrapper(output)
4077 }
4078
4079 fn max_extrinsic_weight_in_gas_versioned(
4080 input: $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedInputPayload
4081 ) -> $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedOutputPayload {
4082 use $crate::pallet_revive_types::runtime_api::*;
4083 use $crate::runtime_api::*;
4084 use alloc::boxed::Box;
4085
4086 let (_input, output_wrapper): (
4087 _,
4088 Box<dyn Fn(MaxExtrinsicWeightInGasOutputPayload) -> MaxExtrinsicWeightInGasVersionedOutputPayload>,
4089 ) = match input {
4090 MaxExtrinsicWeightInGasVersionedInputPayload::V1(payload) => (
4091 MaxExtrinsicWeightInGasInputPayload::from(payload),
4092 Box::new(|output| MaxExtrinsicWeightInGasVersionedOutputPayload::V1(output.into())),
4093 ),
4094 };
4095
4096 let output = MaxExtrinsicWeightInGasOutputPayload {
4097 max_extrinsic_weight_in_gas: $crate::Pallet::<Self>::evm_max_extrinsic_weight_in_gas()
4098 };
4099 output_wrapper(output)
4100 }
4101
4102 fn balance_versioned(
4103 input: $crate::pallet_revive_types::runtime_api::BalanceVersionedInputPayload
4104 ) -> $crate::pallet_revive_types::runtime_api::BalanceVersionedOutputPayload {
4105 use $crate::pallet_revive_types::runtime_api::*;
4106 use $crate::runtime_api::*;
4107 use alloc::boxed::Box;
4108
4109 let (input, output_wrapper): (
4110 _,
4111 Box<dyn Fn(BalanceOutputPayload) -> BalanceVersionedOutputPayload>,
4112 ) = match input {
4113 BalanceVersionedInputPayload::V1(payload) => (
4114 BalanceInputPayload::from(payload),
4115 Box::new(|output| BalanceVersionedOutputPayload::V1(output.into())),
4116 ),
4117 };
4118
4119 let output = BalanceOutputPayload {
4120 balance: $crate::Pallet::<Self>::evm_balance(&input.address)
4121 };
4122 output_wrapper(output)
4123 }
4124
4125 fn gas_price_versioned(
4126 input: $crate::pallet_revive_types::runtime_api::GasPriceVersionedInputPayload
4127 ) -> $crate::pallet_revive_types::runtime_api::GasPriceVersionedOutputPayload {
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(GasPriceOutputPayload) -> GasPriceVersionedOutputPayload>,
4135 ) = match input {
4136 GasPriceVersionedInputPayload::V1(payload) => (
4137 GasPriceInputPayload::from(payload),
4138 Box::new(|output| GasPriceVersionedOutputPayload::V1(output.into())),
4139 ),
4140 };
4141
4142 let output = GasPriceOutputPayload {
4143 gas_price: $crate::Pallet::<Self>::evm_base_fee()
4144 };
4145 output_wrapper(output)
4146 }
4147
4148 fn nonce_versioned(
4149 input: $crate::pallet_revive_types::runtime_api::NonceVersionedInputPayload
4150 ) -> $crate::pallet_revive_types::runtime_api::NonceVersionedOutputPayload<Nonce> {
4151 use $crate::pallet_revive_types::runtime_api::*;
4152 use $crate::runtime_api::*;
4153 use $crate::AddressMapper;
4154 use alloc::boxed::Box;
4155
4156 let (input, output_wrapper): (
4157 _,
4158 Box<dyn Fn(NonceOutputPayload<Nonce>) -> NonceVersionedOutputPayload<Nonce>>,
4159 ) = match input {
4160 NonceVersionedInputPayload::V1(payload) => (
4161 NonceInputPayload::from(payload),
4162 Box::new(|output| NonceVersionedOutputPayload::V1(output.into())),
4163 ),
4164 };
4165
4166 let account = <Self as $crate::Config>::AddressMapper::to_account_id(&input.address);
4167 let output = NonceOutputPayload {
4168 nonce: $crate::frame_system::Pallet::<Self>::account_nonce(account)
4169 };
4170 output_wrapper(output)
4171 }
4172
4173 fn call_versioned(
4174 input: $crate::pallet_revive_types::runtime_api::CallVersionedInputPayload<AccountId, Balance>
4175 ) -> $crate::pallet_revive_types::runtime_api::CallVersionedOutputPayload<Balance> {
4176 use $crate::pallet_revive_types::runtime_api::*;
4177 use $crate::runtime_api::*;
4178 use $crate::frame_support::traits::Get;
4179 use alloc::boxed::Box;
4180
4181 let (input, output_wrapper): (
4182 _,
4183 Box<dyn Fn(CallOutputPayload<Balance>) -> CallVersionedOutputPayload<Balance>>,
4184 ) = match input {
4185 CallVersionedInputPayload::V1(payload) => (
4186 CallInputPayload::from(payload),
4187 Box::new(|output| CallVersionedOutputPayload::V1(output.into())),
4188 ),
4189 };
4190
4191 let blockweights: $crate::BlockWeights =
4192 <Self as $crate::frame_system::Config>::BlockWeights::get();
4193
4194 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
4195 let contract_result = $crate::Pallet::<Self>::bare_call(
4196 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
4197 input.dest,
4198 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
4199 $crate::TransactionLimits::WeightAndDeposit {
4200 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
4201 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
4202 },
4203 input.input_data,
4204 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
4205 );
4206
4207 let output = CallOutputPayload { contract_result };
4208 output_wrapper(output)
4209 }
4210
4211 fn instantiate_versioned(
4212 input: $crate::pallet_revive_types::runtime_api::InstantiateVersionedInputPayload<AccountId, Balance>
4213 ) -> $crate::pallet_revive_types::runtime_api::InstantiateVersionedOutputPayload<Balance> {
4214 use $crate::pallet_revive_types::runtime_api::*;
4215 use $crate::runtime_api::*;
4216 use $crate::frame_support::traits::Get;
4217 use alloc::boxed::Box;
4218
4219 let (input, output_wrapper): (
4220 _,
4221 Box<dyn Fn(InstantiateOutputPayload<Balance>) -> InstantiateVersionedOutputPayload<Balance>>,
4222 ) = match input {
4223 InstantiateVersionedInputPayload::V1(payload) => (
4224 InstantiateInputPayload::from(payload),
4225 Box::new(|output| InstantiateVersionedOutputPayload::V1(output.into())),
4226 ),
4227 };
4228
4229 let blockweights: $crate::BlockWeights =
4230 <Self as $crate::frame_system::Config>::BlockWeights::get();
4231
4232 $crate::Pallet::<Self>::prepare_dry_run(&input.origin);
4233 let contract_result = $crate::Pallet::<Self>::bare_instantiate(
4234 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
4235 $crate::Pallet::<Self>::convert_native_to_evm(input.value),
4236 $crate::TransactionLimits::WeightAndDeposit {
4237 weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
4238 deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
4239 },
4240 input.code,
4241 input.data,
4242 input.salt,
4243 &$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
4244 );
4245
4246 let output = InstantiateOutputPayload { contract_result };
4247 output_wrapper(output)
4248 }
4249
4250 fn eth_transact_versioned(
4251 input: $crate::pallet_revive_types::runtime_api::TransactVersionedInputPayload<__ReviveMacroMoment>
4252 ) -> Result<
4253 $crate::pallet_revive_types::runtime_api::TransactVersionedOutputPayload<Balance>,
4254 $crate::EthTransactError
4255 > {
4256 use $crate::pallet_revive_types::runtime_api::*;
4257 use $crate::runtime_api::*;
4258 use $crate::{
4259 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4260 sp_runtime::traits::TransactionExtension,
4261 sp_runtime::traits::Block as BlockT
4262 };
4263 use alloc::boxed::Box;
4264
4265 let (input, output_wrapper): (
4266 _,
4267 Box<dyn Fn(TransactOutputPayload<Balance>) -> TransactVersionedOutputPayload<Balance>>,
4268 ) = match input {
4269 TransactVersionedInputPayload::V1(payload) => (
4270 TransactInputPayload::from(payload),
4271 Box::new(|output| TransactVersionedOutputPayload::V1(output.into())),
4272 ),
4273 };
4274
4275 let transact_info = $crate::Pallet::<Self>::dry_run_eth_transact(
4276 input.tx,
4277 input.timestamp_override,
4278 input.perform_balance_checks,
4279 input.state_overrides,
4280 )?;
4281 let output = TransactOutputPayload { transact_info };
4282 Ok(output_wrapper(output))
4283 }
4284
4285 fn eth_estimate_gas_versioned(
4286 input: $crate::pallet_revive_types::runtime_api::EstimateGasVersionedInputPayload<__ReviveMacroMoment>
4287 ) -> Result<
4288 $crate::pallet_revive_types::runtime_api::EstimateGasVersionedOutputPayload,
4289 $crate::EthTransactError
4290 > {
4291 use $crate::pallet_revive_types::runtime_api::*;
4292 use $crate::runtime_api::*;
4293 use $crate::{
4294 codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4295 sp_runtime::traits::TransactionExtension,
4296 sp_runtime::traits::Block as BlockT
4297 };
4298 use alloc::boxed::Box;
4299
4300 let (input, output_wrapper): (
4301 _,
4302 Box<dyn Fn(EstimateGasOutputPayload) -> EstimateGasVersionedOutputPayload>,
4303 ) = match input {
4304 EstimateGasVersionedInputPayload::V1(payload) => (
4305 EstimateGasInputPayload::from(payload),
4306 Box::new(|output| EstimateGasVersionedOutputPayload::V1(output.into())),
4307 ),
4308 };
4309
4310 let gas_estimate = $crate::Pallet::<Self>::eth_estimate_gas(
4311 input.tx,
4312 input.timestamp_override,
4313 input.state_overrides,
4314 )?;
4315 let output = EstimateGasOutputPayload { gas_estimate };
4316 Ok(output_wrapper(output))
4317 }
4318
4319 fn eth_pre_dispatch_weight_versioned(
4320 input: $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedInputPayload
4321 ) -> Result<
4322 $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedOutputPayload,
4323 $crate::EthTransactError
4324 > {
4325 use $crate::pallet_revive_types::runtime_api::*;
4326 use $crate::runtime_api::*;
4327 use alloc::boxed::Box;
4328
4329 let (input, output_wrapper): (
4330 _,
4331 Box<dyn Fn(PreDispatchWeightOutputPayload) -> PreDispatchWeightVersionedOutputPayload>,
4332 ) = match input {
4333 PreDispatchWeightVersionedInputPayload::V1(payload) => (
4334 PreDispatchWeightInputPayload::from(payload),
4335 Box::new(|output| PreDispatchWeightVersionedOutputPayload::V1(output.into())),
4336 ),
4337 };
4338
4339 let output = PreDispatchWeightOutputPayload {
4340 weight: $crate::Pallet::<Self>::eth_pre_dispatch_weight(input.tx)?
4341 };
4342 Ok(output_wrapper(output))
4343 }
4344
4345 fn upload_code_versioned(
4346 input: $crate::pallet_revive_types::runtime_api::UploadCodeVersionedInputPayload<AccountId, Balance>
4347 ) -> Result<
4348 $crate::pallet_revive_types::runtime_api::UploadCodeVersionedOutputPayload<Balance>,
4349 $crate::sp_runtime::DispatchError
4350 > {
4351 use $crate::pallet_revive_types::runtime_api::*;
4352 use $crate::runtime_api::*;
4353 use alloc::boxed::Box;
4354
4355 let (input, output_wrapper): (
4356 _,
4357 Box<dyn Fn(UploadCodeOutputPayload<Balance>) -> UploadCodeVersionedOutputPayload<Balance>>,
4358 ) = match input {
4359 UploadCodeVersionedInputPayload::V1(payload) => (
4360 UploadCodeInputPayload::from(payload),
4361 Box::new(|output| UploadCodeVersionedOutputPayload::V1(output.into())),
4362 ),
4363 };
4364
4365 let origin =
4366 <Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin);
4367 let code_upload_return_value = $crate::Pallet::<Self>::bare_upload_code(
4368 origin,
4369 input.code,
4370 input.storage_deposit_limit.unwrap_or(u128::MAX),
4371 )?;
4372 let output = UploadCodeOutputPayload { code_upload_return_value };
4373 Ok(output_wrapper(output))
4374 }
4375
4376 fn get_storage_versioned(
4377 input: $crate::pallet_revive_types::runtime_api::GetStorageVersionedInputPayload
4378 ) -> Result<
4379 $crate::pallet_revive_types::runtime_api::GetStorageVersionedOutputPayload,
4380 $crate::ContractAccessError
4381 > {
4382 use $crate::pallet_revive_types::runtime_api::*;
4383 use $crate::runtime_api::*;
4384 use alloc::boxed::Box;
4385
4386 let (input, output_wrapper): (
4387 _,
4388 Box<dyn Fn(GetStorageOutputPayload) -> GetStorageVersionedOutputPayload>,
4389 ) = match input {
4390 GetStorageVersionedInputPayload::V1(payload) => (
4391 GetStorageInputPayload::from(payload),
4392 Box::new(|output| GetStorageVersionedOutputPayload::V1(output.into())),
4393 ),
4394 };
4395
4396 let storage = match input.key {
4397 StorageKey::Fixed(key) => $crate::Pallet::<Self>::get_storage(input.address, key)?,
4398 StorageKey::Variable(key) => $crate::Pallet::<Self>::get_storage_var_key(input.address, key)?,
4399 };
4400 let output = GetStorageOutputPayload { storage };
4401 Ok(output_wrapper(output))
4402 }
4403
4404 fn runtime_pallets_address_versioned(
4405 input: $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedInputPayload
4406 ) -> $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedOutputPayload {
4407 use $crate::pallet_revive_types::runtime_api::*;
4408 use $crate::runtime_api::*;
4409 use alloc::boxed::Box;
4410
4411 let (_input, output_wrapper): (
4412 _,
4413 Box<dyn Fn(RuntimePalletsAddressOutputPayload) -> RuntimePalletsAddressVersionedOutputPayload>,
4414 ) = match input {
4415 RuntimePalletsAddressVersionedInputPayload::V1(payload) => (
4416 RuntimePalletsAddressInputPayload::from(payload),
4417 Box::new(|output| RuntimePalletsAddressVersionedOutputPayload::V1(output.into())),
4418 ),
4419 };
4420
4421 let output = RuntimePalletsAddressOutputPayload {
4422 runtime_pallets_address: $crate::RUNTIME_PALLETS_ADDR
4423 };
4424 output_wrapper(output)
4425 }
4426
4427 fn code_versioned(
4428 input: $crate::pallet_revive_types::runtime_api::CodeVersionedInputPayload
4429 ) -> $crate::pallet_revive_types::runtime_api::CodeVersionedOutputPayload {
4430 use $crate::pallet_revive_types::runtime_api::*;
4431 use $crate::runtime_api::*;
4432 use alloc::boxed::Box;
4433
4434 let (input, output_wrapper): (
4435 _,
4436 Box<dyn Fn(CodeOutputPayload) -> CodeVersionedOutputPayload>,
4437 ) = match input {
4438 CodeVersionedInputPayload::V1(payload) => (
4439 CodeInputPayload::from(payload),
4440 Box::new(|output| CodeVersionedOutputPayload::V1(output.into())),
4441 ),
4442 };
4443
4444 let output = CodeOutputPayload {
4445 code: $crate::Pallet::<Self>::code(&input.address)
4446 };
4447 output_wrapper(output)
4448 }
4449
4450 fn account_id_versioned(
4451 input: $crate::pallet_revive_types::runtime_api::AccountIdVersionedInputPayload
4452 ) -> $crate::pallet_revive_types::runtime_api::AccountIdVersionedOutputPayload<AccountId> {
4453 use $crate::pallet_revive_types::runtime_api::*;
4454 use $crate::runtime_api::*;
4455 use $crate::AddressMapper;
4456 use alloc::boxed::Box;
4457
4458 let (input, output_wrapper): (
4459 _,
4460 Box<dyn Fn(AccountIdOutputPayload<AccountId>) -> AccountIdVersionedOutputPayload<AccountId>>,
4461 ) = match input {
4462 AccountIdVersionedInputPayload::V1(payload) => (
4463 AccountIdInputPayload::from(payload),
4464 Box::new(|output| AccountIdVersionedOutputPayload::V1(output.into())),
4465 ),
4466 };
4467
4468 let output = AccountIdOutputPayload {
4469 account_id: <Self as $crate::Config>::AddressMapper::to_account_id(&input.address)
4470 };
4471 output_wrapper(output)
4472 }
4473
4474 fn new_balance_with_dust_versioned(
4475 input: $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedInputPayload
4476 ) -> Result<
4477 $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedOutputPayload<Balance>,
4478 $crate::BalanceConversionError
4479 > {
4480 use $crate::pallet_revive_types::runtime_api::*;
4481 use $crate::runtime_api::*;
4482 use alloc::boxed::Box;
4483
4484 let (input, output_wrapper): (
4485 _,
4486 Box<
4487 dyn Fn(NewBalanceWithDustOutputPayload<Balance>) -> NewBalanceWithDustVersionedOutputPayload<Balance>,
4488 >,
4489 ) = match input {
4490 NewBalanceWithDustVersionedInputPayload::V1(payload) => (
4491 NewBalanceWithDustInputPayload::from(payload),
4492 Box::new(|output| NewBalanceWithDustVersionedOutputPayload::V1(output.into())),
4493 ),
4494 };
4495
4496 let (new_balance, dust) = $crate::Pallet::<Self>::new_balance_with_dust(input.balance)?;
4497 let output = NewBalanceWithDustOutputPayload { new_balance, dust };
4498 Ok(output_wrapper(output))
4499 }
4500
4501 fn block_author_versioned(
4502 input: $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedInputPayload
4503 ) -> $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedOutputPayload {
4504 use $crate::pallet_revive_types::runtime_api::*;
4505 use $crate::runtime_api::*;
4506 use alloc::boxed::Box;
4507
4508 let (_input, output_wrapper): (
4509 _,
4510 Box<dyn Fn(BlockAuthorOutputPayload) -> BlockAuthorVersionedOutputPayload>,
4511 ) = match input {
4512 BlockAuthorVersionedInputPayload::V1(payload) => (
4513 BlockAuthorInputPayload::from(payload),
4514 Box::new(|output| BlockAuthorVersionedOutputPayload::V1(output.into())),
4515 ),
4516 };
4517
4518 let output = BlockAuthorOutputPayload {
4519 block_author: $crate::Pallet::<Self>::block_author()
4520 };
4521 output_wrapper(output)
4522 }
4523
4524 fn address_versioned(
4525 input: $crate::pallet_revive_types::runtime_api::AddressVersionedInputPayload<AccountId>
4526 ) -> $crate::pallet_revive_types::runtime_api::AddressVersionedOutputPayload {
4527 use $crate::pallet_revive_types::runtime_api::*;
4528 use $crate::runtime_api::*;
4529 use $crate::AddressMapper;
4530 use alloc::boxed::Box;
4531
4532 let (input, output_wrapper): (
4533 _,
4534 Box<dyn Fn(AddressOutputPayload) -> AddressVersionedOutputPayload>,
4535 ) = match input {
4536 AddressVersionedInputPayload::V1(payload) => (
4537 AddressInputPayload::from(payload),
4538 Box::new(|output| AddressVersionedOutputPayload::V1(output.into())),
4539 ),
4540 };
4541
4542 let output = AddressOutputPayload {
4543 address: <Self as $crate::Config>::AddressMapper::to_address(&input.account_id)
4544 };
4545 output_wrapper(output)
4546 }
4547
4548 fn trace_block_versioned(
4549 input: $crate::pallet_revive_types::runtime_api::TraceBlockVersionedInputPayload<Block>
4550 ) -> $crate::pallet_revive_types::runtime_api::TraceBlockVersionedOutputPayload {
4551 use $crate::{
4552 sp_runtime::traits::Block,
4553 tracing::trace,
4554 evm::TraceEntry,
4555 runtime_api::*,
4556 pallet_revive_types::runtime_api::*
4557 };
4558 use alloc::boxed::Box;
4559
4560 let (input, output_wrapper): (_, Box<dyn Fn(TraceBlockOutputPayload) -> TraceBlockVersionedOutputPayload>) = match input {
4561 TraceBlockVersionedInputPayload::V1(payload) => (
4562 TraceBlockInputPayload::from(payload),
4563 Box::new(|output| TraceBlockVersionedOutputPayload::V1(output.into()))
4564 ),
4565 TraceBlockVersionedInputPayload::V2(payload) => (
4566 TraceBlockInputPayload::from(payload),
4567 Box::new(|output| TraceBlockVersionedOutputPayload::V2(output.into()))
4568 ),
4569 };
4570
4571 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4572 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4573 {
4574 return output_wrapper(Default::default())
4575 }
4576
4577 let mut entries = vec![];
4581 let (header, extrinsics) = input.block.deconstruct();
4582 <$Executive>::initialize_block(&header);
4583 for (index, ext) in extrinsics.into_iter().enumerate() {
4584 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4585 let t = tracer.as_tracing();
4586 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4587
4588 if let Some(tx_trace) = tracer.collect_trace() {
4589 entries.push((index as u32, TraceEntry::Traced(tx_trace)));
4590 } else if let Some(entry) = TraceEntry::for_untraced(&result) {
4591 entries.push((index as u32, entry));
4592 }
4593 }
4594
4595 let output = TraceBlockOutputPayload { entries };
4596 output_wrapper(output)
4597 }
4598
4599 fn trace_tx_versioned(
4600 input: $crate::pallet_revive_types::runtime_api::TraceTxVersionedInputPayload<Block>
4601 ) -> $crate::pallet_revive_types::runtime_api::TraceTxVersionedOutputPayload {
4602 use $crate::pallet_revive_types::runtime_api::*;
4603 use $crate::runtime_api::*;
4604 use $crate::{evm::TraceEntry, sp_runtime::traits::Block, tracing::trace};
4605 use alloc::boxed::Box;
4606
4607 let (input, output_wrapper): (
4608 _,
4609 Box<dyn Fn(TraceTxOutputPayload) -> TraceTxVersionedOutputPayload>,
4610 ) = match input {
4611 TraceTxVersionedInputPayload::V1(payload) => (
4612 TraceTxInputPayload::from(payload),
4613 Box::new(|output| TraceTxVersionedOutputPayload::V1(output.into())),
4614 ),
4615 TraceTxVersionedInputPayload::V2(payload) => (
4616 TraceTxInputPayload::from(payload),
4617 Box::new(|output| TraceTxVersionedOutputPayload::V2(output.into())),
4618 ),
4619 };
4620
4621 if matches!(&input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4622 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4623 {
4624 return output_wrapper(TraceTxOutputPayload { entry: None })
4625 }
4626
4627 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config);
4631 let (header, extrinsics) = input.block.deconstruct();
4632
4633 <$Executive>::initialize_block(&header);
4634 let mut entry = None;
4635 for (index, ext) in extrinsics.into_iter().enumerate() {
4636 if index as u32 == input.tx_index {
4637 let t = tracer.as_tracing();
4638 let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4639 entry = match tracer.collect_trace() {
4640 Some(tx_trace) => Some(TraceEntry::Traced(tx_trace)),
4641 None => TraceEntry::for_untraced(&result),
4642 };
4643 break;
4644 } else {
4645 let _ = <$Executive>::apply_extrinsic(ext);
4646 }
4647 }
4648
4649 let output = TraceTxOutputPayload { entry };
4650 output_wrapper(output)
4651 }
4652
4653 fn trace_call_versioned(
4654 input: $crate::pallet_revive_types::runtime_api::TraceCallVersionedInputPayload
4655 ) -> Result<
4656 $crate::pallet_revive_types::runtime_api::TraceCallVersionedOutputPayload,
4657 $crate::EthTransactError
4658 > {
4659 use $crate::pallet_revive_types::runtime_api::*;
4660 use $crate::runtime_api::*;
4661 use $crate::tracing::trace;
4662 use alloc::boxed::Box;
4663
4664 let (input, output_wrapper): (
4665 _,
4666 Box<dyn Fn(TraceCallOutputPayload) -> TraceCallVersionedOutputPayload>,
4667 ) = match input {
4668 TraceCallVersionedInputPayload::V1(payload) => (
4669 TraceCallInputPayload::from(payload),
4670 Box::new(|output| TraceCallVersionedOutputPayload::V1(output.into())),
4671 ),
4672 TraceCallVersionedInputPayload::V2(payload) => (
4673 TraceCallInputPayload::from(payload),
4674 Box::new(|output| TraceCallVersionedOutputPayload::V2(output.into())),
4675 ),
4676 };
4677
4678 if let Some(overrides) = input.state_overrides {
4679 $crate::state_overrides::apply_state_overrides::<Runtime>(overrides)?;
4680 }
4681
4682 if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4683 !$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4684 {
4685 return Err($crate::EthTransactError::Message("Execution Tracing is disabled".into()))
4686 }
4687
4688 let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4689 let t = tracer.as_tracing();
4690
4691 t.watch_address(&input.tx.from.unwrap_or_default());
4692 t.watch_address(&$crate::Pallet::<Self>::block_author());
4693 let result = trace(t, || {
4694 $crate::Pallet::<Self>::dry_run_eth_transact(input.tx, None, true, None)
4695 });
4696
4697 let trace = if let Some(trace) = tracer.collect_trace() {
4698 Ok(trace)
4699 } else if let Err(err) = result {
4700 Err(err)
4701 } else {
4702 Ok($crate::Pallet::<Self>::evm_tracer(input.config).empty_trace())
4703 }?;
4704
4705 let output = TraceCallOutputPayload { trace };
4706 Ok(output_wrapper(output))
4707 }
4708 }
4709 }
4710 };
4711}