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