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;
24mod address;
25mod benchmarking;
26mod exec;
27mod gas;
28mod limits;
29mod primitives;
30mod pure_precompiles;
31mod storage;
32mod transient_storage;
33mod wasm;
34
35#[cfg(test)]
36mod tests;
37
38pub mod chain_extension;
39pub mod evm;
40pub mod test_utils;
41pub mod tracing;
42pub mod weights;
43
44use crate::{
45	evm::{runtime::GAS_PRICE, CallTrace, GasEncoder, GenericTransaction, TracerConfig},
46	exec::{AccountIdOf, ExecError, Executable, Key, Stack as ExecStack},
47	gas::GasMeter,
48	storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
49	wasm::{CodeInfo, RuntimeCosts, WasmBlob},
50};
51use alloc::{boxed::Box, format, vec};
52use codec::{Codec, Decode, Encode};
53use environmental::*;
54use frame_support::{
55	dispatch::{
56		DispatchErrorWithPostInfo, DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, Pays,
57		PostDispatchInfo, RawOrigin,
58	},
59	ensure,
60	pallet_prelude::DispatchClass,
61	traits::{
62		fungible::{Inspect, Mutate, MutateHold},
63		tokens::{Fortitude::Polite, Preservation::Preserve},
64		ConstU32, ConstU64, Contains, EnsureOrigin, Get, IsType, OriginTrait, Time,
65	},
66	weights::{Weight, WeightMeter},
67	BoundedVec, RuntimeDebugNoBound,
68};
69use frame_system::{
70	ensure_signed,
71	pallet_prelude::{BlockNumberFor, OriginFor},
72	Pallet as System,
73};
74use scale_info::TypeInfo;
75use sp_core::{H160, H256, U256};
76use sp_runtime::{
77	traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating, Zero},
78	AccountId32, DispatchError,
79};
80
81pub use crate::{
82	address::{create1, create2, AccountId32Mapper, AddressMapper},
83	exec::{MomentOf, Origin},
84	pallet::*,
85};
86pub use primitives::*;
87pub use weights::WeightInfo;
88
89#[cfg(doc)]
90pub use crate::wasm::SyscallDoc;
91
92type TrieId = BoundedVec<u8, ConstU32<128>>;
93type BalanceOf<T> =
94	<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
95type CodeVec = BoundedVec<u8, ConstU32<{ limits::code::BLOB_BYTES }>>;
96type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
97
98/// Used as a sentinel value when reading and writing contract memory.
99///
100/// It is usually used to signal `None` to a contract when only a primitive is allowed
101/// and we don't want to go through encoding a full Rust type. Using `u32::Max` is a safe
102/// sentinel because contracts are never allowed to use such a large amount of resources
103/// that this value makes sense for a memory location or length.
104const SENTINEL: u32 = u32::MAX;
105
106/// The target that is used for the log output emitted by this crate.
107///
108/// Hence you can use this target to selectively increase the log level for this crate.
109///
110/// Example: `RUST_LOG=runtime::revive=debug my_code --dev`
111const LOG_TARGET: &str = "runtime::revive";
112
113#[frame_support::pallet]
114pub mod pallet {
115	use super::*;
116	use frame_support::{pallet_prelude::*, traits::FindAuthor};
117	use frame_system::pallet_prelude::*;
118	use sp_core::U256;
119	use sp_runtime::Perbill;
120
121	/// The in-code storage version.
122	pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
123
124	#[pallet::pallet]
125	#[pallet::storage_version(STORAGE_VERSION)]
126	pub struct Pallet<T>(_);
127
128	#[pallet::config(with_default)]
129	pub trait Config: frame_system::Config {
130		/// The time implementation used to supply timestamps to contracts through `seal_now`.
131		type Time: Time;
132
133		/// The fungible in which fees are paid and contract balances are held.
134		#[pallet::no_default]
135		type Currency: Inspect<Self::AccountId>
136			+ Mutate<Self::AccountId>
137			+ MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>;
138
139		/// The overarching event type.
140		#[pallet::no_default_bounds]
141		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
142
143		/// The overarching call type.
144		#[pallet::no_default_bounds]
145		type RuntimeCall: Parameter
146			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
147			+ GetDispatchInfo;
148
149		/// Overarching hold reason.
150		#[pallet::no_default_bounds]
151		type RuntimeHoldReason: From<HoldReason>;
152
153		/// Filter that is applied to calls dispatched by contracts.
154		///
155		/// Use this filter to control which dispatchables are callable by contracts.
156		/// This is applied in **addition** to [`frame_system::Config::BaseCallFilter`].
157		/// It is recommended to treat this as a whitelist.
158		///
159		/// # Stability
160		///
161		/// The runtime **must** make sure that all dispatchables that are callable by
162		/// contracts remain stable. In addition [`Self::RuntimeCall`] itself must remain stable.
163		/// This means that no existing variants are allowed to switch their positions.
164		///
165		/// # Note
166		///
167		/// Note that dispatchables that are called via contracts do not spawn their
168		/// own wasm instance for each call (as opposed to when called via a transaction).
169		/// Therefore please make sure to be restrictive about which dispatchables are allowed
170		/// in order to not introduce a new DoS vector like memory allocation patterns that can
171		/// be exploited to drive the runtime into a panic.
172		///
173		/// This filter does not apply to XCM transact calls. To impose restrictions on XCM transact
174		/// calls, you must configure them separately within the XCM pallet itself.
175		#[pallet::no_default_bounds]
176		type CallFilter: Contains<<Self as frame_system::Config>::RuntimeCall>;
177
178		/// Used to answer contracts' queries regarding the current weight price. This is **not**
179		/// used to calculate the actual fee and is only for informational purposes.
180		#[pallet::no_default_bounds]
181		type WeightPrice: Convert<Weight, BalanceOf<Self>>;
182
183		/// Describes the weights of the dispatchables of this module and is also used to
184		/// construct a default cost schedule.
185		type WeightInfo: WeightInfo;
186
187		/// Type that allows the runtime authors to add new host functions for a contract to call.
188		#[pallet::no_default_bounds]
189		type ChainExtension: chain_extension::ChainExtension<Self> + Default;
190
191		/// Find the author of the current block.
192		type FindAuthor: FindAuthor<Self::AccountId>;
193
194		/// The amount of balance a caller has to pay for each byte of storage.
195		///
196		/// # Note
197		///
198		/// It is safe to change this value on a live chain as all refunds are pro rata.
199		#[pallet::constant]
200		#[pallet::no_default_bounds]
201		type DepositPerByte: Get<BalanceOf<Self>>;
202
203		/// The amount of balance a caller has to pay for each storage item.
204		///
205		/// # Note
206		///
207		/// It is safe to change this value on a live chain as all refunds are pro rata.
208		#[pallet::constant]
209		#[pallet::no_default_bounds]
210		type DepositPerItem: Get<BalanceOf<Self>>;
211
212		/// The percentage of the storage deposit that should be held for using a code hash.
213		/// Instantiating a contract, protects the code from being removed. In order to prevent
214		/// abuse these actions are protected with a percentage of the code deposit.
215		#[pallet::constant]
216		type CodeHashLockupDepositPercent: Get<Perbill>;
217
218		/// Use either valid type is [`address::AccountId32Mapper`] or [`address::H160Mapper`].
219		#[pallet::no_default]
220		type AddressMapper: AddressMapper<Self>;
221
222		/// Make contract callable functions marked as `#[unstable]` available.
223		///
224		/// Contracts that use `#[unstable]` functions won't be able to be uploaded unless
225		/// this is set to `true`. This is only meant for testnets and dev nodes in order to
226		/// experiment with new features.
227		///
228		/// # Warning
229		///
230		/// Do **not** set to `true` on productions chains.
231		#[pallet::constant]
232		type UnsafeUnstableInterface: Get<bool>;
233
234		/// Origin allowed to upload code.
235		///
236		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to upload contract
237		/// code.
238		#[pallet::no_default_bounds]
239		type UploadOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
240
241		/// Origin allowed to instantiate code.
242		///
243		/// # Note
244		///
245		/// This is not enforced when a contract instantiates another contract. The
246		/// [`Self::UploadOrigin`] should make sure that no code is deployed that does unwanted
247		/// instantiations.
248		///
249		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to instantiate
250		/// contract code.
251		#[pallet::no_default_bounds]
252		type InstantiateOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
253
254		/// A type that exposes XCM APIs, allowing contracts to interact with other parachains, and
255		/// execute XCM programs.
256		#[pallet::no_default_bounds]
257		type Xcm: xcm_builder::Controller<
258			OriginFor<Self>,
259			<Self as frame_system::Config>::RuntimeCall,
260			BlockNumberFor<Self>,
261		>;
262
263		/// The amount of memory in bytes that parachain nodes a lot to the runtime.
264		///
265		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
266		/// memory to support this pallet if set to the correct value.
267		type RuntimeMemory: Get<u32>;
268
269		/// The amount of memory in bytes that relay chain validators a lot to the PoV.
270		///
271		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
272		/// memory to support this pallet if set to the correct value.
273		///
274		/// This value is usually higher than [`Self::RuntimeMemory`] to account for the fact
275		/// that validators have to hold all storage items in PvF memory.
276		type PVFMemory: Get<u32>;
277
278		/// The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID.
279		///
280		/// This is a unique identifier assigned to each blockchain network,
281		/// preventing replay attacks.
282		#[pallet::constant]
283		type ChainId: Get<u64>;
284
285		/// The ratio between the decimal representation of the native token and the ETH token.
286		#[pallet::constant]
287		type NativeToEthRatio: Get<u32>;
288
289		/// Encode and decode Ethereum gas values.
290		/// Only valid value is `()`. See [`GasEncoder`].
291		#[pallet::no_default_bounds]
292		type EthGasEncoder: GasEncoder<BalanceOf<Self>>;
293	}
294
295	/// Container for different types that implement [`DefaultConfig`]` of this pallet.
296	pub mod config_preludes {
297		use super::*;
298		use frame_support::{
299			derive_impl,
300			traits::{ConstBool, ConstU32},
301		};
302		use frame_system::EnsureSigned;
303		use sp_core::parameter_types;
304
305		type AccountId = sp_runtime::AccountId32;
306		type Balance = u64;
307		const UNITS: Balance = 10_000_000_000;
308		const CENTS: Balance = UNITS / 100;
309
310		pub const fn deposit(items: u32, bytes: u32) -> Balance {
311			items as Balance * 1 * CENTS + (bytes as Balance) * 1 * CENTS
312		}
313
314		parameter_types! {
315			pub const DepositPerItem: Balance = deposit(1, 0);
316			pub const DepositPerByte: Balance = deposit(0, 1);
317			pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
318		}
319
320		/// A type providing default configurations for this pallet in testing environment.
321		pub struct TestDefaultConfig;
322
323		impl Time for TestDefaultConfig {
324			type Moment = u64;
325			fn now() -> Self::Moment {
326				unimplemented!("No default `now` implementation in `TestDefaultConfig` provide a custom `T::Time` type.")
327			}
328		}
329
330		impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
331			fn convert(w: Weight) -> T {
332				w.ref_time().into()
333			}
334		}
335
336		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
337		impl frame_system::DefaultConfig for TestDefaultConfig {}
338
339		#[frame_support::register_default_impl(TestDefaultConfig)]
340		impl DefaultConfig for TestDefaultConfig {
341			#[inject_runtime_type]
342			type RuntimeEvent = ();
343
344			#[inject_runtime_type]
345			type RuntimeHoldReason = ();
346
347			#[inject_runtime_type]
348			type RuntimeCall = ();
349			type CallFilter = ();
350			type ChainExtension = ();
351			type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
352			type DepositPerByte = DepositPerByte;
353			type DepositPerItem = DepositPerItem;
354			type Time = Self;
355			type UnsafeUnstableInterface = ConstBool<true>;
356			type UploadOrigin = EnsureSigned<AccountId>;
357			type InstantiateOrigin = EnsureSigned<AccountId>;
358			type WeightInfo = ();
359			type WeightPrice = Self;
360			type Xcm = ();
361			type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
362			type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
363			type ChainId = ConstU64<0>;
364			type NativeToEthRatio = ConstU32<1>;
365			type EthGasEncoder = ();
366			type FindAuthor = ();
367		}
368	}
369
370	#[pallet::event]
371	pub enum Event<T: Config> {
372		/// A custom event emitted by the contract.
373		ContractEmitted {
374			/// The contract that emitted the event.
375			contract: H160,
376			/// Data supplied by the contract. Metadata generated during contract compilation
377			/// is needed to decode it.
378			data: Vec<u8>,
379			/// A list of topics used to index the event.
380			/// Number of topics is capped by [`limits::NUM_EVENT_TOPICS`].
381			topics: Vec<H256>,
382		},
383	}
384
385	#[pallet::error]
386	pub enum Error<T> {
387		/// Invalid schedule supplied, e.g. with zero weight of a basic operation.
388		InvalidSchedule,
389		/// Invalid combination of flags supplied to `seal_call` or `seal_delegate_call`.
390		InvalidCallFlags,
391		/// The executed contract exhausted its gas limit.
392		OutOfGas,
393		/// Performing the requested transfer failed. Probably because there isn't enough
394		/// free balance in the sender's account.
395		TransferFailed,
396		/// Performing a call was denied because the calling depth reached the limit
397		/// of what is specified in the schedule.
398		MaxCallDepthReached,
399		/// No contract was found at the specified address.
400		ContractNotFound,
401		/// No code could be found at the supplied code hash.
402		CodeNotFound,
403		/// No code info could be found at the supplied code hash.
404		CodeInfoNotFound,
405		/// A buffer outside of sandbox memory was passed to a contract API function.
406		OutOfBounds,
407		/// Input passed to a contract API function failed to decode as expected type.
408		DecodingFailed,
409		/// Contract trapped during execution.
410		ContractTrapped,
411		/// The size defined in `T::MaxValueSize` was exceeded.
412		ValueTooLarge,
413		/// Termination of a contract is not allowed while the contract is already
414		/// on the call stack. Can be triggered by `seal_terminate`.
415		TerminatedWhileReentrant,
416		/// `seal_call` forwarded this contracts input. It therefore is no longer available.
417		InputForwarded,
418		/// The amount of topics passed to `seal_deposit_events` exceeds the limit.
419		TooManyTopics,
420		/// The chain does not provide a chain extension. Calling the chain extension results
421		/// in this error. Note that this usually  shouldn't happen as deploying such contracts
422		/// is rejected.
423		NoChainExtension,
424		/// Failed to decode the XCM program.
425		XCMDecodeFailed,
426		/// A contract with the same AccountId already exists.
427		DuplicateContract,
428		/// A contract self destructed in its constructor.
429		///
430		/// This can be triggered by a call to `seal_terminate`.
431		TerminatedInConstructor,
432		/// A call tried to invoke a contract that is flagged as non-reentrant.
433		ReentranceDenied,
434		/// A contract called into the runtime which then called back into this pallet.
435		ReenteredPallet,
436		/// A contract attempted to invoke a state modifying API while being in read-only mode.
437		StateChangeDenied,
438		/// Origin doesn't have enough balance to pay the required storage deposits.
439		StorageDepositNotEnoughFunds,
440		/// More storage was created than allowed by the storage deposit limit.
441		StorageDepositLimitExhausted,
442		/// Code removal was denied because the code is still in use by at least one contract.
443		CodeInUse,
444		/// The contract ran to completion but decided to revert its storage changes.
445		/// Please note that this error is only returned from extrinsics. When called directly
446		/// or via RPC an `Ok` will be returned. In this case the caller needs to inspect the flags
447		/// to determine whether a reversion has taken place.
448		ContractReverted,
449		/// The contract failed to compile or is missing the correct entry points.
450		///
451		/// A more detailed error can be found on the node console if debug messages are enabled
452		/// by supplying `-lruntime::revive=debug`.
453		CodeRejected,
454		/// The code blob supplied is larger than [`limits::code::BLOB_BYTES`].
455		BlobTooLarge,
456		/// The static memory consumption of the blob will be larger than
457		/// [`limits::code::STATIC_MEMORY_BYTES`].
458		StaticMemoryTooLarge,
459		/// The program contains a basic block that is larger than allowed.
460		BasicBlockTooLarge,
461		/// The program contains an invalid instruction.
462		InvalidInstruction,
463		/// The contract has reached its maximum number of delegate dependencies.
464		MaxDelegateDependenciesReached,
465		/// The dependency was not found in the contract's delegate dependencies.
466		DelegateDependencyNotFound,
467		/// The contract already depends on the given delegate dependency.
468		DelegateDependencyAlreadyExists,
469		/// Can not add a delegate dependency to the code hash of the contract itself.
470		CannotAddSelfAsDelegateDependency,
471		/// Can not add more data to transient storage.
472		OutOfTransientStorage,
473		/// The contract tried to call a syscall which does not exist (at its current api level).
474		InvalidSyscall,
475		/// Invalid storage flags were passed to one of the storage syscalls.
476		InvalidStorageFlags,
477		/// PolkaVM failed during code execution. Probably due to a malformed program.
478		ExecutionFailed,
479		/// Failed to convert a U256 to a Balance.
480		BalanceConversionFailed,
481		/// Failed to convert an EVM balance to a native balance.
482		DecimalPrecisionLoss,
483		/// Immutable data can only be set during deploys and only be read during calls.
484		/// Additionally, it is only valid to set the data once and it must not be empty.
485		InvalidImmutableAccess,
486		/// An `AccountID32` account tried to interact with the pallet without having a mapping.
487		///
488		/// Call [`Pallet::map_account`] in order to create a mapping for the account.
489		AccountUnmapped,
490		/// Tried to map an account that is already mapped.
491		AccountAlreadyMapped,
492		/// The transaction used to dry-run a contract is invalid.
493		InvalidGenericTransaction,
494		/// The refcount of a code either over or underflowed.
495		RefcountOverOrUnderflow,
496		/// Unsupported precompile address
497		UnsupportedPrecompileAddress,
498		/// Precompile Error
499		PrecompileFailure,
500	}
501
502	/// A reason for the pallet contracts placing a hold on funds.
503	#[pallet::composite_enum]
504	pub enum HoldReason {
505		/// The Pallet has reserved it for storing code on-chain.
506		CodeUploadDepositReserve,
507		/// The Pallet has reserved it for storage deposit.
508		StorageDepositReserve,
509		/// Deposit for creating an address mapping in [`OriginalAccount`].
510		AddressMapping,
511	}
512
513	/// A mapping from a contract's code hash to its code.
514	#[pallet::storage]
515	pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, CodeVec>;
516
517	/// A mapping from a contract's code hash to its code info.
518	#[pallet::storage]
519	pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
520
521	/// The code associated with a given account.
522	#[pallet::storage]
523	pub(crate) type ContractInfoOf<T: Config> = StorageMap<_, Identity, H160, ContractInfo<T>>;
524
525	/// The immutable data associated with a given account.
526	#[pallet::storage]
527	pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
528
529	/// Evicted contracts that await child trie deletion.
530	///
531	/// Child trie deletion is a heavy operation depending on the amount of storage items
532	/// stored in said trie. Therefore this operation is performed lazily in `on_idle`.
533	#[pallet::storage]
534	pub(crate) type DeletionQueue<T: Config> = StorageMap<_, Twox64Concat, u32, TrieId>;
535
536	/// A pair of monotonic counters used to track the latest contract marked for deletion
537	/// and the latest deleted contract in queue.
538	#[pallet::storage]
539	pub(crate) type DeletionQueueCounter<T: Config> =
540		StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
541
542	/// Map a Ethereum address to its original `AccountId32`.
543	///
544	/// When deriving a `H160` from an `AccountId32` we use a hash function. In order to
545	/// reconstruct the original account we need to store the reverse mapping here.
546	/// Register your `AccountId32` using [`Pallet::map_account`] in order to
547	/// use it with this pallet.
548	#[pallet::storage]
549	pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
550
551	#[pallet::hooks]
552	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
553		fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
554			let mut meter = WeightMeter::with_limit(limit);
555			ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
556			meter.consumed()
557		}
558
559		fn integrity_test() {
560			use limits::code::STATIC_MEMORY_BYTES;
561
562			// The memory available in the block building runtime
563			let max_runtime_mem: u32 = T::RuntimeMemory::get();
564			// The root frame is not accounted in CALL_STACK_DEPTH
565			let max_call_depth =
566				limits::CALL_STACK_DEPTH.checked_add(1).expect("CallStack size is too big");
567			// Transient storage uses a BTreeMap, which has overhead compared to the raw size of
568			// key-value data. To ensure safety, a margin of 2x the raw key-value size is used.
569			let max_transient_storage_size = limits::TRANSIENT_STORAGE_BYTES
570				.checked_mul(2)
571				.expect("MaxTransientStorageSize is too large");
572
573			// We only allow 50% of the runtime memory to be utilized by the contracts call
574			// stack, keeping the rest for other facilities, such as PoV, etc.
575			const TOTAL_MEMORY_DEVIDER: u32 = 2;
576
577			// The inefficiencies of the freeing-bump allocator
578			// being used in the client for the runtime memory allocations, could lead to possible
579			// memory allocations grow up to `x4` times in some extreme cases.
580			const MEMORY_ALLOCATOR_INEFFICENCY_DEVIDER: u32 = 4;
581
582			// Check that the configured `STATIC_MEMORY_BYTES` fits into runtime memory.
583			//
584			// `STATIC_MEMORY_BYTES` is the amount of memory that a contract can consume
585			// in memory and is enforced at upload time.
586			//
587			// Dynamic allocations are not available, yet. Hence are not taken into consideration
588			// here.
589			let static_memory_limit = max_runtime_mem
590				.saturating_div(TOTAL_MEMORY_DEVIDER)
591				.saturating_sub(max_transient_storage_size)
592				.saturating_div(max_call_depth)
593				.saturating_sub(STATIC_MEMORY_BYTES)
594				.saturating_div(MEMORY_ALLOCATOR_INEFFICENCY_DEVIDER);
595
596			assert!(
597				STATIC_MEMORY_BYTES < static_memory_limit,
598				"Given `CallStack` height {:?}, `STATIC_MEMORY_LIMIT` should be set less than {:?} \
599				 (current value is {:?}), to avoid possible runtime oom issues.",
600				max_call_depth,
601				static_memory_limit,
602				STATIC_MEMORY_BYTES,
603			);
604
605			// Validators are configured to be able to use more memory than block builders. This is
606			// because in addition to `max_runtime_mem` they need to hold additional data in
607			// memory: PoV in multiple copies (1x encoded + 2x decoded) and all storage which
608			// includes emitted events. The assumption is that storage/events size
609			// can be a maximum of half of the validator runtime memory - max_runtime_mem.
610			let max_block_ref_time = T::BlockWeights::get()
611				.get(DispatchClass::Normal)
612				.max_total
613				.unwrap_or_else(|| T::BlockWeights::get().max_block)
614				.ref_time();
615			let max_payload_size = limits::PAYLOAD_BYTES;
616			let max_key_size =
617				Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
618					.expect("Key of maximal size shall be created")
619					.hash()
620					.len() as u32;
621
622			let max_immutable_key_size = T::AccountId::max_encoded_len() as u32;
623			let max_immutable_size: u32 = ((max_block_ref_time /
624				(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetImmutableData(
625					limits::IMMUTABLE_BYTES,
626				))
627				.ref_time()))
628			.saturating_mul(limits::IMMUTABLE_BYTES.saturating_add(max_immutable_key_size) as u64))
629			.try_into()
630			.expect("Immutable data size too big");
631
632			// We can use storage to store items using the available block ref_time with the
633			// `set_storage` host function.
634			let max_storage_size: u32 = ((max_block_ref_time /
635				(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
636					new_bytes: max_payload_size,
637					old_bytes: 0,
638				})
639				.ref_time()))
640			.saturating_mul(max_payload_size.saturating_add(max_key_size) as u64))
641			.saturating_add(max_immutable_size.into())
642			.try_into()
643			.expect("Storage size too big");
644
645			let max_pvf_mem: u32 = T::PVFMemory::get();
646			let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
647
648			assert!(
649				max_storage_size < storage_size_limit,
650				"Maximal storage size {} exceeds the storage limit {}",
651				max_storage_size,
652				storage_size_limit
653			);
654
655			// We can use storage to store events using the available block ref_time with the
656			// `deposit_event` host function. The overhead of stored events, which is around 100B,
657			// is not taken into account to simplify calculations, as it does not change much.
658			let max_events_size: u32 = ((max_block_ref_time /
659				(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
660					num_topic: 0,
661					len: max_payload_size,
662				})
663				.saturating_add(<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::HostFn))
664				.ref_time()))
665			.saturating_mul(max_payload_size as u64))
666			.try_into()
667			.expect("Events size too big");
668
669			assert!(
670				max_events_size < storage_size_limit,
671				"Maximal events size {} exceeds the events limit {}",
672				max_events_size,
673				storage_size_limit
674			);
675		}
676	}
677
678	#[pallet::call]
679	impl<T: Config> Pallet<T>
680	where
681		BalanceOf<T>: Into<U256> + TryFrom<U256>,
682		MomentOf<T>: Into<U256>,
683		T::Hash: frame_support::traits::IsType<H256>,
684	{
685		/// A raw EVM transaction, typically dispatched by an Ethereum JSON-RPC server.
686		///
687		/// # Parameters
688		///
689		/// * `payload`: The encoded [`crate::evm::TransactionSigned`].
690		/// * `gas_limit`: The gas limit enforced during contract execution.
691		/// * `storage_deposit_limit`: The maximum balance that can be charged to the caller for
692		///   storage usage.
693		///
694		/// # Note
695		///
696		/// This call cannot be dispatched directly; attempting to do so will result in a failed
697		/// transaction. It serves as a wrapper for an Ethereum transaction. When submitted, the
698		/// runtime converts it into a [`sp_runtime::generic::CheckedExtrinsic`] by recovering the
699		/// signer and validating the transaction.
700		#[allow(unused_variables)]
701		#[pallet::call_index(0)]
702		#[pallet::weight(Weight::MAX)]
703		pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
704			Err(frame_system::Error::CallFiltered::<T>.into())
705		}
706
707		/// Makes a call to an account, optionally transferring some balance.
708		///
709		/// # Parameters
710		///
711		/// * `dest`: Address of the contract to call.
712		/// * `value`: The balance to transfer from the `origin` to `dest`.
713		/// * `gas_limit`: The gas limit enforced when executing the constructor.
714		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the
715		///   caller to pay for the storage consumed.
716		/// * `data`: The input data to pass to the contract.
717		///
718		/// * If the account is a smart-contract account, the associated code will be
719		/// executed and any value will be transferred.
720		/// * If the account is a regular account, any value will be transferred.
721		/// * If no account exists and the call value is not less than `existential_deposit`,
722		/// a regular account will be created and any value will be transferred.
723		#[pallet::call_index(1)]
724		#[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))]
725		pub fn call(
726			origin: OriginFor<T>,
727			dest: H160,
728			#[pallet::compact] value: BalanceOf<T>,
729			gas_limit: Weight,
730			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
731			data: Vec<u8>,
732		) -> DispatchResultWithPostInfo {
733			let mut output = Self::bare_call(
734				origin,
735				dest,
736				value,
737				gas_limit,
738				DepositLimit::Balance(storage_deposit_limit),
739				data,
740			);
741
742			if let Ok(return_value) = &output.result {
743				if return_value.did_revert() {
744					output.result = Err(<Error<T>>::ContractReverted.into());
745				}
746			}
747			dispatch_result(output.result, output.gas_consumed, T::WeightInfo::call())
748		}
749
750		/// Instantiates a contract from a previously deployed wasm binary.
751		///
752		/// This function is identical to [`Self::instantiate_with_code`] but without the
753		/// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary
754		/// must be supplied.
755		#[pallet::call_index(2)]
756		#[pallet::weight(
757			T::WeightInfo::instantiate(data.len() as u32).saturating_add(*gas_limit)
758		)]
759		pub fn instantiate(
760			origin: OriginFor<T>,
761			#[pallet::compact] value: BalanceOf<T>,
762			gas_limit: Weight,
763			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
764			code_hash: sp_core::H256,
765			data: Vec<u8>,
766			salt: Option<[u8; 32]>,
767		) -> DispatchResultWithPostInfo {
768			let data_len = data.len() as u32;
769			let mut output = Self::bare_instantiate(
770				origin,
771				value,
772				gas_limit,
773				DepositLimit::Balance(storage_deposit_limit),
774				Code::Existing(code_hash),
775				data,
776				salt,
777			);
778			if let Ok(retval) = &output.result {
779				if retval.result.did_revert() {
780					output.result = Err(<Error<T>>::ContractReverted.into());
781				}
782			}
783			dispatch_result(
784				output.result.map(|result| result.result),
785				output.gas_consumed,
786				T::WeightInfo::instantiate(data_len),
787			)
788		}
789
790		/// Instantiates a new contract from the supplied `code` optionally transferring
791		/// some balance.
792		///
793		/// This dispatchable has the same effect as calling [`Self::upload_code`] +
794		/// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please
795		/// also check the documentation of [`Self::upload_code`].
796		///
797		/// # Parameters
798		///
799		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
800		/// * `gas_limit`: The gas limit enforced when executing the constructor.
801		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved
802		///   from the caller to pay for the storage consumed.
803		/// * `code`: The contract code to deploy in raw bytes.
804		/// * `data`: The input data to pass to the contract constructor.
805		/// * `salt`: Used for the address derivation. If `Some` is supplied then `CREATE2`
806		/// 	semantics are used. If `None` then `CRATE1` is used.
807		///
808		///
809		/// Instantiation is executed as follows:
810		///
811		/// - The supplied `code` is deployed, and a `code_hash` is created for that code.
812		/// - If the `code_hash` already exists on the chain the underlying `code` will be shared.
813		/// - The destination address is computed based on the sender, code_hash and the salt.
814		/// - The smart-contract account is created at the computed address.
815		/// - The `value` is transferred to the new account.
816		/// - The `deploy` function is executed in the context of the newly-created account.
817		#[pallet::call_index(3)]
818		#[pallet::weight(
819			T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
820			.saturating_add(*gas_limit)
821		)]
822		pub fn instantiate_with_code(
823			origin: OriginFor<T>,
824			#[pallet::compact] value: BalanceOf<T>,
825			gas_limit: Weight,
826			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
827			code: Vec<u8>,
828			data: Vec<u8>,
829			salt: Option<[u8; 32]>,
830		) -> DispatchResultWithPostInfo {
831			let code_len = code.len() as u32;
832			let data_len = data.len() as u32;
833			let mut output = Self::bare_instantiate(
834				origin,
835				value,
836				gas_limit,
837				DepositLimit::Balance(storage_deposit_limit),
838				Code::Upload(code),
839				data,
840				salt,
841			);
842			if let Ok(retval) = &output.result {
843				if retval.result.did_revert() {
844					output.result = Err(<Error<T>>::ContractReverted.into());
845				}
846			}
847			dispatch_result(
848				output.result.map(|result| result.result),
849				output.gas_consumed,
850				T::WeightInfo::instantiate_with_code(code_len, data_len),
851			)
852		}
853
854		/// Upload new `code` without instantiating a contract from it.
855		///
856		/// If the code does not already exist a deposit is reserved from the caller
857		/// and unreserved only when [`Self::remove_code`] is called. The size of the reserve
858		/// depends on the size of the supplied `code`.
859		///
860		/// # Note
861		///
862		/// Anyone can instantiate a contract from any uploaded code and thus prevent its removal.
863		/// To avoid this situation a constructor could employ access control so that it can
864		/// only be instantiated by permissioned entities. The same is true when uploading
865		/// through [`Self::instantiate_with_code`].
866		#[pallet::call_index(4)]
867		#[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))]
868		pub fn upload_code(
869			origin: OriginFor<T>,
870			code: Vec<u8>,
871			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
872		) -> DispatchResult {
873			Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
874		}
875
876		/// Remove the code stored under `code_hash` and refund the deposit to its owner.
877		///
878		/// A code can only be removed by its original uploader (its owner) and only if it is
879		/// not used by any contract.
880		#[pallet::call_index(5)]
881		#[pallet::weight(T::WeightInfo::remove_code())]
882		pub fn remove_code(
883			origin: OriginFor<T>,
884			code_hash: sp_core::H256,
885		) -> DispatchResultWithPostInfo {
886			let origin = ensure_signed(origin)?;
887			<WasmBlob<T>>::remove(&origin, code_hash)?;
888			// we waive the fee because removing unused code is beneficial
889			Ok(Pays::No.into())
890		}
891
892		/// Privileged function that changes the code of an existing contract.
893		///
894		/// This takes care of updating refcounts and all other necessary operations. Returns
895		/// an error if either the `code_hash` or `dest` do not exist.
896		///
897		/// # Note
898		///
899		/// This does **not** change the address of the contract in question. This means
900		/// that the contract address is no longer derived from its code hash after calling
901		/// this dispatchable.
902		#[pallet::call_index(6)]
903		#[pallet::weight(T::WeightInfo::set_code())]
904		pub fn set_code(
905			origin: OriginFor<T>,
906			dest: H160,
907			code_hash: sp_core::H256,
908		) -> DispatchResult {
909			ensure_root(origin)?;
910			<ContractInfoOf<T>>::try_mutate(&dest, |contract| {
911				let contract = if let Some(contract) = contract {
912					contract
913				} else {
914					return Err(<Error<T>>::ContractNotFound.into());
915				};
916				<CodeInfo<T>>::increment_refcount(code_hash)?;
917				<CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
918				contract.code_hash = code_hash;
919				Ok(())
920			})
921		}
922
923		/// Register the callers account id so that it can be used in contract interactions.
924		///
925		/// This will error if the origin is already mapped or is a eth native `Address20`. It will
926		/// take a deposit that can be released by calling [`Self::unmap_account`].
927		#[pallet::call_index(7)]
928		#[pallet::weight(T::WeightInfo::map_account())]
929		pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
930			let origin = ensure_signed(origin)?;
931			T::AddressMapper::map(&origin)
932		}
933
934		/// Unregister the callers account id in order to free the deposit.
935		///
936		/// There is no reason to ever call this function other than freeing up the deposit.
937		/// This is only useful when the account should no longer be used.
938		#[pallet::call_index(8)]
939		#[pallet::weight(T::WeightInfo::unmap_account())]
940		pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
941			let origin = ensure_signed(origin)?;
942			T::AddressMapper::unmap(&origin)
943		}
944
945		/// Dispatch an `call` with the origin set to the callers fallback address.
946		///
947		/// Every `AccountId32` can control its corresponding fallback account. The fallback account
948		/// is the `AccountId20` with the last 12 bytes set to `0xEE`. This is essentially a
949		/// recovery function in case an `AccountId20` was used without creating a mapping first.
950		#[pallet::call_index(9)]
951		#[pallet::weight({
952			let dispatch_info = call.get_dispatch_info();
953			(
954				T::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
955				dispatch_info.class
956			)
957		})]
958		pub fn dispatch_as_fallback_account(
959			origin: OriginFor<T>,
960			call: Box<<T as Config>::RuntimeCall>,
961		) -> DispatchResultWithPostInfo {
962			let origin = ensure_signed(origin)?;
963			let unmapped_account =
964				T::AddressMapper::to_fallback_account_id(&T::AddressMapper::to_address(&origin));
965			call.dispatch(RawOrigin::Signed(unmapped_account).into())
966		}
967	}
968}
969
970/// Create a dispatch result reflecting the amount of consumed gas.
971fn dispatch_result<R>(
972	result: Result<R, DispatchError>,
973	gas_consumed: Weight,
974	base_weight: Weight,
975) -> DispatchResultWithPostInfo {
976	let post_info = PostDispatchInfo {
977		actual_weight: Some(gas_consumed.saturating_add(base_weight)),
978		pays_fee: Default::default(),
979	};
980
981	result
982		.map(|_| post_info)
983		.map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
984}
985
986impl<T: Config> Pallet<T>
987where
988	BalanceOf<T>: Into<U256> + TryFrom<U256> + Bounded,
989	MomentOf<T>: Into<U256>,
990	T::Hash: frame_support::traits::IsType<H256>,
991{
992	/// A generalized version of [`Self::call`].
993	///
994	/// Identical to [`Self::call`] but tailored towards being called by other code within the
995	/// runtime as opposed to from an extrinsic. It returns more information and allows the
996	/// enablement of features that are not suitable for an extrinsic (debugging, event
997	/// collection).
998	pub fn bare_call(
999		origin: OriginFor<T>,
1000		dest: H160,
1001		value: BalanceOf<T>,
1002		gas_limit: Weight,
1003		storage_deposit_limit: DepositLimit<BalanceOf<T>>,
1004		data: Vec<u8>,
1005	) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
1006		let mut gas_meter = GasMeter::new(gas_limit);
1007		let mut storage_deposit = Default::default();
1008
1009		let try_call = || {
1010			let origin = Origin::from_runtime_origin(origin)?;
1011			let mut storage_meter = match storage_deposit_limit {
1012				DepositLimit::Balance(limit) => StorageMeter::new(&origin, limit, value)?,
1013				DepositLimit::Unchecked => StorageMeter::new_unchecked(BalanceOf::<T>::max_value()),
1014			};
1015			let result = ExecStack::<T, WasmBlob<T>>::run_call(
1016				origin.clone(),
1017				dest,
1018				&mut gas_meter,
1019				&mut storage_meter,
1020				Self::convert_native_to_evm(value),
1021				data,
1022				storage_deposit_limit.is_unchecked(),
1023			)?;
1024			storage_deposit = storage_meter
1025				.try_into_deposit(&origin, storage_deposit_limit.is_unchecked())
1026				.inspect_err(|err| {
1027					log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1028				})?;
1029			Ok(result)
1030		};
1031		let result = Self::run_guarded(try_call);
1032		ContractResult {
1033			result: result.map_err(|r| r.error),
1034			gas_consumed: gas_meter.gas_consumed(),
1035			gas_required: gas_meter.gas_required(),
1036			storage_deposit,
1037		}
1038	}
1039
1040	/// A generalized version of [`Self::instantiate`] or [`Self::instantiate_with_code`].
1041	///
1042	/// Identical to [`Self::instantiate`] or [`Self::instantiate_with_code`] but tailored towards
1043	/// being called by other code within the runtime as opposed to from an extrinsic. It returns
1044	/// more information to the caller useful to estimate the cost of the operation.
1045	pub fn bare_instantiate(
1046		origin: OriginFor<T>,
1047		value: BalanceOf<T>,
1048		gas_limit: Weight,
1049		storage_deposit_limit: DepositLimit<BalanceOf<T>>,
1050		code: Code,
1051		data: Vec<u8>,
1052		salt: Option<[u8; 32]>,
1053	) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1054		let mut gas_meter = GasMeter::new(gas_limit);
1055		let mut storage_deposit = Default::default();
1056		let unchecked_deposit_limit = storage_deposit_limit.is_unchecked();
1057		let mut storage_deposit_limit = match storage_deposit_limit {
1058			DepositLimit::Balance(limit) => limit,
1059			DepositLimit::Unchecked => BalanceOf::<T>::max_value(),
1060		};
1061
1062		let try_instantiate = || {
1063			let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1064			let (executable, upload_deposit) = match code {
1065				Code::Upload(code) => {
1066					let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1067					let (executable, upload_deposit) = Self::try_upload_code(
1068						upload_account,
1069						code,
1070						storage_deposit_limit,
1071						unchecked_deposit_limit,
1072					)?;
1073					storage_deposit_limit.saturating_reduce(upload_deposit);
1074					(executable, upload_deposit)
1075				},
1076				Code::Existing(code_hash) =>
1077					(WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()),
1078			};
1079			let instantiate_origin = Origin::from_account_id(instantiate_account.clone());
1080			let mut storage_meter = if unchecked_deposit_limit {
1081				StorageMeter::new_unchecked(storage_deposit_limit)
1082			} else {
1083				StorageMeter::new(&instantiate_origin, storage_deposit_limit, value)?
1084			};
1085
1086			let result = ExecStack::<T, WasmBlob<T>>::run_instantiate(
1087				instantiate_account,
1088				executable,
1089				&mut gas_meter,
1090				&mut storage_meter,
1091				Self::convert_native_to_evm(value),
1092				data,
1093				salt.as_ref(),
1094				unchecked_deposit_limit,
1095			);
1096			storage_deposit = storage_meter
1097				.try_into_deposit(&instantiate_origin, unchecked_deposit_limit)?
1098				.saturating_add(&StorageDeposit::Charge(upload_deposit));
1099			result
1100		};
1101		let output = Self::run_guarded(try_instantiate);
1102		ContractResult {
1103			result: output
1104				.map(|(addr, result)| InstantiateReturnValue { result, addr })
1105				.map_err(|e| e.error),
1106			gas_consumed: gas_meter.gas_consumed(),
1107			gas_required: gas_meter.gas_required(),
1108			storage_deposit,
1109		}
1110	}
1111
1112	/// A version of [`Self::eth_transact`] used to dry-run Ethereum calls.
1113	///
1114	/// # Parameters
1115	///
1116	/// - `tx`: The Ethereum transaction to simulate.
1117	/// - `gas_limit`: The gas limit enforced during contract execution.
1118	/// - `tx_fee`: A function that returns the fee for the given call and dispatch info.
1119	pub fn bare_eth_transact(
1120		mut tx: GenericTransaction,
1121		gas_limit: Weight,
1122		tx_fee: impl Fn(Call<T>, DispatchInfo) -> BalanceOf<T>,
1123	) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
1124	where
1125		<T as frame_system::Config>::RuntimeCall:
1126			Dispatchable<Info = frame_support::dispatch::DispatchInfo>,
1127		<T as Config>::RuntimeCall: From<crate::Call<T>>,
1128		<T as Config>::RuntimeCall: Encode,
1129		T::Nonce: Into<U256>,
1130		T::Hash: frame_support::traits::IsType<H256>,
1131	{
1132		log::trace!(target: LOG_TARGET, "bare_eth_transact: tx: {tx:?} gas_limit: {gas_limit:?}");
1133
1134		let from = tx.from.unwrap_or_default();
1135		let origin = T::AddressMapper::to_account_id(&from);
1136
1137		let storage_deposit_limit = if tx.gas.is_some() {
1138			DepositLimit::Balance(BalanceOf::<T>::max_value())
1139		} else {
1140			DepositLimit::Unchecked
1141		};
1142
1143		if tx.nonce.is_none() {
1144			tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
1145		}
1146		if tx.chain_id.is_none() {
1147			tx.chain_id = Some(T::ChainId::get().into());
1148		}
1149		if tx.gas_price.is_none() {
1150			tx.gas_price = Some(GAS_PRICE.into());
1151		}
1152		if tx.gas.is_none() {
1153			tx.gas = Some(Self::evm_block_gas_limit());
1154		}
1155
1156		// Convert the value to the native balance type.
1157		let evm_value = tx.value.unwrap_or_default();
1158		let native_value = match Self::convert_evm_to_native(evm_value, ConversionPrecision::Exact)
1159		{
1160			Ok(v) => v,
1161			Err(_) => return Err(EthTransactError::Message("Failed to convert value".into())),
1162		};
1163
1164		let input = tx.input.clone().to_vec();
1165
1166		let extract_error = |err| {
1167			if err == Error::<T>::TransferFailed.into() ||
1168				err == Error::<T>::StorageDepositNotEnoughFunds.into() ||
1169				err == Error::<T>::StorageDepositLimitExhausted.into()
1170			{
1171				let balance = Self::evm_balance(&from);
1172				return Err(EthTransactError::Message(
1173						format!("insufficient funds for gas * price + value: address {from:?} have {balance} (supplied gas {})",
1174							tx.gas.unwrap_or_default()))
1175					);
1176			}
1177
1178			return Err(EthTransactError::Message(format!(
1179				"Failed to instantiate contract: {err:?}"
1180			)));
1181		};
1182
1183		// Dry run the call
1184		let (mut result, dispatch_info) = match tx.to {
1185			// A contract call.
1186			Some(dest) => {
1187				// Dry run the call.
1188				let result = crate::Pallet::<T>::bare_call(
1189					T::RuntimeOrigin::signed(origin),
1190					dest,
1191					native_value,
1192					gas_limit,
1193					storage_deposit_limit,
1194					input.clone(),
1195				);
1196
1197				let data = match result.result {
1198					Ok(return_value) => {
1199						if return_value.did_revert() {
1200							return Err(EthTransactError::Data(return_value.data));
1201						}
1202						return_value.data
1203					},
1204					Err(err) => {
1205						log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
1206						return extract_error(err)
1207					},
1208				};
1209
1210				let result = EthTransactInfo {
1211					gas_required: result.gas_required,
1212					storage_deposit: result.storage_deposit.charge_or_zero(),
1213					data,
1214					eth_gas: Default::default(),
1215				};
1216
1217				let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
1218					result.gas_required,
1219					result.storage_deposit,
1220				);
1221				let dispatch_call: <T as Config>::RuntimeCall = crate::Call::<T>::call {
1222					dest,
1223					value: native_value,
1224					gas_limit,
1225					storage_deposit_limit,
1226					data: input.clone(),
1227				}
1228				.into();
1229				(result, dispatch_call.get_dispatch_info())
1230			},
1231			// A contract deployment
1232			None => {
1233				// Extract code and data from the input.
1234				let (code, data) = match polkavm::ProgramBlob::blob_length(&input) {
1235					Some(blob_len) => blob_len
1236						.try_into()
1237						.ok()
1238						.and_then(|blob_len| (input.split_at_checked(blob_len)))
1239						.unwrap_or_else(|| (&input[..], &[][..])),
1240					_ => {
1241						log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length");
1242						(&input[..], &[][..])
1243					},
1244				};
1245
1246				// Dry run the call.
1247				let result = crate::Pallet::<T>::bare_instantiate(
1248					T::RuntimeOrigin::signed(origin),
1249					native_value,
1250					gas_limit,
1251					storage_deposit_limit,
1252					Code::Upload(code.to_vec()),
1253					data.to_vec(),
1254					None,
1255				);
1256
1257				let returned_data = match result.result {
1258					Ok(return_value) => {
1259						if return_value.result.did_revert() {
1260							return Err(EthTransactError::Data(return_value.result.data));
1261						}
1262						return_value.result.data
1263					},
1264					Err(err) => {
1265						log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
1266						return extract_error(err)
1267					},
1268				};
1269
1270				let result = EthTransactInfo {
1271					gas_required: result.gas_required,
1272					storage_deposit: result.storage_deposit.charge_or_zero(),
1273					data: returned_data,
1274					eth_gas: Default::default(),
1275				};
1276
1277				// Get the dispatch info of the call.
1278				let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
1279					result.gas_required,
1280					result.storage_deposit,
1281				);
1282				let dispatch_call: <T as Config>::RuntimeCall =
1283					crate::Call::<T>::instantiate_with_code {
1284						value: native_value,
1285						gas_limit,
1286						storage_deposit_limit,
1287						code: code.to_vec(),
1288						data: data.to_vec(),
1289						salt: None,
1290					}
1291					.into();
1292				(result, dispatch_call.get_dispatch_info())
1293			},
1294		};
1295
1296		let Ok(unsigned_tx) = tx.clone().try_into_unsigned() else {
1297			return Err(EthTransactError::Message("Invalid transaction".into()));
1298		};
1299
1300		let eth_dispatch_call =
1301			crate::Call::<T>::eth_transact { payload: unsigned_tx.dummy_signed_payload() };
1302		let fee = tx_fee(eth_dispatch_call, dispatch_info);
1303		let raw_gas = Self::evm_fee_to_gas(fee);
1304		let eth_gas =
1305			T::EthGasEncoder::encode(raw_gas, result.gas_required, result.storage_deposit);
1306
1307		log::trace!(target: LOG_TARGET, "bare_eth_call: raw_gas: {raw_gas:?} eth_gas: {eth_gas:?}");
1308		result.eth_gas = eth_gas;
1309		Ok(result)
1310	}
1311
1312	/// Get the balance with EVM decimals of the given `address`.
1313	pub fn evm_balance(address: &H160) -> U256 {
1314		let account = T::AddressMapper::to_account_id(&address);
1315		Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite))
1316	}
1317
1318	/// Convert a substrate fee into a gas value, using the fixed `GAS_PRICE`.
1319	/// The gas is calculated as `fee / GAS_PRICE`, rounded up to the nearest integer.
1320	pub fn evm_fee_to_gas(fee: BalanceOf<T>) -> U256 {
1321		let fee = Self::convert_native_to_evm(fee);
1322		let gas_price = GAS_PRICE.into();
1323		let (quotient, remainder) = fee.div_mod(gas_price);
1324		if remainder.is_zero() {
1325			quotient
1326		} else {
1327			quotient + U256::one()
1328		}
1329	}
1330
1331	/// Convert a gas value into a substrate fee
1332	fn evm_gas_to_fee(gas: U256, gas_price: U256) -> Result<BalanceOf<T>, Error<T>> {
1333		let fee = gas.saturating_mul(gas_price);
1334		Self::convert_evm_to_native(fee, ConversionPrecision::RoundUp)
1335	}
1336
1337	/// Convert a weight to a gas value.
1338	pub fn evm_gas_from_weight(weight: Weight) -> U256 {
1339		let fee = T::WeightPrice::convert(weight);
1340		Self::evm_fee_to_gas(fee)
1341	}
1342
1343	/// Get the block gas limit.
1344	pub fn evm_block_gas_limit() -> U256 {
1345		let max_block_weight = T::BlockWeights::get()
1346			.get(DispatchClass::Normal)
1347			.max_total
1348			.unwrap_or_else(|| T::BlockWeights::get().max_block);
1349
1350		Self::evm_gas_from_weight(max_block_weight)
1351	}
1352
1353	/// Get the gas price.
1354	pub fn evm_gas_price() -> U256 {
1355		GAS_PRICE.into()
1356	}
1357
1358	/// A generalized version of [`Self::upload_code`].
1359	///
1360	/// It is identical to [`Self::upload_code`] and only differs in the information it returns.
1361	pub fn bare_upload_code(
1362		origin: OriginFor<T>,
1363		code: Vec<u8>,
1364		storage_deposit_limit: BalanceOf<T>,
1365	) -> CodeUploadResult<BalanceOf<T>> {
1366		let origin = T::UploadOrigin::ensure_origin(origin)?;
1367		let (module, deposit) = Self::try_upload_code(origin, code, storage_deposit_limit, false)?;
1368		Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit })
1369	}
1370
1371	/// Query storage of a specified contract under a specified key.
1372	pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
1373		let contract_info =
1374			ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1375
1376		let maybe_value = contract_info.read(&Key::from_fixed(key));
1377		Ok(maybe_value)
1378	}
1379
1380	/// Uploads new code and returns the Wasm blob and deposit amount collected.
1381	fn try_upload_code(
1382		origin: T::AccountId,
1383		code: Vec<u8>,
1384		storage_deposit_limit: BalanceOf<T>,
1385		skip_transfer: bool,
1386	) -> Result<(WasmBlob<T>, BalanceOf<T>), DispatchError> {
1387		let mut module = WasmBlob::from_code(code, origin)?;
1388		let deposit = module.store_code(skip_transfer)?;
1389		ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
1390		Ok((module, deposit))
1391	}
1392
1393	/// Run the supplied function `f` if no other instance of this pallet is on the stack.
1394	fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
1395		executing_contract::using_once(&mut false, || {
1396			executing_contract::with(|f| {
1397				// Fail if already entered contract execution
1398				if *f {
1399					return Err(())
1400				}
1401				// We are entering contract execution
1402				*f = true;
1403				Ok(())
1404			})
1405				.expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
1406				.map_err(|_| <Error<T>>::ReenteredPallet.into())
1407				.map(|_| f())
1408				.and_then(|r| r)
1409		})
1410	}
1411
1412	/// Convert a native balance to EVM balance.
1413	fn convert_native_to_evm(value: BalanceOf<T>) -> U256 {
1414		value.into().saturating_mul(T::NativeToEthRatio::get().into())
1415	}
1416
1417	/// Convert an EVM balance to a native balance.
1418	fn convert_evm_to_native(
1419		value: U256,
1420		precision: ConversionPrecision,
1421	) -> Result<BalanceOf<T>, Error<T>> {
1422		if value.is_zero() {
1423			return Ok(Zero::zero())
1424		}
1425
1426		let (quotient, remainder) = value.div_mod(T::NativeToEthRatio::get().into());
1427		match (precision, remainder.is_zero()) {
1428			(ConversionPrecision::Exact, false) => Err(Error::<T>::DecimalPrecisionLoss),
1429			(_, true) => quotient.try_into().map_err(|_| Error::<T>::BalanceConversionFailed),
1430			(_, false) => quotient
1431				.saturating_add(U256::one())
1432				.try_into()
1433				.map_err(|_| Error::<T>::BalanceConversionFailed),
1434		}
1435	}
1436}
1437
1438impl<T: Config> Pallet<T> {
1439	/// Return the existential deposit of [`Config::Currency`].
1440	fn min_balance() -> BalanceOf<T> {
1441		<T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
1442	}
1443
1444	/// Deposit a pallet contracts event.
1445	fn deposit_event(event: Event<T>) {
1446		<frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
1447	}
1448}
1449
1450// Set up a global reference to the boolean flag used for the re-entrancy guard.
1451environmental!(executing_contract: bool);
1452
1453sp_api::decl_runtime_apis! {
1454	/// The API used to dry-run contract interactions.
1455	#[api_version(1)]
1456	pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber> where
1457		AccountId: Codec,
1458		Balance: Codec,
1459		Nonce: Codec,
1460		BlockNumber: Codec,
1461	{
1462		/// Returns the block gas limit.
1463		fn block_gas_limit() -> U256;
1464
1465		/// Returns the free balance of the given `[H160]` address, using EVM decimals.
1466		fn balance(address: H160) -> U256;
1467
1468		/// Returns the gas price.
1469		fn gas_price() -> U256;
1470
1471		/// Returns the nonce of the given `[H160]` address.
1472		fn nonce(address: H160) -> Nonce;
1473
1474		/// Perform a call from a specified account to a given contract.
1475		///
1476		/// See [`crate::Pallet::bare_call`].
1477		fn call(
1478			origin: AccountId,
1479			dest: H160,
1480			value: Balance,
1481			gas_limit: Option<Weight>,
1482			storage_deposit_limit: Option<Balance>,
1483			input_data: Vec<u8>,
1484		) -> ContractResult<ExecReturnValue, Balance>;
1485
1486		/// Instantiate a new contract.
1487		///
1488		/// See `[crate::Pallet::bare_instantiate]`.
1489		fn instantiate(
1490			origin: AccountId,
1491			value: Balance,
1492			gas_limit: Option<Weight>,
1493			storage_deposit_limit: Option<Balance>,
1494			code: Code,
1495			data: Vec<u8>,
1496			salt: Option<[u8; 32]>,
1497		) -> ContractResult<InstantiateReturnValue, Balance>;
1498
1499
1500		/// Perform an Ethereum call.
1501		///
1502		/// See [`crate::Pallet::bare_eth_transact`]
1503		fn eth_transact(tx: GenericTransaction) -> Result<EthTransactInfo<Balance>, EthTransactError>;
1504
1505		/// Upload new code without instantiating a contract from it.
1506		///
1507		/// See [`crate::Pallet::bare_upload_code`].
1508		fn upload_code(
1509			origin: AccountId,
1510			code: Vec<u8>,
1511			storage_deposit_limit: Option<Balance>,
1512		) -> CodeUploadResult<Balance>;
1513
1514		/// Query a given storage key in a given contract.
1515		///
1516		/// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
1517		/// specified account and `Ok(None)` if it doesn't. If the account specified by the address
1518		/// doesn't exist, or doesn't have a contract then `Err` is returned.
1519		fn get_storage(
1520			address: H160,
1521			key: [u8; 32],
1522		) -> GetStorageResult;
1523
1524
1525		/// Traces the execution of an entire block and returns call traces.
1526		///
1527		/// This is intended to be called through `state_call` to replay the block from the
1528		/// parent block.
1529		///
1530		/// See eth-rpc `debug_traceBlockByNumber` for usage.
1531		fn trace_block(
1532			block: Block,
1533			config: TracerConfig
1534		) -> Vec<(u32, CallTrace)>;
1535
1536		/// Traces the execution of a specific transaction within a block.
1537		///
1538		/// This is intended to be called through `state_call` to replay the block from the
1539		/// parent hash up to the transaction.
1540		///
1541		/// See eth-rpc `debug_traceTransaction` for usage.
1542		fn trace_tx(
1543			block: Block,
1544			tx_index: u32,
1545			config: TracerConfig
1546		) -> Option<CallTrace>;
1547
1548		/// Dry run and return the trace of the given call.
1549		///
1550		/// See eth-rpc `debug_traceCall` for usage.
1551		fn trace_call(tx: GenericTransaction, config: TracerConfig) -> Result<CallTrace, EthTransactError>;
1552
1553	}
1554}