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