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