Skip to main content

pallet_revive/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18#![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 address;
26mod benchmarking;
27#[cfg(any(feature = "runtime-benchmarks", test))]
28pub mod call_builder;
29mod debug;
30mod deposit_payment;
31mod exec;
32mod impl_fungibles;
33mod limits;
34mod metering;
35mod primitives;
36#[doc(hidden)]
37pub mod state_overrides;
38mod storage;
39#[cfg(test)]
40mod tests;
41mod transient_storage;
42mod vm;
43mod weightinfo_extension;
44
45pub mod evm;
46pub mod migrations;
47pub mod mock;
48pub mod precompiles;
49pub mod test_utils;
50pub mod tracing;
51pub mod weights;
52
53use crate::{
54	evm::{
55		CallTracer, CreateCallMode, ExecutionTracer, GenericTransaction, PrestateTracer,
56		TYPE_EIP1559, Trace, Tracer, TracerType, block_hash::EthereumBlockBuilderIR, block_storage,
57		fees::InfoT as FeeInfo, runtime::SetWeightLimit,
58	},
59	exec::{AccountIdOf, ExecError, ReentrancyProtection, Stack as ExecStack},
60	sp_runtime::TransactionOutcome,
61	storage::{AccountType, DeletionQueueManager},
62	tracing::if_tracing,
63	vm::{CodeInfo, RuntimeCosts, pvm::extract_code_and_data},
64	weightinfo_extension::OnFinalizeBlockParts,
65};
66use alloc::{boxed::Box, format, vec};
67use codec::{Codec, Decode, Encode};
68use environmental::*;
69use frame_support::{
70	BoundedVec,
71	dispatch::{
72		DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
73		Pays, PostDispatchInfo, RawOrigin,
74	},
75	ensure,
76	pallet_prelude::DispatchClass,
77	storage::with_transaction,
78	traits::{
79		ConstU32, ConstU64, DefensiveResult, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced,
80		OriginTrait,
81		fungible::{Balanced, Credit, Inspect, Mutate, MutateHold},
82		tokens::Balance,
83	},
84	weights::WeightMeter,
85};
86use frame_system::{
87	Pallet as System, ensure_signed,
88	pallet_prelude::{BlockNumberFor, OriginFor},
89};
90use scale_info::TypeInfo;
91use sp_runtime::{
92	AccountId32, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion,
93	traits::{
94		BadOrigin, Bounded, Convert, Dispatchable, Saturating, UniqueSaturatedFrom,
95		UniqueSaturatedInto, Zero,
96	},
97};
98
99pub use crate::{
100	address::{AccountId32Mapper, AddressMapper, AutoMapper, TestAccountMapper, create1, create2},
101	debug::DebugSettings,
102	deposit_payment::{Deposit, PGasDeposit},
103	evm::{
104		Address as EthAddress, Block as EthBlock, DryRunConfig, ReceiptInfo, TracingConfig,
105		block_hash::ReceiptGasInfo,
106	},
107	exec::{CallResources, DelegateInfo, Executable, Key, MomentOf, Origin as ExecOrigin},
108	limits::TRANSIENT_STORAGE_BYTES as TRANSIENT_STORAGE_LIMIT,
109	metering::{
110		EthTxInfo, FrameMeter, ResourceMeter, Token as WeightToken, TransactionLimits,
111		TransactionMeter,
112	},
113	pallet::{genesis, *},
114	storage::{AccountInfo, ContractInfo},
115	transient_storage::{MeterEntry, StorageMeter as TransientStorageMeter, TransientStorage},
116	vm::{BytecodeType, ContractBlob},
117};
118pub use codec;
119use frame_support::traits::tokens::Precision;
120pub use frame_support::{self, dispatch::DispatchInfo, traits::Time, weights::Weight};
121pub use frame_system::{self, limits::BlockWeights};
122pub use primitives::*;
123pub use sp_core::{H160, H256, U256, keccak_256};
124pub use sp_runtime;
125pub use weights::WeightInfo;
126
127#[cfg(doc)]
128pub use crate::vm::pvm::SyscallDoc;
129
130pub type BalanceOf<T> = <T as Config>::Balance;
131pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
132type TrieId = BoundedVec<u8, ConstU32<128>>;
133type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
134type CallOf<T> = <T as Config>::RuntimeCall;
135
136/// Used as a sentinel value when reading and writing contract memory.
137///
138/// It is usually used to signal `None` to a contract when only a primitive is allowed
139/// and we don't want to go through encoding a full Rust type. Using `u32::Max` is a safe
140/// sentinel because contracts are never allowed to use such a large amount of resources
141/// that this value makes sense for a memory location or length.
142const SENTINEL: u32 = u32::MAX;
143
144/// The target that is used for the log output emitted by this crate.
145///
146/// Hence you can use this target to selectively increase the log level for this crate.
147///
148/// Example: `RUST_LOG=runtime::revive=debug my_code --dev`
149const LOG_TARGET: &str = "runtime::revive";
150
151#[frame_support::pallet]
152pub mod pallet {
153	use super::*;
154	use frame_support::{pallet_prelude::*, traits::FindAuthor};
155	use frame_system::pallet_prelude::*;
156	use sp_core::U256;
157	use sp_runtime::Perbill;
158
159	/// The in-code storage version.
160	pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
161
162	#[pallet::pallet]
163	#[pallet::storage_version(STORAGE_VERSION)]
164	pub struct Pallet<T>(_);
165
166	#[pallet::config(with_default)]
167	pub trait Config: frame_system::Config {
168		/// The time implementation used to supply timestamps to contracts through `seal_now`.
169		type Time: Time<Moment: Into<U256>>;
170
171		/// The balance type of [`Self::Currency`].
172		///
173		/// Just added here to add additional trait bounds.
174		#[pallet::no_default]
175		type Balance: Balance
176			+ TryFrom<U256>
177			+ Into<U256>
178			+ Bounded
179			+ UniqueSaturatedInto<u64>
180			+ UniqueSaturatedFrom<u64>
181			+ UniqueSaturatedInto<u128>;
182
183		/// The fungible in which fees are paid and contract balances are held.
184		#[pallet::no_default]
185		type Currency: Inspect<Self::AccountId, Balance = Self::Balance>
186			+ Mutate<Self::AccountId>
187			+ MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>
188			+ Balanced<Self::AccountId>;
189
190		/// Handler for burned native currency (e.g. gas rounding).
191		///
192		/// When EVM gas accounting rounds up the transaction cost, the small rounding
193		/// difference is withdrawn from the caller and forwarded to this handler.
194		/// Use this to redirect burned value to a treasury or DAP instead of silently
195		/// destroying it.
196		#[pallet::no_default_bounds]
197		type OnBurn: OnUnbalanced<CreditOf<Self>>;
198
199		/// The overarching event type.
200		#[pallet::no_default_bounds]
201		#[allow(deprecated)]
202		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
203
204		/// The overarching call type.
205		#[pallet::no_default_bounds]
206		type RuntimeCall: Parameter
207			+ Dispatchable<
208				RuntimeOrigin = OriginFor<Self>,
209				Info = DispatchInfo,
210				PostInfo = PostDispatchInfo,
211			> + IsType<<Self as frame_system::Config>::RuntimeCall>
212			+ From<Call<Self>>
213			+ IsSubType<Call<Self>>
214			+ GetDispatchInfo;
215
216		/// The overarching origin type.
217		#[pallet::no_default_bounds]
218		type RuntimeOrigin: IsType<OriginFor<Self>>
219			+ From<Origin<Self>>
220			+ Into<Result<Origin<Self>, OriginFor<Self>>>;
221
222		/// Overarching hold reason.
223		#[pallet::no_default_bounds]
224		type RuntimeHoldReason: From<HoldReason>;
225
226		/// Describes the weights of the dispatchables of this module and is also used to
227		/// construct a default cost schedule.
228		type WeightInfo: WeightInfo;
229
230		/// Type that allows the runtime authors to add new host functions for a contract to call.
231		///
232		/// Pass in a tuple of types that implement [`precompiles::Precompile`].
233		#[pallet::no_default_bounds]
234		#[allow(private_bounds)]
235		type Precompiles: precompiles::Precompiles<Self>;
236
237		/// Find the author of the current block.
238		type FindAuthor: FindAuthor<Self::AccountId>;
239
240		/// The amount of balance a caller has to pay for each byte of storage.
241		///
242		/// # Note
243		///
244		/// It is safe to change this value on a live chain as all refunds are pro rata.
245		#[pallet::constant]
246		#[pallet::no_default_bounds]
247		type DepositPerByte: Get<BalanceOf<Self>>;
248
249		/// The amount of balance a caller has to pay for each storage item.
250		///
251		/// # Note
252		///
253		/// It is safe to change this value on a live chain as all refunds are pro rata.
254		#[pallet::constant]
255		#[pallet::no_default_bounds]
256		type DepositPerItem: Get<BalanceOf<Self>>;
257
258		/// The amount of balance a caller has to pay for each child trie storage item.
259		///
260		/// Those are the items created by a contract. In Solidity each value is a single
261		/// storage item. This is why we need to set a lower value here than for the main
262		/// trie items. Otherwise the storage deposit is too high.
263		///
264		/// # Note
265		///
266		/// It is safe to change this value on a live chain as all refunds are pro rata.
267		#[pallet::constant]
268		#[pallet::no_default_bounds]
269		type DepositPerChildTrieItem: Get<BalanceOf<Self>>;
270
271		/// The percentage of the storage deposit that should be held for using a code hash.
272		/// Instantiating a contract, protects the code from being removed. In order to prevent
273		/// abuse these actions are protected with a percentage of the code deposit.
274		#[pallet::constant]
275		type CodeHashLockupDepositPercent: Get<Perbill>;
276
277		/// Use either valid type is [`address::AccountId32Mapper`] or [`address::H160Mapper`].
278		#[pallet::no_default]
279		type AddressMapper: AddressMapper<Self>;
280
281		/// Allow EVM bytecode to be uploaded and instantiated.
282		#[pallet::constant]
283		type AllowEVMBytecode: Get<bool>;
284
285		/// Origin allowed to upload code.
286		///
287		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to upload contract
288		/// code.
289		#[pallet::no_default_bounds]
290		type UploadOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
291
292		/// Origin allowed to instantiate code.
293		///
294		/// # Note
295		///
296		/// This is not enforced when a contract instantiates another contract. The
297		/// [`Self::UploadOrigin`] should make sure that no code is deployed that does unwanted
298		/// instantiations.
299		///
300		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to instantiate
301		/// contract code.
302		#[pallet::no_default_bounds]
303		type InstantiateOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
304
305		/// The amount of memory in bytes that parachain nodes a lot to the runtime.
306		///
307		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
308		/// memory to support this pallet if set to the correct value.
309		type RuntimeMemory: Get<u32>;
310
311		/// The amount of memory in bytes that relay chain validators a lot to the PoV.
312		///
313		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
314		/// memory to support this pallet if set to the correct value.
315		///
316		/// This value is usually higher than [`Self::RuntimeMemory`] to account for the fact
317		/// that validators have to hold all storage items in PvF memory.
318		type PVFMemory: Get<u32>;
319
320		/// The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID.
321		///
322		/// This is a unique identifier assigned to each blockchain network,
323		/// preventing replay attacks.
324		#[pallet::constant]
325		type ChainId: Get<u64>;
326
327		/// The ratio between the decimal representation of the native token and the ETH token.
328		#[pallet::constant]
329		type NativeToEthRatio: Get<u32>;
330
331		/// Set to [`crate::evm::fees::Info`] for a production runtime.
332		///
333		/// For mock runtimes that do not need to interact with any eth compat functionality
334		/// the default value of `()` will suffice.
335		#[pallet::no_default_bounds]
336		type FeeInfo: FeeInfo<Self>;
337
338		/// Payment backend used to charge storage deposits.
339		/// The default `()` binding always uses the native currency.
340		#[pallet::no_default_bounds]
341		type Deposit: Deposit<Self>;
342
343		/// The fraction the maximum extrinsic weight `eth_transact` extrinsics are capped to.
344		///
345		/// This is not a security measure but a requirement due to how we map gas to `(Weight,
346		/// StorageDeposit)`. The mapping might derive a `Weight` that is too large to fit into an
347		/// extrinsic. In this case we cap it to the limit specified here.
348		///
349		/// `eth_transact` transactions that use more weight than specified will fail with an out of
350		/// gas error during execution. Larger fractions will allow more transactions to run.
351		/// Smaller values waste less block space: Choose as small as possible and as large as
352		/// necessary.
353		///
354		///  Default: `0.5`.
355		#[pallet::constant]
356		type MaxEthExtrinsicWeight: Get<FixedU128>;
357
358		/// Allows debug-mode configuration, such as enabling unlimited contract size.
359		#[pallet::constant]
360		type DebugEnabled: Get<bool>;
361
362		/// When enabled, accounts are automatically mapped on creation and unmapped on
363		/// kill via [`AutoMapper`]. This removes the need for explicit `map_account` calls.
364		///
365		/// Requires `frame_system::Config::OnNewAccount` and `OnKilledAccount` to be set
366		/// to [`AutoMapper`]. When enabled, the `map_account` and `unmap_account`
367		/// dispatchables are disabled.
368		#[pallet::constant]
369		type AutoMap: Get<bool>;
370
371		/// This determines the relative scale of our gas price and gas estimates.
372		///
373		/// By default, the gas price (in wei) is `FeeInfo::next_fee_multiplier()` multiplied by
374		/// `NativeToEthRatio`. `GasScale` allows to scale this value: the actual gas price is the
375		/// default gas price multiplied by `GasScale`.
376		///
377		/// As a consequence, gas cost (gas estimates and actual gas usage during transaction) is
378		/// scaled down by the same factor. Thus, the total transaction cost is not affected by
379		/// `GasScale` – apart from rounding differences: the transaction cost is always a multiple
380		/// of the gas price and is derived by rounded up, so that with higher `GasScales` this can
381		/// lead to higher gas cost as the rounding difference would be larger.
382		///
383		/// The main purpose of changing the `GasScale` is to tune the gas cost so that it is closer
384		/// to standard EVM gas cost and contracts will not run out of gas when tools or code
385		/// assume hard coded gas limits.
386		///
387		/// Requirement: `GasScale` must not be 0
388		#[pallet::constant]
389		#[pallet::no_default_bounds]
390		type GasScale: Get<u32>;
391	}
392
393	/// Container for different types that implement [`DefaultConfig`]` of this pallet.
394	pub mod config_preludes {
395		use super::*;
396		use frame_support::{
397			derive_impl,
398			traits::{ConstBool, ConstU32},
399		};
400		use frame_system::EnsureSigned;
401		use sp_core::parameter_types;
402
403		type Balance = u64;
404
405		pub const DOLLARS: Balance = 1_000_000_000_000;
406		pub const CENTS: Balance = DOLLARS / 100;
407		pub const MILLICENTS: Balance = CENTS / 1_000;
408
409		pub const fn deposit(items: u32, bytes: u32) -> Balance {
410			items as Balance * 20 * CENTS + (bytes as Balance) * MILLICENTS
411		}
412
413		parameter_types! {
414			pub const DepositPerItem: Balance = deposit(1, 0);
415			pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
416			pub const DepositPerByte: Balance = deposit(0, 1);
417			pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
418			pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(9, 10);
419			pub const GasScale: u32 = 10u32;
420		}
421
422		/// A type providing default configurations for this pallet in testing environment.
423		pub struct TestDefaultConfig;
424
425		impl Time for TestDefaultConfig {
426			type Moment = u64;
427			fn now() -> Self::Moment {
428				0u64
429			}
430		}
431
432		impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
433			fn convert(w: Weight) -> T {
434				w.ref_time().into()
435			}
436		}
437
438		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
439		impl frame_system::DefaultConfig for TestDefaultConfig {}
440
441		#[frame_support::register_default_impl(TestDefaultConfig)]
442		impl DefaultConfig for TestDefaultConfig {
443			#[inject_runtime_type]
444			type RuntimeEvent = ();
445
446			#[inject_runtime_type]
447			type RuntimeHoldReason = ();
448
449			#[inject_runtime_type]
450			type RuntimeCall = ();
451
452			#[inject_runtime_type]
453			type RuntimeOrigin = ();
454
455			type Precompiles = ();
456			type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
457			type DepositPerByte = DepositPerByte;
458			type DepositPerItem = DepositPerItem;
459			type DepositPerChildTrieItem = DepositPerChildTrieItem;
460			type Time = Self;
461			type AllowEVMBytecode = ConstBool<true>;
462			type UploadOrigin = EnsureSigned<Self::AccountId>;
463			type InstantiateOrigin = EnsureSigned<Self::AccountId>;
464			type WeightInfo = ();
465			type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
466			type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
467			type ChainId = ConstU64<42>;
468			type NativeToEthRatio = ConstU32<1_000_000>;
469			type FindAuthor = ();
470			type FeeInfo = ();
471			type Deposit = ();
472			type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
473			type DebugEnabled = ConstBool<false>;
474			type AutoMap = ConstBool<false>;
475			type GasScale = GasScale;
476			type OnBurn = ();
477		}
478	}
479
480	#[pallet::event]
481	pub enum Event<T: Config> {
482		/// A custom event emitted by the contract.
483		ContractEmitted {
484			/// The contract that emitted the event.
485			contract: H160,
486			/// Data supplied by the contract. Metadata generated during contract compilation
487			/// is needed to decode it.
488			data: Vec<u8>,
489			/// A list of topics used to index the event.
490			/// Number of topics is capped by [`limits::NUM_EVENT_TOPICS`].
491			topics: Vec<H256>,
492		},
493
494		/// Contract deployed by deployer at the specified address.
495		Instantiated { deployer: H160, contract: H160 },
496
497		/// Emitted when an Ethereum transaction reverts.
498		///
499		/// Ethereum transactions always complete successfully at the extrinsic level,
500		/// as even reverted calls must store their `ReceiptInfo`.
501		/// To distinguish reverted calls from successful ones, this event is emitted
502		/// for failed Ethereum transactions.
503		EthExtrinsicRevert { dispatch_error: DispatchError },
504	}
505
506	#[pallet::error]
507	#[repr(u8)]
508	pub enum Error<T> {
509		/// Invalid schedule supplied, e.g. with zero weight of a basic operation.
510		InvalidSchedule = 0x01,
511		/// Invalid combination of flags supplied to `seal_call` or `seal_delegate_call`.
512		InvalidCallFlags = 0x02,
513		/// The executed contract exhausted its gas limit.
514		OutOfGas = 0x03,
515		/// Performing the requested transfer failed. Probably because there isn't enough
516		/// free balance in the sender's account.
517		TransferFailed = 0x04,
518		/// Performing a call was denied because the calling depth reached the limit
519		/// of what is specified in the schedule.
520		MaxCallDepthReached = 0x05,
521		/// No contract was found at the specified address.
522		ContractNotFound = 0x06,
523		/// No code could be found at the supplied code hash.
524		CodeNotFound = 0x07,
525		/// No code info could be found at the supplied code hash.
526		CodeInfoNotFound = 0x08,
527		/// A buffer outside of sandbox memory was passed to a contract API function.
528		OutOfBounds = 0x09,
529		/// Input passed to a contract API function failed to decode as expected type.
530		DecodingFailed = 0x0A,
531		/// Contract trapped during execution.
532		ContractTrapped = 0x0B,
533		/// Event body or storage item exceeds [`limits::STORAGE_BYTES`].
534		ValueTooLarge = 0x0C,
535		/// Termination of a contract is not allowed while the contract is already
536		/// on the call stack. Can be triggered by `seal_terminate`.
537		TerminatedWhileReentrant = 0x0D,
538		/// `seal_call` forwarded this contracts input. It therefore is no longer available.
539		InputForwarded = 0x0E,
540		/// The amount of topics passed to `seal_deposit_events` exceeds the limit.
541		TooManyTopics = 0x0F,
542		/// A contract with the same AccountId already exists.
543		DuplicateContract = 0x12,
544		/// A contract self destructed in its constructor.
545		///
546		/// This can be triggered by a call to `seal_terminate`.
547		TerminatedInConstructor = 0x13,
548		/// A call tried to invoke a contract that is flagged as non-reentrant.
549		ReentranceDenied = 0x14,
550		/// A contract called into the runtime which then called back into this pallet.
551		ReenteredPallet = 0x15,
552		/// A contract attempted to invoke a state modifying API while being in read-only mode.
553		StateChangeDenied = 0x16,
554		/// Origin doesn't have enough balance to pay the required storage deposits.
555		StorageDepositNotEnoughFunds = 0x17,
556		/// More storage was created than allowed by the storage deposit limit.
557		StorageDepositLimitExhausted = 0x18,
558		/// Code removal was denied because the code is still in use by at least one contract.
559		CodeInUse = 0x19,
560		/// The contract ran to completion but decided to revert its storage changes.
561		/// Please note that this error is only returned from extrinsics. When called directly
562		/// or via RPC an `Ok` will be returned. In this case the caller needs to inspect the flags
563		/// to determine whether a reversion has taken place.
564		ContractReverted = 0x1A,
565		/// The contract failed to compile or is missing the correct entry points.
566		///
567		/// A more detailed error can be found on the node console if debug messages are enabled
568		/// by supplying `-lruntime::revive=debug`.
569		CodeRejected = 0x1B,
570		/// The code blob supplied is larger than [`limits::code::BLOB_BYTES`].
571		BlobTooLarge = 0x1C,
572		/// The contract declares too much memory (ro + rw + stack).
573		StaticMemoryTooLarge = 0x1D,
574		/// The program contains a basic block that is larger than allowed.
575		BasicBlockTooLarge = 0x1E,
576		/// The program contains an invalid instruction.
577		InvalidInstruction = 0x1F,
578		/// The contract has reached its maximum number of delegate dependencies.
579		MaxDelegateDependenciesReached = 0x20,
580		/// The dependency was not found in the contract's delegate dependencies.
581		DelegateDependencyNotFound = 0x21,
582		/// The contract already depends on the given delegate dependency.
583		DelegateDependencyAlreadyExists = 0x22,
584		/// Can not add a delegate dependency to the code hash of the contract itself.
585		CannotAddSelfAsDelegateDependency = 0x23,
586		/// Can not add more data to transient storage.
587		OutOfTransientStorage = 0x24,
588		/// The contract tried to call a syscall which does not exist (at its current api level).
589		InvalidSyscall = 0x25,
590		/// Invalid storage flags were passed to one of the storage syscalls.
591		InvalidStorageFlags = 0x26,
592		/// PolkaVM failed during code execution. Probably due to a malformed program.
593		ExecutionFailed = 0x27,
594		/// Failed to convert a U256 to a Balance.
595		BalanceConversionFailed = 0x28,
596		/// Immutable data can only be set during deploys and only be read during calls.
597		/// Additionally, it is only valid to set the data once and it must not be empty.
598		InvalidImmutableAccess = 0x2A,
599		/// An `AccountID32` account tried to interact with the pallet without having a mapping.
600		///
601		/// Call [`Pallet::map_account`] in order to create a mapping for the account.
602		AccountUnmapped = 0x2B,
603		/// Tried to map an account that is already mapped.
604		AccountAlreadyMapped = 0x2C,
605		/// The transaction used to dry-run a contract is invalid.
606		InvalidGenericTransaction = 0x2D,
607		/// The refcount of a code either over or underflowed.
608		RefcountOverOrUnderflow = 0x2E,
609		/// Unsupported precompile address.
610		UnsupportedPrecompileAddress = 0x2F,
611		/// The calldata exceeds [`limits::CALLDATA_BYTES`].
612		CallDataTooLarge = 0x30,
613		/// The return data exceeds [`limits::CALLDATA_BYTES`].
614		ReturnDataTooLarge = 0x31,
615		/// Invalid jump destination. Dynamic jumps points to invalid not jumpdest opcode.
616		InvalidJump = 0x32,
617		/// Attempting to pop a value from an empty stack.
618		StackUnderflow = 0x33,
619		/// Attempting to push a value onto a full stack.
620		StackOverflow = 0x34,
621		/// Too much deposit was drawn from the shared txfee and deposit credit.
622		///
623		/// This happens if the passed `gas` inside the ethereum transaction is too low.
624		TxFeeOverdraw = 0x35,
625		/// When calling an EVM constructor `data` has to be empty.
626		///
627		/// EVM constructors do not accept data. Their input data is part of the code blob itself.
628		EvmConstructorNonEmptyData = 0x36,
629		/// Tried to construct an EVM contract via code hash.
630		///
631		/// EVM contracts can only be instantiated via code upload as no initcode is
632		/// stored on-chain.
633		EvmConstructedFromHash = 0x37,
634		/// The contract does not have enough balance to refund the storage deposit.
635		///
636		/// This is a bug and should never happen. It means the accounting got out of sync.
637		StorageRefundNotEnoughFunds = 0x38,
638		/// This means there are locks on the contracts storage deposit that prevents refunding it.
639		///
640		/// This would be the case if the contract used its storage deposits for governance
641		/// or other pallets that allow creating locks over held balance.
642		StorageRefundLocked = 0x39,
643		/// Called a pre-compile that is not allowed to be delegate called.
644		///
645		/// Some pre-compile functions will trap the caller context if being delegate
646		/// called or if their caller was being delegate called.
647		PrecompileDelegateDenied = 0x40,
648		/// ECDSA public key recovery failed. Most probably wrong recovery id or signature.
649		EcdsaRecoveryFailed = 0x41,
650		/// Manual mapping is disabled when auto-mapping is enabled.
651		AutoMappingEnabled = 0x42,
652		/// A contract cannot be created at this address: it still has uncleared
653		/// [`NativeDepositOf`] entries from a previously terminated contract that the deletion
654		/// queue has not yet drained.
655		PendingDepositCleanup = 0x43,
656		/// Benchmarking only error.
657		#[cfg(feature = "runtime-benchmarks")]
658		BenchmarkingError = 0xFF,
659	}
660
661	/// A reason for the pallet revive placing a hold on funds.
662	#[pallet::composite_enum]
663	pub enum HoldReason {
664		/// The Pallet has reserved it for storing code on-chain.
665		CodeUploadDepositReserve,
666		/// The Pallet has reserved it for storage deposit.
667		StorageDepositReserve,
668		/// Deposit for creating an address mapping in [`OriginalAccount`].
669		AddressMapping,
670	}
671
672	/// A reason for the pallet revive placing a freeze on PGAS funds.
673	#[pallet::composite_enum]
674	pub enum FreezeReason {
675		/// Pins the PGAS existential deposit minted into a contract account so it cannot be
676		/// transferred or burned by the contract while it is alive. Without this freeze, a
677		/// contract could call the PGAS ERC20 precompile with `Preservation::Expendable` and
678		/// drain its own ED.
679		PGasMinBalance,
680	}
681
682	#[derive(
683		PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug,
684	)]
685	#[pallet::origin]
686	pub enum Origin<T: Config> {
687		EthTransaction(T::AccountId),
688	}
689
690	/// A mapping from a contract's code hash to its code.
691	/// The code's size is bounded by [`crate::limits::BLOB_BYTES`] for PVM and
692	/// [`revm::primitives::eip170::MAX_CODE_SIZE`] for EVM bytecode.
693	#[pallet::storage]
694	#[pallet::unbounded]
695	pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, Vec<u8>>;
696
697	/// A mapping from a contract's code hash to its code info.
698	#[pallet::storage]
699	pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
700
701	/// The data associated to a contract or externally owned account.
702	#[pallet::storage]
703	pub(crate) type AccountInfoOf<T: Config> = StorageMap<_, Identity, H160, AccountInfo<T>>;
704
705	/// Native currency storage deposit contributed by a user into a contract.
706	///
707	/// Bounds how much native value the user can receive back from that contract's
708	/// storage deposit.
709	///
710	/// Keys: `(holder, contributor) -> amount`
711	/// - `holder`: account on which the deposit is held (a contract, or the pallet's own account
712	///   for code-upload deposits).
713	/// - `contributor`: user that funded the deposit. Receives the native portion on refund, capped
714	///   at this entry's `amount`.
715	#[pallet::storage]
716	pub(crate) type NativeDepositOf<T: Config> = StorageDoubleMap<
717		_,
718		Identity,
719		T::AccountId,
720		Identity,
721		T::AccountId,
722		BalanceOf<T>,
723		ValueQuery,
724	>;
725
726	/// The immutable data associated with a given account.
727	#[pallet::storage]
728	pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
729
730	/// Terminated contracts that await lazy cleanup.
731	///
732	/// Each entry pairs a child trie ID with the contract account so that `on_idle` can
733	/// drain both the child trie and any [`NativeDepositOf`] entries that named the contract
734	/// as `holder`. Both can be arbitrarily large, so cleanup runs lazily in `on_idle`.
735	#[pallet::storage]
736	pub(crate) type DeletionQueue<T: Config> =
737		StorageMap<_, Twox64Concat, u32, crate::storage::DeletionQueueItem<T>>;
738
739	/// A pair of monotonic counters used to track the latest contract marked for deletion
740	/// and the latest deleted contract in queue.
741	#[pallet::storage]
742	pub(crate) type DeletionQueueCounter<T: Config> =
743		StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
744
745	/// Map a Ethereum address to its original `AccountId32`.
746	///
747	/// When deriving a `H160` from an `AccountId32` we use a hash function. In order to
748	/// reconstruct the original account we need to store the reverse mapping here.
749	/// Register your `AccountId32` using [`Pallet::map_account`] in order to
750	/// use it with this pallet.
751	#[pallet::storage]
752	pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
753
754	/// The current Ethereum block that is stored in the `on_finalize` method.
755	///
756	/// # Note
757	///
758	/// This could be further optimized into the future to store only the minimum
759	/// information needed to reconstruct the Ethereum block at the RPC level.
760	///
761	/// Since the block is convenient to have around, and the extra details are capped
762	/// by a few hashes and the vector of transaction hashes, we store the block here.
763	#[pallet::storage]
764	#[pallet::unbounded]
765	pub(crate) type EthereumBlock<T> = StorageValue<_, EthBlock, ValueQuery>;
766
767	/// Mapping for block number and hashes.
768	///
769	/// The maximum number of elements stored is capped by the block hash count `BLOCK_HASH_COUNT`.
770	#[pallet::storage]
771	pub(crate) type BlockHash<T: Config> =
772		StorageMap<_, Identity, BlockNumberFor<T>, H256, ValueQuery>;
773
774	/// The details needed to reconstruct the receipt info offchain.
775	///
776	/// This contains valuable information about the gas used by the transaction.
777	///
778	/// NOTE: The item is unbound and should therefore never be read on chain.
779	/// It could otherwise inflate the PoV size of a block.
780	#[pallet::storage]
781	#[pallet::unbounded]
782	pub(crate) type ReceiptInfoData<T: Config> = StorageValue<_, Vec<ReceiptGasInfo>, ValueQuery>;
783
784	/// Incremental ethereum block builder.
785	#[pallet::storage]
786	#[pallet::unbounded]
787	pub(crate) type EthBlockBuilderIR<T: Config> =
788		StorageValue<_, EthereumBlockBuilderIR<T>, ValueQuery>;
789
790	/// The first transaction and receipt of the ethereum block.
791	///
792	/// These values are moved out of the `EthBlockBuilderIR` to avoid serializing and
793	/// deserializing them on every transaction. Instead, they are loaded when needed.
794	#[pallet::storage]
795	#[pallet::unbounded]
796	pub(crate) type EthBlockBuilderFirstValues<T: Config> =
797		StorageValue<_, Option<(Vec<u8>, Vec<u8>)>, ValueQuery>;
798
799	/// Debugging settings that can be configured when DebugEnabled config is true.
800	#[pallet::storage]
801	pub(crate) type DebugSettingsOf<T: Config> = StorageValue<_, DebugSettings, ValueQuery>;
802
803	pub mod genesis {
804		use super::*;
805		use crate::evm::Bytes32;
806
807		/// Genesis configuration for contract-specific data.
808		#[derive(Clone, PartialEq, Debug, Default, serde::Serialize, serde::Deserialize)]
809		pub struct ContractData {
810			/// Contract code.
811			pub code: crate::evm::Bytes,
812			/// Initial storage entries as 32-byte key/value pairs.
813			pub storage: alloc::collections::BTreeMap<Bytes32, Bytes32>,
814		}
815
816		/// Genesis configuration for a contract account.
817		#[derive(PartialEq, Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
818		pub struct Account<T: Config> {
819			/// Contract address.
820			pub address: H160,
821			/// Contract balance.
822			#[serde(default)]
823			pub balance: U256,
824			/// Account nonce
825			#[serde(default)]
826			pub nonce: T::Nonce,
827			/// Contract-specific data (code and storage). None for EOAs.
828			#[serde(flatten, skip_serializing_if = "Option::is_none")]
829			pub contract_data: Option<ContractData>,
830		}
831	}
832
833	#[pallet::genesis_config]
834	#[derive(Debug, PartialEq, frame_support::DefaultNoBound)]
835	pub struct GenesisConfig<T: Config> {
836		/// List of native Substrate accounts (typically `AccountId32`) to be mapped at genesis
837		/// block, enabling them to interact with smart contracts.
838		#[serde(default, skip_serializing_if = "Vec::is_empty")]
839		pub mapped_accounts: Vec<T::AccountId>,
840
841		/// Account entries (both EOAs and contracts)
842		#[serde(default, skip_serializing_if = "Vec::is_empty")]
843		pub accounts: Vec<genesis::Account<T>>,
844
845		/// Optional debugging settings applied at genesis.
846		#[serde(default, skip_serializing_if = "Option::is_none")]
847		pub debug_settings: Option<DebugSettings>,
848	}
849
850	#[pallet::genesis_build]
851	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
852		fn build(&self) {
853			use crate::{exec::Key, vm::ContractBlob};
854			use frame_support::traits::fungible::Mutate;
855
856			if !System::<T>::account_exists(&Pallet::<T>::account_id()) {
857				let _ = T::Currency::mint_into(
858					&Pallet::<T>::account_id(),
859					T::Currency::minimum_balance(),
860				);
861			}
862
863			for id in &self.mapped_accounts {
864				if let Err(err) = T::AddressMapper::map_no_deposit_unchecked(id) {
865					log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
866				}
867			}
868
869			let owner = Pallet::<T>::account_id();
870
871			for genesis::Account { address, balance, nonce, contract_data } in &self.accounts {
872				let account_id = T::AddressMapper::to_account_id(address);
873
874				if !System::<T>::account_exists(&account_id) {
875					let _ = T::Currency::mint_into(&account_id, T::Currency::minimum_balance());
876				}
877
878				frame_system::Account::<T>::mutate(&account_id, |info| {
879					info.nonce = (*nonce).into();
880				});
881
882				match contract_data {
883					None => {
884						AccountInfoOf::<T>::insert(
885							address,
886							AccountInfo { account_type: AccountType::EOA, dust: 0 },
887						);
888					},
889					Some(genesis::ContractData { code, storage }) => {
890						let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) {
891							ContractBlob::<T>::from_pvm_code(code.0.clone(), owner.clone())
892								.inspect_err(|err| {
893									log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}");
894								})
895						} else {
896							ContractBlob::<T>::from_evm_runtime_code(code.0.clone(), account_id)
897								.inspect_err(|err| {
898									log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}");
899								})
900						};
901
902						let Ok(blob) = blob else {
903							continue;
904						};
905
906						let code_hash = *blob.code_hash();
907						let Ok(info) = <ContractInfo<T>>::new(&address, 0u32.into(), code_hash)
908							.inspect_err(|err| {
909								log::error!(target: LOG_TARGET, "Failed to create ContractInfo for {address:?}: {err:?}");
910							})
911						else {
912							continue;
913						};
914
915						AccountInfoOf::<T>::insert(
916							address,
917							AccountInfo { account_type: info.clone().into(), dust: 0 },
918						);
919
920						<PristineCode<T>>::insert(blob.code_hash(), code.0.clone());
921						<CodeInfoOf<T>>::insert(blob.code_hash(), blob.code_info().clone());
922						for (k, v) in storage {
923							let _ = info.write(&Key::from_fixed(k.0), Some(v.0.to_vec()), None, false).inspect_err(|err| {
924								log::error!(target: LOG_TARGET, "Failed to write genesis storage for {address:?} at key {k:?}: {err:?}");
925							});
926						}
927					},
928				}
929
930				let _ = Pallet::<T>::set_evm_balance(address, *balance).inspect_err(|err| {
931					log::error!(target: LOG_TARGET, "Failed to set EVM balance for {address:?}: {err:?}");
932				});
933			}
934
935			// Build genesis block
936			block_storage::on_finalize_build_eth_block::<T>(
937				// Make sure to use the block number from storage instead of the hardcoded 0.
938				// This enables testing tools like anvil to customise the genesis block number.
939				frame_system::Pallet::<T>::block_number(),
940			);
941
942			// Set debug settings.
943			if let Some(settings) = self.debug_settings.as_ref() {
944				settings.write_to_storage::<T>()
945			}
946		}
947	}
948
949	#[pallet::hooks]
950	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
951		fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
952			let mut meter = WeightMeter::with_limit(limit);
953			ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
954			meter.consumed()
955		}
956
957		fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
958			// Kill related ethereum block storage items.
959			block_storage::on_initialize::<T>();
960
961			// Warm up the pallet account.
962			System::<T>::account_exists(&Pallet::<T>::account_id());
963			// Account for the fixed part of the costs incurred in `on_finalize`.
964			<T as Config>::WeightInfo::on_finalize_block_fixed()
965		}
966
967		fn on_finalize(block_number: BlockNumberFor<T>) {
968			// Build the ethereum block and place it in storage.
969			block_storage::on_finalize_build_eth_block::<T>(block_number);
970		}
971
972		fn integrity_test() {
973			assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
974
975			assert!(T::GasScale::get() > 0u32.into(), "GasScale must not be 0");
976
977			T::FeeInfo::integrity_test();
978
979			// The memory available in the block building runtime
980			let max_runtime_mem: u64 = T::RuntimeMemory::get().into();
981
982			// We only allow 50% of the runtime memory to be utilized by the contracts call
983			// stack, keeping the rest for other facilities, such as PoV, etc.
984			const TOTAL_MEMORY_DEVIDER: u64 = 2;
985
986			// Validators are configured to be able to use more memory than block builders. This is
987			// because in addition to `max_runtime_mem` they need to hold additional data in
988			// memory: PoV in multiple copies (1x encoded + 2x decoded) and all storage which
989			// includes emitted events. The assumption is that storage/events size
990			// can be a maximum of half of the validator runtime memory - max_runtime_mem.
991			let max_block_weight = T::BlockWeights::get()
992				.get(DispatchClass::Normal)
993				.max_total
994				.unwrap_or_else(|| T::BlockWeights::get().max_block);
995			let max_key_size: u64 =
996				Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
997					.expect("Key of maximal size shall be created")
998					.hash()
999					.len()
1000					.try_into()
1001					.unwrap();
1002
1003			let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
1004			let max_immutable_size: u64 = max_block_weight
1005				.checked_div_per_component(&<RuntimeCosts as WeightToken<T>>::weight(
1006					&RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
1007				))
1008				.unwrap()
1009				.saturating_mul(
1010					u64::from(limits::IMMUTABLE_BYTES)
1011						.saturating_add(max_immutable_key_size)
1012						.into(),
1013				);
1014
1015			let max_pvf_mem: u64 = T::PVFMemory::get().into();
1016			let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
1017
1018			// We can use storage to store events using the available block ref_time with the
1019			// `deposit_event` host function. The overhead of stored events, which is around 100B,
1020			// is not taken into account to simplify calculations, as it does not change much.
1021			let max_events_size = max_block_weight
1022				.checked_div_per_component(
1023					&(<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::DepositEvent {
1024						num_topic: 0,
1025						len: limits::EVENT_BYTES,
1026					})
1027					.saturating_add(<RuntimeCosts as WeightToken<T>>::weight(
1028						&RuntimeCosts::HostFn,
1029					))),
1030				)
1031				.unwrap()
1032				.saturating_mul(limits::EVENT_BYTES.into());
1033
1034			assert!(
1035				max_events_size <= storage_size_limit,
1036				"Maximal events size {} exceeds the events limit {}",
1037				max_events_size,
1038				storage_size_limit
1039			);
1040
1041			// The incremental block builder uses 3 x maximum entry size for receipts and
1042			// for transactions. Transactions are bounded to `MAX_TRANSACTION_PAYLOAD_SIZE`.
1043			//
1044			// To determine the maximum size of the receipts, we know the following:
1045			// - (I) first receipt is stored into pallet storage and not given to the hasher until
1046			//   finalization.
1047			// - (II) the hasher will not consume more memory than the receipts we are giving it.
1048			// - (III) the hasher is capped by 3 x maximum entry for 3 or more transactions.
1049			//
1050			// # Case 1. One transaction with maximum receipts
1051			//
1052			// The worst case scenario for having one single transaction is for the transaction
1053			// to emit the maximum receipt size (ie `max_events_size`). In this case,
1054			// the maximum storage (and memory) consumed is bounded by `max_events_size` (II). The
1055			// receipt is stored in pallet storage, and loaded from storage in the
1056			// `on_finalize` hook (I).
1057			//
1058			// # Case 2. Two transactions
1059			//
1060			// The sum of the receipt size of both transactions cannot exceed `max_events_size`,
1061			// otherwise one transaction will be reverted. From (II), the bytes utilized
1062			// by the builder are capped to `max_events_size`.
1063			//
1064			// # Case 3. Three or more transactions
1065			//
1066			// Similar to the above case, the sum of all receipt size is bounded to
1067			// `max_events_size`. Therefore, the bytes are capped to `max_events_size`.
1068			//
1069			// On average, a transaction could emit `max_events_size / num_tx`. The would
1070			// consume `max_events_size / num_tx * 3` bytes, which is lower than
1071			// `max_events_size` for more than 3 transactions.
1072			//
1073			// In practice, the builder will consume even lower amounts considering
1074			// it is unlikely for a transaction to utilize all the weight of the block for events.
1075			let max_eth_block_builder_bytes =
1076				block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());
1077
1078			log::debug!(
1079				target: LOG_TARGET,
1080				"Integrity check: max_eth_block_builder_bytes={} KB using max_events_size={} KB",
1081				max_eth_block_builder_bytes / 1024,
1082				max_events_size / 1024,
1083			);
1084
1085			// Check that the configured memory limits fit into runtime memory.
1086			//
1087			// Dynamic allocations are not available, yet. Hence they are not taken into
1088			// consideration here.
1089			let memory_left = i128::from(max_runtime_mem)
1090				.saturating_div(TOTAL_MEMORY_DEVIDER.into())
1091				.saturating_sub(limits::MEMORY_REQUIRED.into())
1092				.saturating_sub(max_eth_block_builder_bytes.into());
1093
1094			log::debug!(target: LOG_TARGET, "Integrity check: memory_left={} KB", memory_left / 1024);
1095
1096			assert!(
1097				memory_left >= 0,
1098				"Runtime does not have enough memory for current limits. Additional runtime memory required: {} KB",
1099				memory_left.saturating_mul(TOTAL_MEMORY_DEVIDER.into()).abs() / 1024
1100			);
1101
1102			// We can use storage to store items using the available block ref_time with the
1103			// `set_storage` host function.
1104			let max_storage_size = max_block_weight
1105				.checked_div_per_component(
1106					&<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::SetStorage {
1107						new_bytes: limits::STORAGE_BYTES,
1108						old_bytes: 0,
1109					})
1110					.saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
1111				)
1112				.unwrap()
1113				.saturating_add(max_immutable_size.into())
1114				.saturating_add(max_eth_block_builder_bytes.into());
1115
1116			assert!(
1117				max_storage_size <= storage_size_limit,
1118				"Maximal storage size {} exceeds the storage limit {}",
1119				max_storage_size,
1120				storage_size_limit
1121			);
1122		}
1123	}
1124
1125	#[pallet::call]
1126	impl<T: Config> Pallet<T> {
1127		/// A raw EVM transaction, typically dispatched by an Ethereum JSON-RPC server.
1128		///
1129		/// # Parameters
1130		///
1131		/// * `payload`: The encoded [`crate::evm::TransactionSigned`].
1132		///
1133		/// # Note
1134		///
1135		/// This call cannot be dispatched directly; attempting to do so will result in a failed
1136		/// transaction. It serves as a wrapper for an Ethereum transaction. When submitted, the
1137		/// runtime converts it into a [`sp_runtime::generic::CheckedExtrinsic`] by recovering the
1138		/// signer and validating the transaction.
1139		#[allow(unused_variables)]
1140		#[pallet::call_index(0)]
1141		#[pallet::weight(Weight::MAX)]
1142		pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
1143			Err(frame_system::Error::CallFiltered::<T>.into())
1144		}
1145
1146		/// Makes a call to an account, optionally transferring some balance.
1147		///
1148		/// # Parameters
1149		///
1150		/// * `dest`: Address of the contract to call.
1151		/// * `value`: The balance to transfer from the `origin` to `dest`.
1152		/// * `weight_limit`: The weight limit enforced when executing the constructor.
1153		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the
1154		///   caller to pay for the storage consumed.
1155		/// * `data`: The input data to pass to the contract.
1156		///
1157		/// * If the account is a smart-contract account, the associated code will be
1158		/// executed and any value will be transferred.
1159		/// * If the account is a regular account, any value will be transferred.
1160		/// * If no account exists and the call value is not less than `existential_deposit`,
1161		/// a regular account will be created and any value will be transferred.
1162		#[pallet::call_index(1)]
1163		#[pallet::weight(<T as Config>::WeightInfo::call().saturating_add(*weight_limit))]
1164		pub fn call(
1165			origin: OriginFor<T>,
1166			dest: H160,
1167			#[pallet::compact] value: BalanceOf<T>,
1168			weight_limit: Weight,
1169			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1170			data: Vec<u8>,
1171		) -> DispatchResultWithPostInfo {
1172			Self::ensure_non_contract_if_signed(&origin)?;
1173			let mut output = Self::bare_call(
1174				origin,
1175				dest,
1176				Pallet::<T>::convert_native_to_evm(value),
1177				TransactionLimits::WeightAndDeposit {
1178					weight_limit,
1179					deposit_limit: storage_deposit_limit,
1180				},
1181				data,
1182				&ExecConfig::new_substrate_tx(),
1183			);
1184
1185			if let Ok(return_value) = &output.result &&
1186				return_value.did_revert()
1187			{
1188				output.result = Err(<Error<T>>::ContractReverted.into());
1189			}
1190			dispatch_result(
1191				output.result,
1192				output.weight_consumed,
1193				<T as Config>::WeightInfo::call(),
1194			)
1195		}
1196
1197		/// Instantiates a contract from a previously deployed vm binary.
1198		///
1199		/// This function is identical to [`Self::instantiate_with_code`] but without the
1200		/// code deployment step. Instead, the `code_hash` of an on-chain deployed vm binary
1201		/// must be supplied.
1202		#[pallet::call_index(2)]
1203		#[pallet::weight(
1204			<T as Config>::WeightInfo::instantiate(data.len() as u32).saturating_add(*weight_limit)
1205		)]
1206		pub fn instantiate(
1207			origin: OriginFor<T>,
1208			#[pallet::compact] value: BalanceOf<T>,
1209			weight_limit: Weight,
1210			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1211			code_hash: sp_core::H256,
1212			data: Vec<u8>,
1213			salt: Option<[u8; 32]>,
1214		) -> DispatchResultWithPostInfo {
1215			Self::ensure_non_contract_if_signed(&origin)?;
1216			let data_len = data.len() as u32;
1217			let mut output = Self::bare_instantiate(
1218				origin,
1219				Pallet::<T>::convert_native_to_evm(value),
1220				TransactionLimits::WeightAndDeposit {
1221					weight_limit,
1222					deposit_limit: storage_deposit_limit,
1223				},
1224				Code::Existing(code_hash),
1225				data,
1226				salt,
1227				&ExecConfig::new_substrate_tx(),
1228			);
1229			if let Ok(retval) = &output.result &&
1230				retval.result.did_revert()
1231			{
1232				output.result = Err(<Error<T>>::ContractReverted.into());
1233			}
1234			dispatch_result(
1235				output.result.map(|result| result.result),
1236				output.weight_consumed,
1237				<T as Config>::WeightInfo::instantiate(data_len),
1238			)
1239		}
1240
1241		/// Instantiates a new contract from the supplied `code` optionally transferring
1242		/// some balance.
1243		///
1244		/// This dispatchable has the same effect as calling [`Self::upload_code`] +
1245		/// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please
1246		/// also check the documentation of [`Self::upload_code`].
1247		///
1248		/// # Parameters
1249		///
1250		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1251		/// * `weight_limit`: The weight limit enforced when executing the constructor.
1252		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved
1253		///   from the caller to pay for the storage consumed.
1254		/// * `code`: The contract code to deploy in raw bytes.
1255		/// * `data`: The input data to pass to the contract constructor.
1256		/// * `salt`: Used for the address derivation. If `Some` is supplied then `CREATE2`
1257		/// 	semantics are used. If `None` then `CRATE1` is used.
1258		///
1259		///
1260		/// Instantiation is executed as follows:
1261		///
1262		/// - The supplied `code` is deployed, and a `code_hash` is created for that code.
1263		/// - If the `code_hash` already exists on the chain the underlying `code` will be shared.
1264		/// - The destination address is computed based on the sender, code_hash and the salt.
1265		/// - The smart-contract account is created at the computed address.
1266		/// - The `value` is transferred to the new account.
1267		/// - The `deploy` function is executed in the context of the newly-created account.
1268		#[pallet::call_index(3)]
1269		#[pallet::weight(
1270			<T as Config>::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
1271			.saturating_add(*weight_limit)
1272		)]
1273		pub fn instantiate_with_code(
1274			origin: OriginFor<T>,
1275			#[pallet::compact] value: BalanceOf<T>,
1276			weight_limit: Weight,
1277			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1278			code: Vec<u8>,
1279			data: Vec<u8>,
1280			salt: Option<[u8; 32]>,
1281		) -> DispatchResultWithPostInfo {
1282			Self::ensure_non_contract_if_signed(&origin)?;
1283			let code_len = code.len() as u32;
1284			let data_len = data.len() as u32;
1285			let mut output = Self::bare_instantiate(
1286				origin,
1287				Pallet::<T>::convert_native_to_evm(value),
1288				TransactionLimits::WeightAndDeposit {
1289					weight_limit,
1290					deposit_limit: storage_deposit_limit,
1291				},
1292				Code::Upload(code),
1293				data,
1294				salt,
1295				&ExecConfig::new_substrate_tx(),
1296			);
1297			if let Ok(retval) = &output.result &&
1298				retval.result.did_revert()
1299			{
1300				output.result = Err(<Error<T>>::ContractReverted.into());
1301			}
1302			dispatch_result(
1303				output.result.map(|result| result.result),
1304				output.weight_consumed,
1305				<T as Config>::WeightInfo::instantiate_with_code(code_len, data_len),
1306			)
1307		}
1308
1309		/// Same as [`Self::instantiate_with_code`], but intended to be dispatched **only**
1310		/// by an EVM transaction through the EVM compatibility layer.
1311		///
1312		/// # Parameters
1313		///
1314		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1315		/// * `weight_limit`: The gas limit used to derive the transaction weight for transaction
1316		///   payment
1317		/// * `eth_gas_limit`: The Ethereum gas limit governing the resource usage of the execution
1318		/// * `code`: The contract code to deploy in raw bytes.
1319		/// * `data`: The input data to pass to the contract constructor.
1320		/// * `transaction_encoded`: The RLP encoding of the signed Ethereum transaction,
1321		///   represented as [crate::evm::TransactionSigned], provided by the Ethereum wallet. This
1322		///   is used for building the Ethereum transaction root.
1323		/// * effective_gas_price: the price of a unit of gas
1324		/// * encoded len: the byte code size of the `eth_transact` extrinsic
1325		///
1326		/// Calling this dispatchable ensures that the origin's nonce is bumped only once,
1327		/// via the `CheckNonce` transaction extension. In contrast, [`Self::instantiate_with_code`]
1328		/// also bumps the nonce after contract instantiation, since it may be invoked multiple
1329		/// times within a batch call transaction.
1330		#[pallet::call_index(10)]
1331		#[pallet::weight(
1332			<T as Config>::WeightInfo::eth_instantiate_with_code(code.len() as u32, data.len() as u32, Pallet::<T>::has_dust(*value).into())
1333			.saturating_add(*weight_limit)
1334			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1335		)]
1336		pub fn eth_instantiate_with_code(
1337			origin: OriginFor<T>,
1338			value: U256,
1339			weight_limit: Weight,
1340			eth_gas_limit: U256,
1341			code: Vec<u8>,
1342			data: Vec<u8>,
1343			transaction_encoded: Vec<u8>,
1344			effective_gas_price: U256,
1345			encoded_len: u32,
1346		) -> DispatchResultWithPostInfo {
1347			let signer = Self::ensure_eth_signed(origin)?;
1348			let origin = OriginFor::<T>::signed(signer.clone());
1349			Self::ensure_non_contract_if_signed(&origin)?;
1350			let mut call = Call::<T>::eth_instantiate_with_code {
1351				value,
1352				weight_limit,
1353				eth_gas_limit,
1354				code: code.clone(),
1355				data: data.clone(),
1356				transaction_encoded: transaction_encoded.clone(),
1357				effective_gas_price,
1358				encoded_len,
1359			}
1360			.into();
1361			let info = T::FeeInfo::dispatch_info(&call);
1362			let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1363			drop(call);
1364
1365			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1366				let extra_weight = base_info.total_weight();
1367				let output = Self::bare_instantiate(
1368					origin,
1369					value,
1370					TransactionLimits::EthereumGas {
1371						eth_gas_limit: eth_gas_limit.saturated_into(),
1372						weight_limit,
1373						eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1374					},
1375					Code::Upload(code),
1376					data,
1377					None,
1378					&ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1379				);
1380
1381				block_storage::EthereumCallResult::new::<T>(
1382					signer,
1383					output.map_result(|r| r.result),
1384					base_info.call_weight,
1385					encoded_len,
1386					&info,
1387					effective_gas_price,
1388				)
1389			})
1390		}
1391
1392		/// Same as [`Self::call`], but intended to be dispatched **only**
1393		/// by an EVM transaction through the EVM compatibility layer.
1394		///
1395		/// # Parameters
1396		///
1397		/// * `dest`: The Ethereum address of the account to be called
1398		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1399		/// * `weight_limit`: The gas limit used to derive the transaction weight for transaction
1400		///   payment
1401		/// * `eth_gas_limit`: The Ethereum gas limit governing the resource usage of the execution
1402		/// * `data`: The input data to pass to the contract constructor.
1403		/// * `transaction_encoded`: The RLP encoding of the signed Ethereum transaction,
1404		///   represented as [crate::evm::TransactionSigned], provided by the Ethereum wallet. This
1405		///   is used for building the Ethereum transaction root.
1406		/// * effective_gas_price: the price of a unit of gas
1407		/// * encoded len: the byte code size of the `eth_transact` extrinsic
1408		#[pallet::call_index(11)]
1409		#[pallet::weight(
1410			T::WeightInfo::eth_call(Pallet::<T>::has_dust(*value).into())
1411			.saturating_add(*weight_limit)
1412			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1413		)]
1414		pub fn eth_call(
1415			origin: OriginFor<T>,
1416			dest: H160,
1417			value: U256,
1418			weight_limit: Weight,
1419			eth_gas_limit: U256,
1420			data: Vec<u8>,
1421			transaction_encoded: Vec<u8>,
1422			effective_gas_price: U256,
1423			encoded_len: u32,
1424		) -> DispatchResultWithPostInfo {
1425			let signer = Self::ensure_eth_signed(origin)?;
1426			let origin = OriginFor::<T>::signed(signer.clone());
1427
1428			Self::ensure_non_contract_if_signed(&origin)?;
1429			let mut call = Call::<T>::eth_call {
1430				dest,
1431				value,
1432				weight_limit,
1433				eth_gas_limit,
1434				data: data.clone(),
1435				transaction_encoded: transaction_encoded.clone(),
1436				effective_gas_price,
1437				encoded_len,
1438			}
1439			.into();
1440			let info = T::FeeInfo::dispatch_info(&call);
1441			let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1442			drop(call);
1443
1444			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1445				let extra_weight = base_info.total_weight();
1446				let output = Self::bare_call(
1447					origin,
1448					dest,
1449					value,
1450					TransactionLimits::EthereumGas {
1451						eth_gas_limit: eth_gas_limit.saturated_into(),
1452						weight_limit,
1453						eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1454					},
1455					data,
1456					&ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1457				);
1458
1459				block_storage::EthereumCallResult::new::<T>(
1460					signer,
1461					output,
1462					base_info.call_weight,
1463					encoded_len,
1464					&info,
1465					effective_gas_price,
1466				)
1467			})
1468		}
1469
1470		/// Executes a Substrate runtime call from an Ethereum transaction.
1471		///
1472		/// This dispatchable is intended to be called **only** through the EVM compatibility
1473		/// layer. The provided call will be dispatched using `RawOrigin::Signed`.
1474		///
1475		/// # Parameters
1476		///
1477		/// * `origin`: Must be an [`Origin::EthTransaction`] origin.
1478		/// * `call`: The Substrate runtime call to execute.
1479		/// * `transaction_encoded`: The RLP encoding of the Ethereum transaction,
1480		#[pallet::call_index(12)]
1481		#[pallet::weight(
1482			T::WeightInfo::eth_substrate_call(transaction_encoded.len() as u32)
1483			.saturating_add(call.get_dispatch_info().call_weight)
1484			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1485		)]
1486		pub fn eth_substrate_call(
1487			origin: OriginFor<T>,
1488			call: Box<<T as Config>::RuntimeCall>,
1489			transaction_encoded: Vec<u8>,
1490		) -> DispatchResultWithPostInfo {
1491			// Note that the inner dispatch uses `RawOrigin::Signed`, which cannot
1492			// re-enter `eth_substrate_call` (which requires `Origin::EthTransaction`).
1493			let signer = Self::ensure_eth_signed(origin)?;
1494			Self::ensure_non_contract_if_signed(&OriginFor::<T>::signed(signer.clone()))?;
1495			let tx_len = transaction_encoded.len() as u32;
1496			let weight_overhead = T::WeightInfo::eth_substrate_call(tx_len)
1497				.saturating_add(T::WeightInfo::on_finalize_block_per_tx(tx_len));
1498
1499			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1500				let call_weight = call.get_dispatch_info().call_weight;
1501				let mut call_result = call.dispatch(RawOrigin::Signed(signer).into());
1502
1503				// Add extrinsic_overhead to the actual weight in PostDispatchInfo
1504				match &mut call_result {
1505					Ok(post_info) | Err(DispatchErrorWithPostInfo { post_info, .. }) => {
1506						post_info.actual_weight = Some(
1507							post_info
1508								.actual_weight
1509								.unwrap_or_else(|| call_weight)
1510								.saturating_add(weight_overhead),
1511						);
1512					},
1513				}
1514
1515				// Return zero EVM gas (Substrate dispatch, not EVM contract call).
1516				// Actual weight is in `post_info.actual_weight`.
1517				block_storage::EthereumCallResult {
1518					receipt_gas_info: ReceiptGasInfo::default(),
1519					result: call_result,
1520				}
1521			})
1522		}
1523
1524		/// Upload new `code` without instantiating a contract from it.
1525		///
1526		/// If the code does not already exist a deposit is reserved from the caller
1527		/// The size of the reserve depends on the size of the supplied `code`.
1528		///
1529		/// # Note
1530		///
1531		/// Anyone can instantiate a contract from any uploaded code and thus prevent its removal.
1532		/// To avoid this situation a constructor could employ access control so that it can
1533		/// only be instantiated by permissioned entities. The same is true when uploading
1534		/// through [`Self::instantiate_with_code`].
1535		///
1536		/// If the refcount of the code reaches zero after terminating the last contract that
1537		/// references this code, the code will be removed automatically.
1538		#[pallet::call_index(4)]
1539		#[pallet::weight(<T as Config>::WeightInfo::upload_code(code.len() as u32))]
1540		pub fn upload_code(
1541			origin: OriginFor<T>,
1542			code: Vec<u8>,
1543			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1544		) -> DispatchResult {
1545			Self::ensure_non_contract_if_signed(&origin)?;
1546			Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
1547		}
1548
1549		/// Remove the code stored under `code_hash` and refund the deposit to its owner.
1550		///
1551		/// A code can only be removed by its original uploader (its owner) and only if it is
1552		/// not used by any contract.
1553		#[pallet::call_index(5)]
1554		#[pallet::weight(<T as Config>::WeightInfo::remove_code())]
1555		pub fn remove_code(
1556			origin: OriginFor<T>,
1557			code_hash: sp_core::H256,
1558		) -> DispatchResultWithPostInfo {
1559			let origin = ensure_signed(origin)?;
1560			<ContractBlob<T>>::remove(&origin, code_hash)?;
1561			// we waive the fee because removing unused code is beneficial
1562			Ok(Pays::No.into())
1563		}
1564
1565		/// Privileged function that changes the code of an existing contract.
1566		///
1567		/// This takes care of updating refcounts and all other necessary operations. Returns
1568		/// an error if either the `code_hash` or `dest` do not exist.
1569		///
1570		/// # Note
1571		///
1572		/// This does **not** change the address of the contract in question. This means
1573		/// that the contract address is no longer derived from its code hash after calling
1574		/// this dispatchable.
1575		#[pallet::call_index(6)]
1576		#[pallet::weight(<T as Config>::WeightInfo::set_code())]
1577		pub fn set_code(
1578			origin: OriginFor<T>,
1579			dest: H160,
1580			code_hash: sp_core::H256,
1581		) -> DispatchResult {
1582			ensure_root(origin)?;
1583			<AccountInfoOf<T>>::try_mutate(&dest, |account| {
1584				let Some(account) = account else {
1585					return Err(<Error<T>>::ContractNotFound.into());
1586				};
1587
1588				let AccountType::Contract(ref mut contract) = account.account_type else {
1589					return Err(<Error<T>>::ContractNotFound.into());
1590				};
1591
1592				<CodeInfo<T>>::increment_refcount(code_hash)?;
1593				let _ = <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
1594				contract.code_hash = code_hash;
1595
1596				Ok(())
1597			})
1598		}
1599
1600		/// Register the callers account id so that it can be used in contract interactions.
1601		///
1602		/// This will error if the origin is already mapped or is a eth native `Address20`. It will
1603		/// take a deposit that can be released by calling [`Self::unmap_account`].
1604		///
1605		/// Noop when [`Config::AutoMap`] is enabled, as accounts are automatically mapped
1606		/// on creation via [`AutoMapper`].
1607		#[pallet::call_index(7)]
1608		#[pallet::weight(<T as Config>::WeightInfo::map_account())]
1609		pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
1610			#[cfg(not(feature = "runtime-benchmarks"))]
1611			if T::AutoMap::get() {
1612				return Ok(());
1613			}
1614
1615			Self::ensure_non_contract_if_signed(&origin)?;
1616			let origin = ensure_signed(origin)?;
1617			T::AddressMapper::map(&origin)
1618		}
1619
1620		/// Map many accounts and make the TX free if at least 90% were unmapped or held deposits.
1621		#[pallet::call_index(13)]
1622		#[pallet::weight(<T as Config>::WeightInfo::batch_map_accounts(accounts.len().saturated_into::<u32>()))]
1623		pub fn batch_map_accounts(
1624			origin: OriginFor<T>,
1625			accounts: Vec<T::AccountId>,
1626		) -> DispatchResultWithPostInfo {
1627			ensure_signed(origin.clone())?;
1628			Self::ensure_non_contract_if_signed(&origin)?;
1629
1630			let total: u32 = accounts.len().saturated_into();
1631			let mut mapped = 0;
1632
1633			for account_id in accounts
1634				.iter()
1635				// Eth-derived accounts are stateless mapped, nothing to do.
1636				.filter(|&a| !T::AddressMapper::is_eth_derived(a))
1637				// Skip non-existent accounts: otherwise any caller could permanently
1638				// insert mappings for arbitrary AccountIds at no cost.
1639				.filter(|&a| frame_system::Pallet::<T>::account_exists(a))
1640			{
1641				let mut useful = false;
1642
1643				match T::AddressMapper::map_no_deposit_unchecked(account_id) {
1644					Ok(()) => {
1645						useful = true;
1646					},
1647					Err(err) => log::debug!(
1648						target: LOG_TARGET,
1649						"Failed to map account {account_id:?}: {err:?}",
1650					),
1651				}
1652
1653				match T::Currency::release_all(
1654					&HoldReason::AddressMapping.into(),
1655					account_id,
1656					Precision::BestEffort,
1657				) {
1658					// `release_all` returns `Ok(0)` when there is no hold to release,
1659					// which is not useful work and must not earn a fee refund.
1660					Ok(released) if !released.is_zero() => {
1661						useful = true;
1662					},
1663					Ok(_) => {},
1664					Err(err) => log::debug!(
1665						target: LOG_TARGET,
1666						"Failed to release mapping deposit for {account_id:?}: {err:?}",
1667					),
1668				}
1669
1670				if useful {
1671					mapped = mapped.saturating_add(1);
1672				}
1673			}
1674
1675			// guard against 0 division below
1676			if total == 0 || mapped == 0 {
1677				return Ok(Pays::Yes.into());
1678			}
1679
1680			let proportion_mapped = Perbill::from_rational(mapped, total);
1681			if proportion_mapped >= Perbill::from_percent(90) {
1682				Ok(Pays::No.into())
1683			} else {
1684				Ok(Pays::Yes.into())
1685			}
1686		}
1687
1688		/// Unregister the callers account id in order to free the deposit.
1689		///
1690		/// There is no reason to ever call this function other than freeing up the deposit.
1691		/// This is only useful when the account should no longer be used.
1692		///
1693		/// Disabled when [`Config::AutoMap`] is enabled, as accounts are automatically unmapped
1694		/// on kill via [`AutoMapper`].
1695		#[pallet::call_index(8)]
1696		#[pallet::weight(<T as Config>::WeightInfo::unmap_account())]
1697		pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
1698			#[cfg(not(feature = "runtime-benchmarks"))]
1699			ensure!(!T::AutoMap::get(), <Error<T>>::AutoMappingEnabled);
1700			let origin = ensure_signed(origin)?;
1701			T::AddressMapper::unmap(&origin)
1702		}
1703
1704		/// Dispatch an `call` with the origin set to the callers fallback address.
1705		///
1706		/// Every `AccountId32` can control its corresponding fallback account. The fallback account
1707		/// is the `AccountId20` with the last 12 bytes set to `0xEE`. This is essentially a
1708		/// recovery function in case an `AccountId20` was used without creating a mapping first.
1709		#[pallet::call_index(9)]
1710		#[pallet::weight({
1711			let dispatch_info = call.get_dispatch_info();
1712			(
1713				<T as Config>::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
1714				dispatch_info.class
1715			)
1716		})]
1717		pub fn dispatch_as_fallback_account(
1718			mut origin: OriginFor<T>,
1719			call: Box<<T as Config>::RuntimeCall>,
1720		) -> DispatchResultWithPostInfo {
1721			Self::ensure_non_contract_if_signed(&origin)?;
1722			let account_id = origin.as_signer().ok_or(DispatchError::BadOrigin)?;
1723			let unmapped_account = T::AddressMapper::to_fallback_account_id(
1724				&T::AddressMapper::to_address(&account_id),
1725			);
1726			origin.set_caller_from(RawOrigin::Signed(unmapped_account));
1727			call.dispatch(origin)
1728		}
1729	}
1730}
1731
1732/// Create a dispatch result reflecting the amount of consumed weight.
1733fn dispatch_result<R>(
1734	result: Result<R, DispatchError>,
1735	weight_consumed: Weight,
1736	base_weight: Weight,
1737) -> DispatchResultWithPostInfo {
1738	let post_info = PostDispatchInfo {
1739		actual_weight: Some(weight_consumed.saturating_add(base_weight)),
1740		pays_fee: Default::default(),
1741	};
1742
1743	result
1744		.map(|_| post_info)
1745		.map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
1746}
1747
1748impl<T: Config> Pallet<T> {
1749	/// A generalized version of [`Self::call`].
1750	///
1751	/// Identical to [`Self::call`] but tailored towards being called by other code within the
1752	/// runtime as opposed to from an extrinsic. It returns more information and allows the
1753	/// enablement of features that are not suitable for an extrinsic (debugging, event
1754	/// collection).
1755	pub fn bare_call(
1756		origin: OriginFor<T>,
1757		dest: H160,
1758		evm_value: U256,
1759		transaction_limits: TransactionLimits<T>,
1760		data: Vec<u8>,
1761		exec_config: &ExecConfig<T>,
1762	) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
1763		let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1764			Ok(transaction_meter) => transaction_meter,
1765			Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1766		};
1767		let mut storage_deposit = Default::default();
1768
1769		let try_call = || {
1770			let origin = ExecOrigin::from_runtime_origin(origin)?;
1771			let result = ExecStack::<T, ContractBlob<T>>::run_call(
1772				origin.clone(),
1773				dest,
1774				&mut transaction_meter,
1775				evm_value,
1776				data,
1777				&exec_config,
1778			)?;
1779
1780			storage_deposit = transaction_meter
1781				.execute_postponed_deposits(&origin, &exec_config)
1782				.inspect_err(|err| {
1783				log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1784			})?;
1785
1786			Ok(result)
1787		};
1788		let result = Self::run_guarded(try_call);
1789
1790		log::trace!(target: LOG_TARGET, "Bare call ends: \
1791			result={result:?}, \
1792			weight_consumed={:?}, \
1793			weight_required={:?}, \
1794			storage_deposit={:?}, \
1795			gas_consumed={:?}, \
1796			max_storage_deposit={:?}",
1797			transaction_meter.weight_consumed(),
1798			transaction_meter.weight_required(),
1799			storage_deposit,
1800			transaction_meter.total_consumed_gas(),
1801			transaction_meter.deposit_required()
1802		);
1803
1804		ContractResult {
1805			result: result.map_err(|r| r.error),
1806			weight_consumed: transaction_meter.weight_consumed(),
1807			weight_required: transaction_meter.weight_required(),
1808			storage_deposit,
1809			gas_consumed: transaction_meter.total_consumed_gas(),
1810			max_storage_deposit: transaction_meter.deposit_required(),
1811		}
1812	}
1813
1814	/// Prepare a dry run for the given account.
1815	///
1816	///
1817	/// This function is public because it is called by the runtime API implementation
1818	/// (see `impl_runtime_apis_plus_revive`).
1819	pub fn prepare_dry_run(account: &T::AccountId) {
1820		// Bump the  nonce to simulate what would happen
1821		// `pre-dispatch` if the transaction was executed.
1822		frame_system::Pallet::<T>::inc_account_nonce(account);
1823	}
1824
1825	/// A generalized version of [`Self::instantiate`] or [`Self::instantiate_with_code`].
1826	///
1827	/// Identical to [`Self::instantiate`] or [`Self::instantiate_with_code`] but tailored towards
1828	/// being called by other code within the runtime as opposed to from an extrinsic. It returns
1829	/// more information to the caller useful to estimate the cost of the operation.
1830	pub fn bare_instantiate(
1831		origin: OriginFor<T>,
1832		evm_value: U256,
1833		transaction_limits: TransactionLimits<T>,
1834		code: Code,
1835		data: Vec<u8>,
1836		salt: Option<[u8; 32]>,
1837		exec_config: &ExecConfig<T>,
1838	) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1839		let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1840			Ok(transaction_meter) => transaction_meter,
1841			Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1842		};
1843
1844		let mut storage_deposit = Default::default();
1845
1846		let try_instantiate = || {
1847			let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1848
1849			if_tracing(|t| t.instantiate_code(&code, salt.as_ref()));
1850			let executable = match code {
1851				Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => {
1852					let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1853					let executable = Self::try_upload_code(
1854						upload_account,
1855						code,
1856						BytecodeType::Pvm,
1857						&mut transaction_meter,
1858						&exec_config,
1859					)?;
1860					executable
1861				},
1862				Code::Upload(code) => {
1863					if T::AllowEVMBytecode::get() {
1864						ensure!(data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
1865						let origin = T::UploadOrigin::ensure_origin(origin)?;
1866						let executable = ContractBlob::from_evm_init_code(code, origin)?;
1867						executable
1868					} else {
1869						return Err(<Error<T>>::CodeRejected.into());
1870					}
1871				},
1872				Code::Existing(code_hash) => {
1873					let executable = ContractBlob::from_storage(code_hash, &mut transaction_meter)?;
1874					ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
1875					executable
1876				},
1877			};
1878			let instantiate_origin = ExecOrigin::from_account_id(instantiate_account.clone());
1879			let result = ExecStack::<T, ContractBlob<T>>::run_instantiate(
1880				instantiate_account,
1881				executable,
1882				&mut transaction_meter,
1883				evm_value,
1884				data,
1885				salt.as_ref(),
1886				&exec_config,
1887			);
1888
1889			storage_deposit = transaction_meter
1890				.execute_postponed_deposits(&instantiate_origin, &exec_config)
1891				.inspect_err(|err| {
1892					log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1893				})?;
1894			result
1895		};
1896		let output = Self::run_guarded(try_instantiate);
1897
1898		log::trace!(target: LOG_TARGET, "Bare instantiate ends: weight_consumed={:?}\
1899			weight_required={:?} \
1900			storage_deposit={:?} \
1901			gas_consumed={:?} \
1902			max_storage_deposit={:?}",
1903			transaction_meter.weight_consumed(),
1904			transaction_meter.weight_required(),
1905			storage_deposit,
1906			transaction_meter.total_consumed_gas(),
1907			transaction_meter.deposit_required()
1908		);
1909
1910		ContractResult {
1911			result: output
1912				.map(|(addr, result)| InstantiateReturnValue { result, addr })
1913				.map_err(|e| e.error),
1914			weight_consumed: transaction_meter.weight_consumed(),
1915			weight_required: transaction_meter.weight_required(),
1916			storage_deposit,
1917			gas_consumed: transaction_meter.total_consumed_gas(),
1918			max_storage_deposit: transaction_meter.deposit_required(),
1919		}
1920	}
1921
1922	/// Estimates the amount of gas that a transactions requires.
1923	///
1924	/// This function estimates the gas of the transaction according to the same binary search
1925	/// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of
1926	/// 1.5% so that the algorithm terminates early.
1927	///
1928	/// # Note
1929	///
1930	/// All calls to [`Self::dry_run_eth_transact`] need to happen inside of a [`with_transaction`]
1931	/// with state rollback to ensure that dry runs subsequent to the first one preserve the correct
1932	/// amount of storage deposits needed without any kind of caching from the previous dry runs.
1933	pub fn eth_estimate_gas(
1934		tx: GenericTransaction,
1935		config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
1936	) -> Result<U256, EthTransactError>
1937	where
1938		T::Nonce: Into<U256> + TryFrom<U256>,
1939		CallOf<T>: SetWeightLimit,
1940	{
1941		log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}");
1942
1943		let mut low = U256::zero();
1944		let mut high = Self::evm_block_gas_limit();
1945
1946		log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}");
1947
1948		// If the user has specified a gas limit then this is the limit we use as the high bound for
1949		// the binary search. Also, if the user didn't specify a gas limit then we need to skip the
1950		// balance checks.
1951		let perform_balance_checks = if let Some(gas_limit) = tx.gas {
1952			high = gas_limit;
1953			log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}");
1954			true
1955		} else {
1956			false
1957		};
1958
1959		// Cap the high bound of the binary search based on the account's balance if it can be done.
1960		let fee_cap = tx.max_fee_per_gas.or(tx.gas_price);
1961		if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) {
1962			let mut available_balance = Self::evm_balance(&from);
1963			if let Some(value) = tx.value {
1964				available_balance = available_balance.checked_sub(value).ok_or_else(|| {
1965					EthTransactError::Message("insufficient funds for value transfer".into())
1966				})?;
1967			}
1968			if let Some(allowance) = available_balance.checked_div(fee_cap) {
1969				if high > allowance && allowance != U256::zero() {
1970					log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}");
1971					high = allowance
1972				}
1973			}
1974		}
1975
1976		// TODO: Implement a short circuit for simple transfers. We just need to determine the gas
1977		// needed for it.
1978
1979		// Perform the first dry run with the gas limit of the binary search's high bound. If it
1980		// fails then we attempt again with the max extrinsic weight in gas which we do since some
1981		// transactions fail the dry run with the highest gas limit. If both of these fail then we
1982		// return early as it means that the transaction simply can't succeed.
1983		let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()].map(|gas_limit| {
1984			let mut transaction = tx.clone();
1985			transaction.gas = Some(gas_limit);
1986			let dry_run_config = config.clone().with_perform_balance_checks(perform_balance_checks);
1987			let eth_transact_result = with_transaction(|| {
1988				TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
1989					transaction,
1990					dry_run_config,
1991				)))
1992			})
1993			.expect("Rollback shouldn't error out");
1994			(gas_limit, eth_transact_result)
1995		});
1996		let (gas_limit, first_dry_run_result) = match dry_run_results {
1997			[(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => {
1998				if dry_run_result2.eth_gas >= gas_limit2 {
1999					(gas_limit1, dry_run_result1)
2000				} else {
2001					(gas_limit2, dry_run_result2)
2002				}
2003			},
2004			[(gas_limit, Ok(dry_run_result)), (_, Err(_))] |
2005			[(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result),
2006			[(_, Err(err)), (_, Err(..))] => return Err(err),
2007		};
2008		log::trace!(
2009			target: LOG_TARGET,
2010			"eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}",
2011			gas_limit,
2012			first_dry_run_result.eth_gas
2013		);
2014		low = first_dry_run_result.eth_gas;
2015		high = gas_limit;
2016
2017		while low + U256::one() < high {
2018			log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}");
2019			let error_ratio = high
2020				.checked_sub(low)
2021				.and_then(|value| value.checked_mul(U256::from(1000)))
2022				.and_then(|value| value.checked_div(high))
2023				.ok_or_else(|| {
2024					EthTransactError::Message(
2025						"failed to calculate error ratio in gas estimation".into(),
2026					)
2027				})?;
2028			if error_ratio <= U256::from(15) {
2029				log::trace!(
2030					target: LOG_TARGET,
2031					"eth_estimate_gas finished due to error ratio being less than 1.5% high={}",
2032					high
2033				);
2034				break;
2035			}
2036
2037			let mut midpoint = high
2038				.checked_sub(low)
2039				.and_then(|value| value.checked_div(U256::from(2)))
2040				.and_then(|value| value.checked_add(low))
2041				.ok_or_else(|| {
2042					EthTransactError::Message(
2043						"failed to calculate midpoint in gas estimation".into(),
2044					)
2045				})?;
2046
2047			if let Some(other_midpoint) = low.checked_mul(U256::from(2)) {
2048				if other_midpoint != U256::zero() {
2049					midpoint = midpoint.min(other_midpoint)
2050				}
2051			};
2052
2053			let mut transaction = tx.clone();
2054			transaction.gas = Some(midpoint);
2055			let dry_run_config = config.clone().with_perform_balance_checks(perform_balance_checks);
2056			let dry_run_result = with_transaction(|| {
2057				TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
2058					transaction,
2059					dry_run_config,
2060				)))
2061			})
2062			.expect("Rollback shouldn't error out");
2063			log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}");
2064			match dry_run_result {
2065				Ok(..) => {
2066					log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}");
2067					high = midpoint
2068				},
2069				Err(..) => {
2070					log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}");
2071					low = midpoint
2072				},
2073			}
2074		}
2075
2076		log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}");
2077		Ok(high)
2078	}
2079
2080	/// Return the pre-dispatch weight booked for the signed Ethereum transaction payload.
2081	///
2082	/// This matches the weight contribution that `frame_system::CheckWeight` would add for the
2083	/// transaction on an otherwise empty block:
2084	/// - the revive call's total dispatch weight, including extension weight,
2085	/// - the dispatch class base extrinsic weight,
2086	/// - and the extrinsic-length proof-size charge.
2087	pub fn eth_pre_dispatch_weight(transaction_encoded: Vec<u8>) -> Result<Weight, EthTransactError>
2088	where
2089		CallOf<T>: SetWeightLimit,
2090	{
2091		let signed_tx =
2092			crate::evm::TransactionSigned::decode(&transaction_encoded).map_err(|err| {
2093				EthTransactError::Message(format!("Failed to decode transaction: {err:?}"))
2094			})?;
2095		let signer_addr = signed_tx.recover_eth_address().map_err(|err| {
2096			EthTransactError::Message(format!("Failed to recover signer: {err:?}"))
2097		})?;
2098		let tx =
2099			GenericTransaction::from_signed(signed_tx, Self::evm_base_fee(), Some(signer_addr));
2100		let encoded_len = T::FeeInfo::encoded_len(
2101			crate::Call::<T>::eth_transact { payload: transaction_encoded.clone() }.into(),
2102		);
2103		let call_info = tx
2104			.into_call::<T>(CreateCallMode::ExtrinsicExecution(encoded_len, transaction_encoded))
2105			.map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2106		let info = T::FeeInfo::dispatch_info(&call_info.call);
2107
2108		Ok(frame_system::calculate_consumed_extrinsic_weight::<CallOf<T>>(
2109			&T::BlockWeights::get(),
2110			&info,
2111			call_info.encoded_len as usize,
2112		))
2113	}
2114
2115	/// Dry-run Ethereum calls.
2116	///
2117	/// # Parameters
2118	///
2119	/// - `tx`: The Ethereum transaction to simulate.
2120	pub fn dry_run_eth_transact(
2121		mut tx: GenericTransaction,
2122		mut dry_run_config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
2123	) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
2124	where
2125		T::Nonce: Into<U256> + TryFrom<U256>,
2126		CallOf<T>: SetWeightLimit,
2127	{
2128		log::debug!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?}");
2129
2130		let origin = T::AddressMapper::to_account_id(&tx.from.unwrap_or_default());
2131		Self::prepare_dry_run(&origin);
2132
2133		if let Some(overrides) = dry_run_config.state_overrides.take() {
2134			state_overrides::apply_state_overrides::<T>(overrides)?;
2135		}
2136
2137		let base_fee = Self::evm_base_fee();
2138		let effective_gas_price = tx.effective_gas_price(base_fee).unwrap_or(base_fee);
2139
2140		if effective_gas_price < base_fee {
2141			Err(EthTransactError::Message(format!(
2142				"Effective gas price {effective_gas_price:?} lower than base fee {base_fee:?}"
2143			)))?;
2144		}
2145
2146		if tx.nonce.is_none() {
2147			tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
2148		}
2149		if tx.chain_id.is_none() {
2150			tx.chain_id = Some(T::ChainId::get().into());
2151		}
2152
2153		// tx.into_call expects tx.gas_price to be the effective gas price
2154		tx.gas_price = Some(effective_gas_price);
2155		// we don't support priority fee for now as the tipping system in pallet-transaction-payment
2156		// works differently and the total tip needs to be known pre dispatch
2157		tx.max_priority_fee_per_gas = Some(0.into());
2158		if tx.max_fee_per_gas.is_none() {
2159			tx.max_fee_per_gas = Some(effective_gas_price);
2160		}
2161
2162		let gas = tx.gas;
2163		if tx.gas.is_none() {
2164			tx.gas = Some(Self::evm_block_gas_limit());
2165		}
2166		if tx.r#type.is_none() {
2167			tx.r#type = Some(TYPE_EIP1559.into());
2168		}
2169
2170		// Store values before moving the tx
2171		let value = tx.value.unwrap_or_default();
2172		let input = tx.input.clone().to_vec();
2173		let from = tx.from;
2174		let to = tx.to;
2175
2176		// we need to parse the weight from the transaction so that it is run
2177		// using the exact weight limit passed by the eth wallet
2178		let mut call_info = tx
2179			.into_call::<T>(CreateCallMode::DryRun)
2180			.map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2181
2182		// the dry-run might leave out certain fields
2183		// in those cases we skip the check that the caller has enough balance
2184		// to pay for the fees
2185		let base_info = T::FeeInfo::base_dispatch_info(&mut call_info.call);
2186		let base_weight = base_info.total_weight();
2187		let perform_balance_checks = dry_run_config.perform_balance_checks;
2188		let exec_config =
2189			ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight)
2190				.with_dry_run(dry_run_config);
2191
2192		// emulate transaction behavior
2193		let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
2194		if let Some(from) = &from {
2195			let fees = if gas.is_some() && matches!(perform_balance_checks, Some(true)) {
2196				fees
2197			} else {
2198				Zero::zero()
2199			};
2200			let balance = Self::evm_balance(from);
2201			if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
2202				return Err(EthTransactError::Message(format!(
2203					"insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
2204				)));
2205			}
2206		}
2207
2208		// the deposit is done when the transaction is transformed from an `eth_transact`
2209		// we emulate this behavior for the dry-run here
2210		T::FeeInfo::deposit_txfee(T::Currency::issue(fees));
2211
2212		let extract_error = |err| {
2213			if err == Error::<T>::StorageDepositNotEnoughFunds.into() {
2214				Err(EthTransactError::Message(format!("Not enough gas supplied: {err:?}")))
2215			} else {
2216				Err(EthTransactError::Message(format!("failed to run contract: {err:?}")))
2217			}
2218		};
2219
2220		let transaction_limits = TransactionLimits::EthereumGas {
2221			eth_gas_limit: call_info.eth_gas_limit.saturated_into(),
2222			weight_limit: Self::evm_max_extrinsic_weight(),
2223			eth_tx_info: EthTxInfo::new(call_info.encoded_len, base_weight),
2224		};
2225
2226		// Dry run the call
2227		let mut dry_run = match to {
2228			// A contract call.
2229			Some(dest) => {
2230				if dest == RUNTIME_PALLETS_ADDR {
2231					let Ok(dispatch_call) = <CallOf<T>>::decode(&mut &input[..]) else {
2232						return Err(EthTransactError::Message(format!(
2233							"Failed to decode pallet-call {input:?}"
2234						)));
2235					};
2236
2237					if let Err(result) =
2238						dispatch_call.clone().dispatch(RawOrigin::Signed(origin).into())
2239					{
2240						return Err(EthTransactError::Message(format!(
2241							"Failed to dispatch call: {:?}",
2242							result.error,
2243						)));
2244					};
2245
2246					Default::default()
2247				} else {
2248					// Dry run the call.
2249					let result = crate::Pallet::<T>::bare_call(
2250						OriginFor::<T>::signed(origin),
2251						dest,
2252						value,
2253						transaction_limits,
2254						input.clone(),
2255						&exec_config,
2256					);
2257
2258					let data = match result.result {
2259						Ok(return_value) => {
2260							if return_value.did_revert() {
2261								return Err(EthTransactError::Data(return_value.data));
2262							}
2263							return_value.data
2264						},
2265						Err(err) => {
2266							log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
2267							return extract_error(err);
2268						},
2269					};
2270
2271					EthTransactInfo {
2272						weight_required: result.weight_required,
2273						storage_deposit: result.storage_deposit.charge_or_zero(),
2274						max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2275						data,
2276						eth_gas: Default::default(),
2277					}
2278				}
2279			},
2280			// A contract deployment
2281			None => {
2282				// Extract code and data from the input.
2283				let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2284					extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default()))
2285				} else {
2286					(input, vec![])
2287				};
2288
2289				// Dry run the call.
2290				let result = crate::Pallet::<T>::bare_instantiate(
2291					OriginFor::<T>::signed(origin),
2292					value,
2293					transaction_limits,
2294					Code::Upload(code.clone()),
2295					data.clone(),
2296					None,
2297					&exec_config,
2298				);
2299
2300				let returned_data = match result.result {
2301					Ok(return_value) => {
2302						if return_value.result.did_revert() {
2303							return Err(EthTransactError::Data(return_value.result.data));
2304						}
2305						return_value.result.data
2306					},
2307					Err(err) => {
2308						log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
2309						return extract_error(err);
2310					},
2311				};
2312
2313				EthTransactInfo {
2314					weight_required: result.weight_required,
2315					storage_deposit: result.storage_deposit.charge_or_zero(),
2316					max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2317					data: returned_data,
2318					eth_gas: Default::default(),
2319				}
2320			},
2321		};
2322
2323		// replace the weight passed in the transaction with the dry_run result
2324		call_info.call.set_weight_limit(dry_run.weight_required);
2325
2326		// we notify the wallet that the tx would not fit
2327		let total_weight = T::FeeInfo::dispatch_info(&call_info.call).total_weight();
2328		let max_weight = Self::evm_max_extrinsic_weight();
2329		if total_weight.any_gt(max_weight) {
2330			log::debug!(target: LOG_TARGET, "Transaction weight estimate exceeds extrinsic maximum: \
2331				total_weight={total_weight:?} \
2332				max_weight={max_weight:?}",
2333			);
2334
2335			Err(EthTransactError::Message(format!(
2336				"\
2337				The transaction consumes more than the allowed weight. \
2338				needed={total_weight} \
2339				allowed={max_weight} \
2340				overweight_by={}\
2341				",
2342				total_weight.saturating_sub(max_weight),
2343			)))?;
2344		}
2345
2346		// not enough gas supplied to pay for both the tx fees and the storage deposit
2347		let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
2348		let available_fee = T::FeeInfo::remaining_txfee();
2349		if transaction_fee > available_fee {
2350			Err(EthTransactError::Message(format!(
2351				"Not enough gas supplied: Off by: {:?}",
2352				transaction_fee.saturating_sub(available_fee),
2353			)))?;
2354		}
2355
2356		let total_cost = transaction_fee.saturating_add(dry_run.max_storage_deposit);
2357		let total_cost_wei = Pallet::<T>::convert_native_to_evm(total_cost);
2358		let (mut eth_gas, rest) = total_cost_wei.div_mod(base_fee);
2359		if !rest.is_zero() {
2360			eth_gas = eth_gas.saturating_add(1_u32.into());
2361		}
2362
2363		log::debug!(target: LOG_TARGET, "\
2364			dry_run_eth_transact finished: \
2365			weight_limit={}, \
2366			total_weight={total_weight}, \
2367			max_weight={max_weight}, \
2368			weight_left={}, \
2369			eth_gas={eth_gas}, \
2370			encoded_len={}, \
2371			tx_fee={transaction_fee:?}, \
2372			storage_deposit={:?}, \
2373			max_storage_deposit={:?}\
2374			",
2375			dry_run.weight_required,
2376			max_weight.saturating_sub(total_weight),
2377			call_info.encoded_len,
2378			dry_run.storage_deposit,
2379			dry_run.max_storage_deposit,
2380
2381		);
2382		dry_run.eth_gas = eth_gas;
2383		Ok(dry_run)
2384	}
2385
2386	/// Get the balance with EVM decimals of the given `address`.
2387	///
2388	/// Returns the spendable balance excluding the existential deposit.
2389	pub fn evm_balance(address: &H160) -> U256 {
2390		let balance = AccountInfo::<T>::balance_of((*address).into());
2391		Self::convert_native_to_evm(balance)
2392	}
2393
2394	/// Get the current Ethereum block from storage.
2395	pub fn eth_block() -> EthBlock {
2396		EthereumBlock::<T>::get()
2397	}
2398
2399	/// Convert the Ethereum block number into the Ethereum block hash.
2400	///
2401	/// # Note
2402	///
2403	/// The Ethereum block number is identical to the Substrate block number.
2404	/// If the provided block number is outside of the pruning None is returned.
2405	pub fn eth_block_hash_from_number(number: U256) -> Option<H256> {
2406		let number = BlockNumberFor::<T>::try_from(number).ok()?;
2407		let hash = <BlockHash<T>>::get(number);
2408		if hash == H256::zero() { None } else { Some(hash) }
2409	}
2410
2411	/// The details needed to reconstruct the receipt information offchain.
2412	pub fn eth_receipt_data() -> Vec<ReceiptGasInfo> {
2413		ReceiptInfoData::<T>::get()
2414	}
2415
2416	/// Set the EVM balance of an account.
2417	///
2418	/// The account's total balance becomes the EVM value plus the existential deposit,
2419	/// consistent with `evm_balance` which returns the spendable balance excluding the existential
2420	/// deposit.
2421	pub fn set_evm_balance(address: &H160, evm_value: U256) -> Result<(), Error<T>> {
2422		let (balance, dust) = Self::new_balance_with_dust(evm_value)
2423			.map_err(|_| <Error<T>>::BalanceConversionFailed)?;
2424		let account_id = T::AddressMapper::to_account_id(&address);
2425		T::Currency::set_balance(&account_id, balance);
2426		AccountInfoOf::<T>::mutate(&address, |account| {
2427			if let Some(account) = account {
2428				account.dust = dust;
2429			} else {
2430				*account = Some(AccountInfo { dust, ..Default::default() });
2431			}
2432		});
2433
2434		Ok(())
2435	}
2436
2437	/// Construct native balance from EVM balance.
2438	///
2439	/// Adds the existential deposit and returns the native balance plus the dust.
2440	pub fn new_balance_with_dust(
2441		evm_value: U256,
2442	) -> Result<(BalanceOf<T>, u32), BalanceConversionError> {
2443		let ed = T::Currency::minimum_balance();
2444		let balance_with_dust = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(evm_value)?;
2445		let (value, dust) = balance_with_dust.deconstruct();
2446
2447		Ok((ed.saturating_add(value), dust))
2448	}
2449
2450	/// Get the nonce for the given `address`.
2451	pub fn evm_nonce(address: &H160) -> u32
2452	where
2453		T::Nonce: Into<u32>,
2454	{
2455		let account = T::AddressMapper::to_account_id(&address);
2456		System::<T>::account_nonce(account).into()
2457	}
2458
2459	/// Get the block gas limit.
2460	pub fn evm_block_gas_limit() -> U256 {
2461		// We just return `u64::MAX` because the gas cost of a transaction can get very large when
2462		// the transaction executes many storage deposits (in theory a contract can behave like a
2463		// factory, procedurally create code and make contract creation calls to store that as
2464		// code). It is too brittle to estimate a maximally possible amount here.
2465		// On the other hand, the data type `u64` seems to be the "common denominator" as the
2466		// typical data type tools and Ethereum implementations use to represent gas amounts.
2467		u64::MAX.into()
2468	}
2469
2470	/// Returns the maximum value of gas that can be represented in weights.
2471	pub fn evm_max_extrinsic_weight_in_gas() -> U256 {
2472		let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight());
2473		let gas_scale: BalanceOf<T> = T::GasScale::get().into();
2474		(max_extrinsic_fee / gas_scale).into()
2475	}
2476
2477	/// The maximum weight an `eth_transact` is allowed to consume.
2478	pub fn evm_max_extrinsic_weight() -> Weight {
2479		let factor = <T as Config>::MaxEthExtrinsicWeight::get();
2480		let max_weight = <T as frame_system::Config>::BlockWeights::get()
2481			.get(DispatchClass::Normal)
2482			.max_extrinsic
2483			.unwrap_or_else(|| <T as frame_system::Config>::BlockWeights::get().max_block);
2484		Weight::from_parts(
2485			factor.saturating_mul_int(max_weight.ref_time()),
2486			factor.saturating_mul_int(max_weight.proof_size()),
2487		)
2488	}
2489
2490	/// Get the base gas price.
2491	pub fn evm_base_fee() -> U256 {
2492		let gas_scale = <T as Config>::GasScale::get();
2493		let multiplier = T::FeeInfo::next_fee_multiplier();
2494		multiplier
2495			.saturating_mul_int::<u128>(T::NativeToEthRatio::get().into())
2496			.saturating_mul(gas_scale.saturated_into())
2497			.into()
2498	}
2499
2500	/// Build an EVM tracer from the given tracer type.
2501	pub fn evm_tracer(tracer_type: TracerType) -> Tracer<T>
2502	where
2503		T::Nonce: Into<u32>,
2504	{
2505		match tracer_type {
2506			TracerType::CallTracer(config) => CallTracer::new(config.unwrap_or_default()).into(),
2507			TracerType::PrestateTracer(config) => {
2508				PrestateTracer::new(config.unwrap_or_default()).into()
2509			},
2510			TracerType::ExecutionTracer(config) => {
2511				ExecutionTracer::new(config.unwrap_or_default()).into()
2512			},
2513		}
2514	}
2515
2516	/// A generalized version of [`Self::upload_code`].
2517	///
2518	/// It is identical to [`Self::upload_code`] and only differs in the information it returns.
2519	pub fn bare_upload_code(
2520		origin: OriginFor<T>,
2521		code: Vec<u8>,
2522		storage_deposit_limit: BalanceOf<T>,
2523	) -> CodeUploadResult<BalanceOf<T>> {
2524		let origin = T::UploadOrigin::ensure_origin(origin)?;
2525
2526		let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2527			BytecodeType::Pvm
2528		} else {
2529			if !T::AllowEVMBytecode::get() {
2530				return Err(<Error<T>>::CodeRejected.into());
2531			}
2532			BytecodeType::Evm
2533		};
2534
2535		let mut meter = TransactionMeter::new(TransactionLimits::WeightAndDeposit {
2536			weight_limit: Default::default(),
2537			deposit_limit: storage_deposit_limit,
2538		})?;
2539
2540		let module = Self::try_upload_code(
2541			origin,
2542			code,
2543			bytecode_type,
2544			&mut meter,
2545			&ExecConfig::new_substrate_tx(),
2546		)?;
2547		Ok(CodeUploadReturnValue {
2548			code_hash: *module.code_hash(),
2549			deposit: meter.deposit_consumed().charge_or_zero(),
2550		})
2551	}
2552
2553	/// Query storage of a specified contract under a specified key.
2554	pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
2555		let contract_info =
2556			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2557
2558		let maybe_value = contract_info.read(&Key::from_fixed(key));
2559		Ok(maybe_value)
2560	}
2561
2562	/// Get the immutable data of a specified contract.
2563	///
2564	/// Returns `None` if the contract does not exist or has no immutable data.
2565	pub fn get_immutables(address: H160) -> Option<ImmutableData> {
2566		let immutable_data = <ImmutableDataOf<T>>::get(address);
2567		immutable_data
2568	}
2569
2570	/// Sets immutable data of a contract
2571	///
2572	/// Returns an error if the contract does not exist.
2573	///
2574	/// # Warning
2575	///
2576	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2577	pub fn set_immutables(address: H160, data: ImmutableData) -> Result<(), ContractAccessError> {
2578		AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2579		<ImmutableDataOf<T>>::insert(address, data);
2580		Ok(())
2581	}
2582
2583	/// Query storage of a specified contract under a specified variable-sized key.
2584	pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
2585		let contract_info =
2586			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2587
2588		let maybe_value = contract_info.read(
2589			&Key::try_from_var(key)
2590				.map_err(|_| ContractAccessError::KeyDecodingFailed)?
2591				.into(),
2592		);
2593		Ok(maybe_value)
2594	}
2595
2596	/// Convert a native balance to EVM balance.
2597	pub fn convert_native_to_evm(value: impl Into<BalanceWithDust<BalanceOf<T>>>) -> U256 {
2598		let (value, dust) = value.into().deconstruct();
2599		value
2600			.into()
2601			.saturating_mul(T::NativeToEthRatio::get().into())
2602			.saturating_add(dust.into())
2603	}
2604
2605	/// Set storage of a specified contract under a specified key.
2606	///
2607	/// If the `value` is `None`, the storage entry is deleted.
2608	///
2609	/// Returns an error if the contract does not exist or if the write operation fails.
2610	///
2611	/// # Warning
2612	///
2613	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2614	pub fn set_storage(address: H160, key: [u8; 32], value: Option<Vec<u8>>) -> SetStorageResult {
2615		let contract_info =
2616			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2617
2618		contract_info
2619			.write(&Key::from_fixed(key), value, None, false)
2620			.map_err(ContractAccessError::StorageWriteFailed)
2621	}
2622
2623	/// Set the storage of a specified contract under a specified variable-sized key.
2624	///
2625	/// If the `value` is `None`, the storage entry is deleted.
2626	///
2627	/// Returns an error if the contract does not exist, if the key decoding fails,
2628	/// or if the write operation fails.
2629	///
2630	/// # Warning
2631	///
2632	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2633	pub fn set_storage_var_key(
2634		address: H160,
2635		key: Vec<u8>,
2636		value: Option<Vec<u8>>,
2637	) -> SetStorageResult {
2638		let contract_info =
2639			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2640
2641		contract_info
2642			.write(
2643				&Key::try_from_var(key)
2644					.map_err(|_| ContractAccessError::KeyDecodingFailed)?
2645					.into(),
2646				value,
2647				None,
2648				false,
2649			)
2650			.map_err(ContractAccessError::StorageWriteFailed)
2651	}
2652
2653	/// Pallet account, used to hold funds for contracts upload deposit.
2654	pub fn account_id() -> T::AccountId {
2655		use frame_support::PalletId;
2656		use sp_runtime::traits::AccountIdConversion;
2657		PalletId(*b"py/reviv").into_account_truncating()
2658	}
2659
2660	/// The address of the validator that produced the current block.
2661	pub fn block_author() -> H160 {
2662		use frame_support::traits::FindAuthor;
2663
2664		let digest = <frame_system::Pallet<T>>::digest();
2665		let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
2666
2667		T::FindAuthor::find_author(pre_runtime_digests)
2668			.map(|account_id| T::AddressMapper::to_address(&account_id))
2669			.unwrap_or_default()
2670	}
2671
2672	/// Returns the code at `address`.
2673	///
2674	/// This takes pre-compiles into account.
2675	pub fn code(address: &H160) -> Vec<u8> {
2676		use precompiles::{All, Precompiles};
2677		if let Some(code) = <All<T>>::code(address.as_fixed_bytes()) {
2678			return code.into();
2679		}
2680		AccountInfo::<T>::load_contract(&address)
2681			.and_then(|contract| <PristineCode<T>>::get(contract.code_hash))
2682			.map(|code| code.into())
2683			.unwrap_or_default()
2684	}
2685
2686	/// Uploads new code and returns the Vm binary contract blob and deposit amount collected.
2687	pub fn try_upload_code(
2688		origin: T::AccountId,
2689		code: Vec<u8>,
2690		code_type: BytecodeType,
2691		meter: &mut TransactionMeter<T>,
2692		exec_config: &ExecConfig<T>,
2693	) -> Result<ContractBlob<T>, DispatchError> {
2694		let mut module = match code_type {
2695			BytecodeType::Pvm => ContractBlob::from_pvm_code(code, origin)?,
2696			BytecodeType::Evm => ContractBlob::from_evm_runtime_code(code, origin)?,
2697		};
2698		module.store_code(exec_config, meter)?;
2699		Ok(module)
2700	}
2701
2702	/// Run the supplied function `f` if no other instance of this pallet is on the stack.
2703	fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
2704		executing_contract::using_once(&mut false, || {
2705			executing_contract::with(|f| {
2706				// Fail if already entered contract execution
2707				if *f {
2708					return Err(())
2709				}
2710				// We are entering contract execution
2711				*f = true;
2712				Ok(())
2713			})
2714				.expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
2715				.map_err(|_| <Error<T>>::ReenteredPallet.into())
2716				.map(|_| f())
2717				.and_then(|r| r)
2718		})
2719	}
2720
2721	/// Transfer a deposit from some account to another and place it on hold under `hold_reason`.
2722	///
2723	/// `from` is usually the transaction origin and `to` a contract or
2724	/// the pallets own account.
2725	fn charge_deposit(
2726		hold_reason: HoldReason,
2727		from: &T::AccountId,
2728		to: &T::AccountId,
2729		amount: BalanceOf<T>,
2730		exec_config: &ExecConfig<T>,
2731	) -> DispatchResult {
2732		if amount.is_zero() {
2733			return Ok(());
2734		}
2735
2736		T::Deposit::charge_and_hold(hold_reason, exec_config.funds(from), to, amount)
2737			.map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
2738		Ok(())
2739	}
2740
2741	/// Refund a deposit.
2742	///
2743	/// `dst` is usually the transaction origin and `from` a contract or
2744	/// the pallets own account.
2745	fn refund_deposit(
2746		hold_reason: HoldReason,
2747		from: &T::AccountId,
2748		dst: deposit_payment::Funds<T::AccountId>,
2749		amount: BalanceOf<T>,
2750	) -> Result<(), DispatchError> {
2751		if amount.is_zero() {
2752			return Ok(());
2753		}
2754
2755		let to = match &dst {
2756			deposit_payment::Funds::Balance(to) | deposit_payment::Funds::TxFee(to) => *to,
2757		};
2758		let result = T::Deposit::refund_on_hold(hold_reason, from, dst, amount);
2759
2760		result.defensive_map_err(|err| {
2761			let available = T::Deposit::total_on_hold(hold_reason, from);
2762			if available < amount {
2763				// The storage deposit accounting got out of sync with the balance: This would be a
2764				// straight up bug in this pallet.
2765				log::error!(
2766					target: LOG_TARGET,
2767					"Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}. Not enough deposit: {available:?}. This is a bug.",
2768				);
2769				Error::<T>::StorageRefundNotEnoughFunds.into()
2770			} else {
2771				// There are some locks preventing the refund. This could be the case if the
2772				// contract participates in government. The consequence is that if a contract votes
2773				// with its storage deposit it would no longer be possible to remove storage without first
2774				// reducing the lock.
2775				log::warn!(
2776					target: LOG_TARGET,
2777					"Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}: {err:?}. First remove locks (staking, governance) from the contracts account.",
2778				);
2779				Error::<T>::StorageRefundLocked.into()
2780			}
2781		})
2782	}
2783
2784	/// Returns true if the evm value carries dust.
2785	fn has_dust(value: U256) -> bool {
2786		value % U256::from(<T>::NativeToEthRatio::get()) != U256::zero()
2787	}
2788
2789	/// Returns true if the evm value carries balance.
2790	fn has_balance(value: U256) -> bool {
2791		value >= U256::from(<T>::NativeToEthRatio::get())
2792	}
2793
2794	/// Return the existential deposit of [`Config::Currency`].
2795	#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))]
2796	fn min_balance() -> BalanceOf<T> {
2797		<T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
2798	}
2799
2800	/// Deposit a pallet revive event.
2801	///
2802	/// This method will be called by the EVM to deposit events emitted by the contract.
2803	/// Therefore all events must be contract emitted events.
2804	fn deposit_event(event: Event<T>) {
2805		<frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
2806	}
2807
2808	// Returns Ok with the account that signed the eth transaction.
2809	fn ensure_eth_signed(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
2810		match <T as Config>::RuntimeOrigin::from(origin).into() {
2811			Ok(Origin::EthTransaction(signer)) => Ok(signer),
2812			_ => Err(BadOrigin.into()),
2813		}
2814	}
2815
2816	/// Ensure that the origin is neither a pre-compile nor a contract.
2817	///
2818	/// This enforces EIP-3607.
2819	fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
2820		if DebugSettings::bypass_eip_3607::<T>() {
2821			return Ok(());
2822		}
2823		let Some(address) = origin
2824			.as_system_ref()
2825			.and_then(|o| o.as_signed())
2826			.map(<T::AddressMapper as AddressMapper<T>>::to_address)
2827		else {
2828			return Ok(());
2829		};
2830		if exec::is_precompile::<T, ContractBlob<T>>(&address) ||
2831			<AccountInfo<T>>::is_contract(&address)
2832		{
2833			log::debug!(
2834				target: crate::LOG_TARGET,
2835				"EIP-3607: reject tx as pre-compile or account exist at {address:?}",
2836			);
2837			Err(DispatchError::BadOrigin)
2838		} else {
2839			Ok(())
2840		}
2841	}
2842}
2843
2844/// The address used to call the runtime's pallets dispatchables
2845///
2846/// Note:
2847/// computed with PalletId(*b"py/paddr").into_account_truncating();
2848pub const RUNTIME_PALLETS_ADDR: H160 =
2849	H160(hex_literal::hex!("6d6f646c70792f70616464720000000000000000"));
2850
2851// Set up a global reference to the boolean flag used for the re-entrancy guard.
2852environmental!(executing_contract: bool);
2853
2854sp_api::decl_runtime_apis! {
2855	/// The API used to dry-run contract interactions.
2856	#[api_version(1)]
2857	pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber, Moment> where
2858		AccountId: Codec,
2859		Balance: Codec,
2860		Nonce: Codec,
2861		BlockNumber: Codec,
2862		Moment: Codec,
2863	{
2864		/// Returns the current ETH block.
2865		///
2866		/// This is one block behind the substrate block.
2867		fn eth_block() -> EthBlock;
2868
2869		/// Returns the ETH block hash for the given block number.
2870		fn eth_block_hash(number: U256) -> Option<H256>;
2871
2872		/// The details needed to reconstruct the receipt information offchain.
2873		///
2874		/// # Note
2875		///
2876		/// Each entry corresponds to the appropriate Ethereum transaction in the current block.
2877		fn eth_receipt_data() -> Vec<ReceiptGasInfo>;
2878
2879		/// Returns the block gas limit.
2880		fn block_gas_limit() -> U256;
2881
2882		/// Returns the block gas limit as calculated from the weights.
2883		fn max_extrinsic_weight_in_gas() -> U256;
2884
2885		/// Returns the free balance of the given `[H160]` address, using EVM decimals.
2886		fn balance(address: H160) -> U256;
2887
2888		/// Returns the gas price.
2889		fn gas_price() -> U256;
2890
2891		/// Returns the nonce of the given `[H160]` address.
2892		fn nonce(address: H160) -> Nonce;
2893
2894		/// Perform a call from a specified account to a given contract.
2895		///
2896		/// See [`crate::Pallet::bare_call`].
2897		fn call(
2898			origin: AccountId,
2899			dest: H160,
2900			value: Balance,
2901			gas_limit: Option<Weight>,
2902			storage_deposit_limit: Option<Balance>,
2903			input_data: Vec<u8>,
2904		) -> ContractResult<ExecReturnValue, Balance>;
2905
2906		/// Instantiate a new contract.
2907		///
2908		/// See `[crate::Pallet::bare_instantiate]`.
2909		fn instantiate(
2910			origin: AccountId,
2911			value: Balance,
2912			gas_limit: Option<Weight>,
2913			storage_deposit_limit: Option<Balance>,
2914			code: Code,
2915			data: Vec<u8>,
2916			salt: Option<[u8; 32]>,
2917		) -> ContractResult<InstantiateReturnValue, Balance>;
2918
2919
2920		/// Perform an Ethereum call.
2921		///
2922		/// Deprecated use `v2` version instead.
2923		/// See [`crate::Pallet::dry_run_eth_transact`]
2924		fn eth_transact(tx: GenericTransaction) -> Result<EthTransactInfo<Balance>, EthTransactError>;
2925
2926		/// Perform an Ethereum call.
2927		///
2928		/// See [`crate::Pallet::dry_run_eth_transact`]
2929		fn eth_transact_with_config(
2930			tx: GenericTransaction,
2931			config: DryRunConfig<Moment>,
2932		) -> Result<EthTransactInfo<Balance>, EthTransactError>;
2933
2934		/// Estimates the amount of gas that a transactions requires.
2935		///
2936		/// This function estimates the gas of the transaction according to the same binary search
2937		/// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of
2938		/// 1.5% so that the algorithm terminates early.
2939		fn eth_estimate_gas(
2940			tx: GenericTransaction,
2941			config: DryRunConfig<Moment>
2942		) -> Result<U256, EthTransactError>;
2943
2944		/// Return the pre-dispatch weight booked for the signed Ethereum transaction payload.
2945		fn eth_pre_dispatch_weight(tx: Vec<u8>) -> Result<Weight, EthTransactError>;
2946
2947		/// Upload new code without instantiating a contract from it.
2948		///
2949		/// See [`crate::Pallet::bare_upload_code`].
2950		fn upload_code(
2951			origin: AccountId,
2952			code: Vec<u8>,
2953			storage_deposit_limit: Option<Balance>,
2954		) -> CodeUploadResult<Balance>;
2955
2956		/// Query a given storage key in a given contract.
2957		///
2958		/// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
2959		/// specified account and `Ok(None)` if it doesn't. If the account specified by the address
2960		/// doesn't exist, or doesn't have a contract then `Err` is returned.
2961		fn get_storage(
2962			address: H160,
2963			key: [u8; 32],
2964		) -> GetStorageResult;
2965
2966		/// Query a given variable-sized storage key in a given contract.
2967		///
2968		/// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
2969		/// specified account and `Ok(None)` if it doesn't. If the account specified by the address
2970		/// doesn't exist, or doesn't have a contract then `Err` is returned.
2971		fn get_storage_var_key(
2972			address: H160,
2973			key: Vec<u8>,
2974		) -> GetStorageResult;
2975
2976		/// Traces the execution of an entire block and returns call traces.
2977		///
2978		/// This is intended to be called through `state_call` to replay the block from the
2979		/// parent block.
2980		///
2981		/// See eth-rpc `debug_traceBlockByNumber` for usage.
2982		fn trace_block(
2983			block: Block,
2984			config: TracerType
2985		) -> Vec<(u32, Trace)>;
2986
2987		/// Traces the execution of a specific transaction within a block.
2988		///
2989		/// This is intended to be called through `state_call` to replay the block from the
2990		/// parent hash up to the transaction.
2991		///
2992		/// See eth-rpc `debug_traceTransaction` for usage.
2993		fn trace_tx(
2994			block: Block,
2995			tx_index: u32,
2996			config: TracerType
2997		) -> Option<Trace>;
2998
2999		/// Dry run and return the trace of the given call.
3000		///
3001		/// See eth-rpc `debug_traceCall` for usage.
3002		fn trace_call(tx: GenericTransaction, config: TracerType) -> Result<Trace, EthTransactError>;
3003
3004		/// Dry run and return the trace of the given call with additional configuration.
3005		///
3006		/// Like [`Self::trace_call`], but accepts a [`TracingConfig`] that can carry state
3007		/// overrides and future extensibility. The config must be the **last argument** for
3008		/// backwards compatibility — see [`TracingConfig`] documentation.
3009		fn trace_call_with_config(
3010			tx: GenericTransaction,
3011			tracer_type: TracerType,
3012			config: TracingConfig,
3013		) -> Result<Trace, EthTransactError>;
3014
3015		/// The address of the validator that produced the current block.
3016		fn block_author() -> H160;
3017
3018		/// Get the H160 address associated to this account id
3019		fn address(account_id: AccountId) -> H160;
3020
3021		/// Get the account id associated to this H160 address.
3022		fn account_id(address: H160) -> AccountId;
3023
3024		/// The address used to call the runtime's pallets dispatchables
3025		fn runtime_pallets_address() -> H160;
3026
3027		/// The code at the specified address taking pre-compiles into account.
3028		fn code(address: H160) -> Vec<u8>;
3029
3030		/// Construct the new balance and dust components of this EVM balance.
3031		fn new_balance_with_dust(balance: U256) -> Result<(Balance, u32), BalanceConversionError>;
3032	}
3033}
3034
3035/// This macro wraps substrate's `impl_runtime_apis!` and implements `pallet_revive` runtime APIs
3036/// and other required traits.
3037///
3038/// # Note
3039///
3040/// This also implements [`SetWeightLimit`] for the runtime call.
3041///
3042/// # Parameters
3043/// - `$Runtime`: The runtime type to implement the APIs for.
3044/// - `$Revive`: The name under which revive is declared in `construct_runtime`.
3045/// - `$Executive`: The Executive type of the runtime.
3046/// - `$EthExtra`: Type for additional Ethereum runtime extension.
3047/// - `$($rest:tt)*`: Remaining input to be forwarded to the underlying `impl_runtime_apis!`.
3048#[macro_export]
3049macro_rules! impl_runtime_apis_plus_revive_traits {
3050	($Runtime: ty, $Revive: ident, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
3051
3052		type __ReviveMacroMoment = <<$Runtime as $crate::Config>::Time as $crate::Time>::Moment;
3053
3054		impl $crate::evm::runtime::SetWeightLimit for RuntimeCall {
3055			fn set_weight_limit(&mut self, new_weight_limit: Weight) -> Weight {
3056				use $crate::pallet::Call as ReviveCall;
3057				match self {
3058					Self::$Revive(
3059						ReviveCall::eth_call{ weight_limit, .. } |
3060						ReviveCall::eth_instantiate_with_code{ weight_limit, .. }
3061					) => {
3062						let old = *weight_limit;
3063						*weight_limit = new_weight_limit;
3064						old
3065					},
3066					_ => Weight::default(),
3067				}
3068			}
3069		}
3070
3071		impl_runtime_apis! {
3072			$($rest)*
3073
3074
3075			impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber, __ReviveMacroMoment> for $Runtime
3076			{
3077				fn eth_block() -> $crate::EthBlock {
3078					$crate::Pallet::<Self>::eth_block()
3079				}
3080
3081				fn eth_block_hash(number: $crate::U256) -> Option<$crate::H256> {
3082					$crate::Pallet::<Self>::eth_block_hash_from_number(number)
3083				}
3084
3085				fn eth_receipt_data() -> Vec<$crate::ReceiptGasInfo> {
3086					$crate::Pallet::<Self>::eth_receipt_data()
3087				}
3088
3089				fn balance(address: $crate::H160) -> $crate::U256 {
3090					$crate::Pallet::<Self>::evm_balance(&address)
3091				}
3092
3093				fn block_author() -> $crate::H160 {
3094					$crate::Pallet::<Self>::block_author()
3095				}
3096
3097				fn block_gas_limit() -> $crate::U256 {
3098					$crate::Pallet::<Self>::evm_block_gas_limit()
3099				}
3100
3101				fn max_extrinsic_weight_in_gas() -> $crate::U256 {
3102					$crate::Pallet::<Self>::evm_max_extrinsic_weight_in_gas()
3103				}
3104
3105				fn gas_price() -> $crate::U256 {
3106					$crate::Pallet::<Self>::evm_base_fee()
3107				}
3108
3109				fn nonce(address: $crate::H160) -> Nonce {
3110					use $crate::AddressMapper;
3111					let account = <Self as $crate::Config>::AddressMapper::to_account_id(&address);
3112					$crate::frame_system::Pallet::<Self>::account_nonce(account)
3113				}
3114
3115				fn address(account_id: AccountId) -> $crate::H160 {
3116					use $crate::AddressMapper;
3117					<Self as $crate::Config>::AddressMapper::to_address(&account_id)
3118				}
3119
3120				fn eth_transact(
3121					tx: $crate::evm::GenericTransaction,
3122				) -> Result<$crate::EthTransactInfo<Balance>, $crate::EthTransactError> {
3123					use $crate::{
3124						codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
3125						sp_runtime::traits::TransactionExtension,
3126						sp_runtime::traits::Block as BlockT
3127					};
3128					$crate::Pallet::<Self>::dry_run_eth_transact(tx, Default::default())
3129				}
3130
3131				fn eth_transact_with_config(
3132					tx: $crate::evm::GenericTransaction,
3133					config: $crate::DryRunConfig<__ReviveMacroMoment>,
3134				) -> Result<$crate::EthTransactInfo<Balance>, $crate::EthTransactError> {
3135					use $crate::{
3136						codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
3137						sp_runtime::traits::TransactionExtension,
3138						sp_runtime::traits::Block as BlockT
3139					};
3140					$crate::Pallet::<Self>::dry_run_eth_transact(tx, config)
3141				}
3142
3143				fn eth_estimate_gas(
3144					tx: $crate::evm::GenericTransaction,
3145					config: $crate::DryRunConfig<__ReviveMacroMoment>,
3146				) -> Result<$crate::U256, $crate::EthTransactError>  {
3147					use $crate::{
3148						codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
3149						sp_runtime::traits::TransactionExtension,
3150						sp_runtime::traits::Block as BlockT
3151					};
3152					$crate::Pallet::<Self>::eth_estimate_gas(tx, config)
3153				}
3154
3155				fn eth_pre_dispatch_weight(
3156					tx: Vec<u8>,
3157				) -> Result<$crate::Weight, $crate::EthTransactError> {
3158					$crate::Pallet::<Self>::eth_pre_dispatch_weight(tx)
3159				}
3160
3161				fn call(
3162					origin: AccountId,
3163					dest: $crate::H160,
3164					value: Balance,
3165					weight_limit: Option<$crate::Weight>,
3166					storage_deposit_limit: Option<Balance>,
3167					input_data: Vec<u8>,
3168				) -> $crate::ContractResult<$crate::ExecReturnValue, Balance> {
3169					use $crate::frame_support::traits::Get;
3170					let blockweights: $crate::BlockWeights =
3171						<Self as $crate::frame_system::Config>::BlockWeights::get();
3172
3173					$crate::Pallet::<Self>::prepare_dry_run(&origin);
3174					$crate::Pallet::<Self>::bare_call(
3175						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin),
3176						dest,
3177						$crate::Pallet::<Self>::convert_native_to_evm(value),
3178						$crate::TransactionLimits::WeightAndDeposit {
3179							weight_limit: weight_limit.unwrap_or(blockweights.max_block),
3180							deposit_limit: storage_deposit_limit.unwrap_or(u128::MAX),
3181						},
3182						input_data,
3183						&$crate::ExecConfig::new_substrate_tx().with_dry_run(Default::default()),
3184					)
3185				}
3186
3187				fn instantiate(
3188					origin: AccountId,
3189					value: Balance,
3190					weight_limit: Option<$crate::Weight>,
3191					storage_deposit_limit: Option<Balance>,
3192					code: $crate::Code,
3193					data: Vec<u8>,
3194					salt: Option<[u8; 32]>,
3195				) -> $crate::ContractResult<$crate::InstantiateReturnValue, Balance> {
3196					use $crate::frame_support::traits::Get;
3197					let blockweights: $crate::BlockWeights =
3198						<Self as $crate::frame_system::Config>::BlockWeights::get();
3199
3200					$crate::Pallet::<Self>::prepare_dry_run(&origin);
3201					$crate::Pallet::<Self>::bare_instantiate(
3202						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin),
3203						$crate::Pallet::<Self>::convert_native_to_evm(value),
3204						$crate::TransactionLimits::WeightAndDeposit {
3205							weight_limit: weight_limit.unwrap_or(blockweights.max_block),
3206							deposit_limit: storage_deposit_limit.unwrap_or(u128::MAX),
3207						},
3208						code,
3209						data,
3210						salt,
3211						&$crate::ExecConfig::new_substrate_tx().with_dry_run(Default::default()),
3212					)
3213				}
3214
3215				fn upload_code(
3216					origin: AccountId,
3217					code: Vec<u8>,
3218					storage_deposit_limit: Option<Balance>,
3219				) -> $crate::CodeUploadResult<Balance> {
3220					let origin =
3221						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(origin);
3222					$crate::Pallet::<Self>::bare_upload_code(
3223						origin,
3224						code,
3225						storage_deposit_limit.unwrap_or(u128::MAX),
3226					)
3227				}
3228
3229				fn get_storage_var_key(
3230					address: $crate::H160,
3231					key: Vec<u8>,
3232				) -> $crate::GetStorageResult {
3233					$crate::Pallet::<Self>::get_storage_var_key(address, key)
3234				}
3235
3236				fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
3237					$crate::Pallet::<Self>::get_storage(address, key)
3238				}
3239
3240				fn trace_block(
3241					block: Block,
3242					tracer_type: $crate::evm::TracerType,
3243				) -> Vec<(u32, $crate::evm::Trace)> {
3244					use $crate::{sp_runtime::traits::Block, tracing::trace};
3245
3246					if matches!(tracer_type, $crate::evm::TracerType::ExecutionTracer(_)) &&
3247						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
3248					{
3249						return Default::default()
3250					}
3251
3252					let mut traces = vec![];
3253					let (header, extrinsics) = block.deconstruct();
3254					<$Executive>::initialize_block(&header);
3255					for (index, ext) in extrinsics.into_iter().enumerate() {
3256						let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type.clone());
3257						let t = tracer.as_tracing();
3258						let _ = trace(t, || <$Executive>::apply_extrinsic(ext));
3259
3260						if let Some(tx_trace) = tracer.collect_trace() {
3261							traces.push((index as u32, tx_trace));
3262						}
3263					}
3264
3265					traces
3266				}
3267
3268				fn trace_tx(
3269					block: Block,
3270					tx_index: u32,
3271					tracer_type: $crate::evm::TracerType,
3272				) -> Option<$crate::evm::Trace> {
3273					use $crate::{sp_runtime::traits::Block, tracing::trace};
3274
3275					if matches!(tracer_type, $crate::evm::TracerType::ExecutionTracer(_)) &&
3276						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
3277					{
3278						return None
3279					}
3280
3281					let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type);
3282					let (header, extrinsics) = block.deconstruct();
3283
3284					<$Executive>::initialize_block(&header);
3285					for (index, ext) in extrinsics.into_iter().enumerate() {
3286						if index as u32 == tx_index {
3287							let t = tracer.as_tracing();
3288							let _ = trace(t, || <$Executive>::apply_extrinsic(ext));
3289							break;
3290						} else {
3291							let _ = <$Executive>::apply_extrinsic(ext);
3292						}
3293					}
3294
3295					tracer.collect_trace()
3296				}
3297
3298				fn trace_call(
3299					tx: $crate::evm::GenericTransaction,
3300					tracer_type: $crate::evm::TracerType,
3301				) -> Result<$crate::evm::Trace, $crate::EthTransactError> {
3302					use $crate::tracing::trace;
3303
3304					if matches!(tracer_type, $crate::evm::TracerType::ExecutionTracer(_)) &&
3305						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
3306					{
3307						return Err($crate::EthTransactError::Message("Execution Tracing is disabled".into()))
3308					}
3309
3310					let mut tracer = $crate::Pallet::<Self>::evm_tracer(tracer_type.clone());
3311					let t = tracer.as_tracing();
3312
3313					t.watch_address(&tx.from.unwrap_or_default());
3314					t.watch_address(&$crate::Pallet::<Self>::block_author());
3315					let result = trace(t, || Self::eth_transact(tx));
3316
3317					if let Some(trace) = tracer.collect_trace() {
3318						Ok(trace)
3319					} else if let Err(err) = result {
3320						Err(err)
3321					} else {
3322						Ok($crate::Pallet::<Self>::evm_tracer(tracer_type).empty_trace())
3323					}
3324				}
3325
3326				fn trace_call_with_config(
3327					tx: $crate::evm::GenericTransaction,
3328					tracer_type: $crate::evm::TracerType,
3329					config: $crate::evm::TracingConfig,
3330				) -> Result<$crate::evm::Trace, $crate::EthTransactError> {
3331					let $crate::evm::TracingConfig { state_overrides } = config;
3332
3333					if let Some(overrides) = state_overrides {
3334						$crate::state_overrides::apply_state_overrides::<Runtime>(overrides)?;
3335					}
3336
3337					Self::trace_call(tx, tracer_type)
3338				}
3339
3340				fn runtime_pallets_address() -> $crate::H160 {
3341					$crate::RUNTIME_PALLETS_ADDR
3342				}
3343
3344				fn code(address: $crate::H160) -> Vec<u8> {
3345					$crate::Pallet::<Self>::code(&address)
3346				}
3347
3348				fn account_id(address: $crate::H160) -> AccountId {
3349					use $crate::AddressMapper;
3350					<Self as $crate::Config>::AddressMapper::to_account_id(&address)
3351				}
3352
3353				fn new_balance_with_dust(balance: $crate::U256) -> Result<(Balance, u32), $crate::BalanceConversionError> {
3354					$crate::Pallet::<Self>::new_balance_with_dust(balance)
3355				}
3356			}
3357		}
3358	};
3359}