// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{
	debug::{CallInterceptor, CallSpan, Tracing},
	gas::GasMeter,
	primitives::{ExecReturnValue, StorageDeposit},
	storage::{self, meter::Diff, WriteOutcome},
	BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf,
	DebugBufferVec, Determinism, Error, Event, Nonce, Origin, Pallet as Contracts, Schedule,
	LOG_TARGET,
};
use frame_support::{
	crypto::ecdsa::ECDSAExt,
	dispatch::{DispatchResult, DispatchResultWithPostInfo},
	ensure,
	storage::{with_transaction, TransactionOutcome},
	traits::{
		fungible::{Inspect, Mutate},
		tokens::{Fortitude, Preservation},
		Contains, OriginTrait, Randomness, Time,
	},
	weights::Weight,
	Blake2_128Concat, BoundedVec, StorageHasher,
};
use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
use smallvec::{Array, SmallVec};
use sp_core::{
	ecdsa::Public as ECDSAPublic,
	sr25519::{Public as SR25519Public, Signature as SR25519Signature},
	Get,
};
use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
use sp_runtime::{
	traits::{Convert, Dispatchable, Hash, Zero},
	DispatchError,
};
use sp_std::{fmt::Debug, marker::PhantomData, mem, prelude::*, vec::Vec};

pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
pub type SeedOf<T> = <T as frame_system::Config>::Hash;
pub type ExecResult = Result<ExecReturnValue, ExecError>;

/// A type that represents a topic of an event. At the moment a hash is used.
pub type TopicOf<T> = <T as frame_system::Config>::Hash;

/// Type for variable sized storage key. Used for transparent hashing.
type VarSizedKey<T> = BoundedVec<u8, <T as Config>::MaxStorageKeyLen>;

/// Combined key type for both fixed and variable sized storage keys.
pub enum Key<T: Config> {
	/// Variant for fixed sized keys.
	Fix([u8; 32]),
	/// Variant for variable sized keys.
	Var(VarSizedKey<T>),
}

impl<T: Config> Key<T> {
	/// Copies self into a new vec.
	pub fn to_vec(&self) -> Vec<u8> {
		match self {
			Key::Fix(v) => v.to_vec(),
			Key::Var(v) => v.to_vec(),
		}
	}

	pub fn hash(&self) -> Vec<u8> {
		match self {
			Key::Fix(v) => blake2_256(v.as_slice()).to_vec(),
			Key::Var(v) => Blake2_128Concat::hash(v.as_slice()),
		}
	}

	pub fn try_from_fix(v: Vec<u8>) -> Result<Self, Vec<u8>> {
		<[u8; 32]>::try_from(v).map(Self::Fix)
	}

	pub fn try_from_var(v: Vec<u8>) -> Result<Self, Vec<u8>> {
		VarSizedKey::<T>::try_from(v).map(Self::Var)
	}
}

/// Origin of the error.
///
/// Call or instantiate both called into other contracts and pass through errors happening
/// in those to the caller. This enum is for the caller to distinguish whether the error
/// happened during the execution of the callee or in the current execution context.
#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
pub enum ErrorOrigin {
	/// Caller error origin.
	///
	/// The error happened in the current execution context rather than in the one
	/// of the contract that is called into.
	Caller,
	/// The error happened during execution of the called contract.
	Callee,
}

/// Error returned by contract execution.
#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
pub struct ExecError {
	/// The reason why the execution failed.
	pub error: DispatchError,
	/// Origin of the error.
	pub origin: ErrorOrigin,
}

impl<T: Into<DispatchError>> From<T> for ExecError {
	fn from(error: T) -> Self {
		Self { error: error.into(), origin: ErrorOrigin::Caller }
	}
}

/// An interface that provides access to the external environment in which the
/// smart-contract is executed.
///
/// This interface is specialized to an account of the executing code, so all
/// operations are implicitly performed on that account.
///
/// # Note
///
/// This trait is sealed and cannot be implemented by downstream crates.
pub trait Ext: sealing::Sealed {
	type T: Config;

	/// Call (possibly transferring some amount of funds) into the specified account.
	///
	/// Returns the code size of the called contract.
	fn call(
		&mut self,
		gas_limit: Weight,
		deposit_limit: BalanceOf<Self::T>,
		to: AccountIdOf<Self::T>,
		value: BalanceOf<Self::T>,
		input_data: Vec<u8>,
		allows_reentry: bool,
	) -> Result<ExecReturnValue, ExecError>;

	/// Execute code in the current frame.
	///
	/// Returns the code size of the called contract.
	fn delegate_call(
		&mut self,
		code: CodeHash<Self::T>,
		input_data: Vec<u8>,
	) -> Result<ExecReturnValue, ExecError>;

	/// Instantiate a contract from the given code.
	///
	/// Returns the original code size of the called contract.
	/// The newly created account will be associated with `code`. `value` specifies the amount of
	/// value transferred from the caller to the newly created account.
	fn instantiate(
		&mut self,
		gas_limit: Weight,
		deposit_limit: BalanceOf<Self::T>,
		code: CodeHash<Self::T>,
		value: BalanceOf<Self::T>,
		input_data: Vec<u8>,
		salt: &[u8],
	) -> Result<(AccountIdOf<Self::T>, ExecReturnValue), ExecError>;

	/// Transfer all funds to `beneficiary` and delete the contract.
	///
	/// Since this function removes the self contract eagerly, if succeeded, no further actions
	/// should be performed on this `Ext` instance.
	///
	/// This function will fail if the same contract is present on the contract
	/// call stack.
	fn terminate(&mut self, beneficiary: &AccountIdOf<Self::T>) -> Result<(), DispatchError>;

	/// Transfer some amount of funds into the specified account.
	fn transfer(&mut self, to: &AccountIdOf<Self::T>, value: BalanceOf<Self::T>) -> DispatchResult;

	/// Returns the storage entry of the executing account by the given `key`.
	///
	/// Returns `None` if the `key` wasn't previously set by `set_storage` or
	/// was deleted.
	fn get_storage(&mut self, key: &Key<Self::T>) -> Option<Vec<u8>>;

	/// Returns `Some(len)` (in bytes) if a storage item exists at `key`.
	///
	/// Returns `None` if the `key` wasn't previously set by `set_storage` or
	/// was deleted.
	fn get_storage_size(&mut self, key: &Key<Self::T>) -> Option<u32>;

	/// Sets the storage entry by the given key to the specified value. If `value` is `None` then
	/// the storage entry is deleted.
	fn set_storage(
		&mut self,
		key: &Key<Self::T>,
		value: Option<Vec<u8>>,
		take_old: bool,
	) -> Result<WriteOutcome, DispatchError>;

	/// Returns the caller.
	fn caller(&self) -> Origin<Self::T>;

	/// Check if a contract lives at the specified `address`.
	fn is_contract(&self, address: &AccountIdOf<Self::T>) -> bool;

	/// Returns the code hash of the contract for the given `address`.
	///
	/// Returns `None` if the `address` does not belong to a contract.
	fn code_hash(&self, address: &AccountIdOf<Self::T>) -> Option<CodeHash<Self::T>>;

	/// Returns the code hash of the contract being executed.
	fn own_code_hash(&mut self) -> &CodeHash<Self::T>;

	/// Check if the caller of the current contract is the origin of the whole call stack.
	///
	/// This can be checked with `is_contract(self.caller())` as well.
	/// However, this function does not require any storage lookup and therefore uses less weight.
	fn caller_is_origin(&self) -> bool;

	/// Check if the caller is origin, and this origin is root.
	fn caller_is_root(&self) -> bool;

	/// Returns a reference to the account id of the current contract.
	fn address(&self) -> &AccountIdOf<Self::T>;

	/// Returns the balance of the current contract.
	///
	/// The `value_transferred` is already added.
	fn balance(&self) -> BalanceOf<Self::T>;

	/// Returns the value transferred along with this call.
	fn value_transferred(&self) -> BalanceOf<Self::T>;

	/// Returns a reference to the timestamp of the current block
	fn now(&self) -> &MomentOf<Self::T>;

	/// Returns the minimum balance that is required for creating an account.
	fn minimum_balance(&self) -> BalanceOf<Self::T>;

	/// Returns a random number for the current block with the given subject.
	fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberFor<Self::T>);

	/// Deposit an event with the given topics.
	///
	/// There should not be any duplicates in `topics`.
	fn deposit_event(&mut self, topics: Vec<TopicOf<Self::T>>, data: Vec<u8>);

	/// Returns the current block number.
	fn block_number(&self) -> BlockNumberFor<Self::T>;

	/// Returns the maximum allowed size of a storage item.
	fn max_value_size(&self) -> u32;

	/// Returns the price for the specified amount of weight.
	fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T>;

	/// Get a reference to the schedule used by the current call.
	fn schedule(&self) -> &Schedule<Self::T>;

	/// Get an immutable reference to the nested gas meter.
	fn gas_meter(&self) -> &GasMeter<Self::T>;

	/// Get a mutable reference to the nested gas meter.
	fn gas_meter_mut(&mut self) -> &mut GasMeter<Self::T>;

	/// Charges `diff` from the meter.
	fn charge_storage(&mut self, diff: &Diff);

	/// Append a string to the debug buffer.
	///
	/// It is added as-is without any additional new line.
	///
	/// This is a no-op if debug message recording is disabled which is always the case
	/// when the code is executing on-chain.
	///
	/// Returns `true` if debug message recording is enabled. Otherwise `false` is returned.
	fn append_debug_buffer(&mut self, msg: &str) -> bool;

	/// Returns `true` if debug message recording is enabled. Otherwise `false` is returned.
	fn debug_buffer_enabled(&self) -> bool;

	/// Call some dispatchable and return the result.
	fn call_runtime(&self, call: <Self::T as Config>::RuntimeCall) -> DispatchResultWithPostInfo;

	/// Recovers ECDSA compressed public key based on signature and message hash.
	fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>;

	/// Verify a sr25519 signature.
	fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool;

	/// Returns Ethereum address from the ECDSA compressed public key.
	fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()>;

	/// Tests sometimes need to modify and inspect the contract info directly.
	#[cfg(test)]
	fn contract_info(&mut self) -> &mut ContractInfo<Self::T>;

	/// Sets new code hash for existing contract.
	fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> Result<(), DispatchError>;

	/// Returns the number of times the currently executing contract exists on the call stack in
	/// addition to the calling instance. A value of 0 means no reentrancy.
	fn reentrance_count(&self) -> u32;

	/// Returns the number of times the specified contract exists on the call stack. Delegated calls
	/// are not calculated as separate entrance.
	/// A value of 0 means it does not exist on the call stack.
	fn account_reentrance_count(&self, account_id: &AccountIdOf<Self::T>) -> u32;

	/// Returns a nonce that is incremented for every instantiated contract.
	fn nonce(&mut self) -> u64;

	/// Increment the reference count of a of a stored code by one.
	///
	/// # Errors
	///
	/// [`Error::CodeNotFound`] is returned if no stored code found having the specified
	/// `code_hash`.
	fn increment_refcount(code_hash: CodeHash<Self::T>) -> Result<(), DispatchError>;

	/// Decrement the reference count of a stored code by one.
	///
	/// # Note
	///
	/// A contract whose reference count dropped to zero isn't automatically removed. A
	/// `remove_code` transaction must be submitted by the original uploader to do so.
	fn decrement_refcount(code_hash: CodeHash<Self::T>);

	/// Adds a delegate dependency to [`ContractInfo`]'s `delegate_dependencies` field.
	///
	/// This ensures that the delegated contract is not removed while it is still in use. It
	/// increases the reference count of the code hash and charges a fraction (see
	/// [`Config::CodeHashLockupDepositPercent`]) of the code deposit.
	///
	/// # Errors
	///
	/// - [`Error::<T>::MaxDelegateDependenciesReached`]
	/// - [`Error::<T>::CannotAddSelfAsDelegateDependency`]
	/// - [`Error::<T>::DelegateDependencyAlreadyExists`]
	fn lock_delegate_dependency(
		&mut self,
		code_hash: CodeHash<Self::T>,
	) -> Result<(), DispatchError>;

	/// Removes a delegate dependency from [`ContractInfo`]'s `delegate_dependencies` field.
	///
	/// This is the counterpart of [`Self::lock_delegate_dependency`]. It decreases the reference
	/// count and refunds the deposit that was charged by [`Self::lock_delegate_dependency`].
	///
	/// # Errors
	///
	/// - [`Error::<T>::DelegateDependencyNotFound`]
	fn unlock_delegate_dependency(
		&mut self,
		code_hash: &CodeHash<Self::T>,
	) -> Result<(), DispatchError>;
}

/// Describes the different functions that can be exported by an [`Executable`].
#[derive(
	Copy,
	Clone,
	PartialEq,
	Eq,
	sp_core::RuntimeDebug,
	codec::Decode,
	codec::Encode,
	codec::MaxEncodedLen,
	scale_info::TypeInfo,
)]
pub enum ExportedFunction {
	/// The constructor function which is executed on deployment of a contract.
	Constructor,
	/// The function which is executed when a contract is called.
	Call,
}

/// A trait that represents something that can be executed.
///
/// In the on-chain environment this would be represented by a wasm module. This trait exists in
/// order to be able to mock the wasm logic for testing.
pub trait Executable<T: Config>: Sized {
	/// Load the executable from storage.
	///
	/// # Note
	/// Charges size base load weight from the gas meter.
	fn from_storage(
		code_hash: CodeHash<T>,
		gas_meter: &mut GasMeter<T>,
	) -> Result<Self, DispatchError>;

	/// Execute the specified exported function and return the result.
	///
	/// When the specified function is `Constructor` the executable is stored and its
	/// refcount incremented.
	///
	/// # Note
	///
	/// This functions expects to be executed in a storage transaction that rolls back
	/// all of its emitted storage changes.
	fn execute<E: Ext<T = T>>(
		self,
		ext: &mut E,
		function: &ExportedFunction,
		input_data: Vec<u8>,
	) -> ExecResult;

	/// The code info of the executable.
	fn code_info(&self) -> &CodeInfo<T>;

	/// The code hash of the executable.
	fn code_hash(&self) -> &CodeHash<T>;

	/// Size of the contract code in bytes.
	fn code_len(&self) -> u32;

	/// The code does not contain any instructions which could lead to indeterminism.
	fn is_deterministic(&self) -> bool;
}

/// The complete call stack of a contract execution.
///
/// The call stack is initiated by either a signed origin or one of the contract RPC calls.
/// This type implements `Ext` and by that exposes the business logic of contract execution to
/// the runtime module which interfaces with the contract (the wasm blob) itself.
pub struct Stack<'a, T: Config, E> {
	/// The origin that initiated the call stack. It could either be a Signed plain account that
	/// holds an account id or Root.
	///
	/// # Note
	///
	/// Please note that it is possible that the id of a Signed origin belongs to a contract rather
	/// than a plain account when being called through one of the contract RPCs where the
	/// client can freely choose the origin. This usually makes no sense but is still possible.
	origin: Origin<T>,
	/// The cost schedule used when charging from the gas meter.
	schedule: &'a Schedule<T>,
	/// The gas meter where costs are charged to.
	gas_meter: &'a mut GasMeter<T>,
	/// The storage meter makes sure that the storage deposit limit is obeyed.
	storage_meter: &'a mut storage::meter::Meter<T>,
	/// The timestamp at the point of call stack instantiation.
	timestamp: MomentOf<T>,
	/// The block number at the time of call stack instantiation.
	block_number: BlockNumberFor<T>,
	/// The nonce is cached here when accessed. It is written back when the call stack
	/// finishes executing. Please refer to [`Nonce`] to a description of
	/// the nonce itself.
	nonce: Option<u64>,
	/// The actual call stack. One entry per nested contract called/instantiated.
	/// This does **not** include the [`Self::first_frame`].
	frames: SmallVec<T::CallStack>,
	/// Statically guarantee that each call stack has at least one frame.
	first_frame: Frame<T>,
	/// A text buffer used to output human readable information.
	///
	/// All the bytes added to this field should be valid UTF-8. The buffer has no defined
	/// structure and is intended to be shown to users as-is for debugging purposes.
	debug_message: Option<&'a mut DebugBufferVec<T>>,
	/// The determinism requirement of this call stack.
	determinism: Determinism,
	/// No executable is held by the struct but influences its behaviour.
	_phantom: PhantomData<E>,
}

/// Represents one entry in the call stack.
///
/// For each nested contract call or instantiate one frame is created. It holds specific
/// information for the said call and caches the in-storage `ContractInfo` data structure.
///
/// # Note
///
/// This is an internal data structure. It is exposed to the public for the sole reason
/// of specifying [`Config::CallStack`].
pub struct Frame<T: Config> {
	/// The account id of the executing contract.
	account_id: T::AccountId,
	/// The cached in-storage data of the contract.
	contract_info: CachedContract<T>,
	/// The amount of balance transferred by the caller as part of the call.
	value_transferred: BalanceOf<T>,
	/// Determines whether this is a call or instantiate frame.
	entry_point: ExportedFunction,
	/// The gas meter capped to the supplied gas limit.
	nested_gas: GasMeter<T>,
	/// The storage meter for the individual call.
	nested_storage: storage::meter::NestedMeter<T>,
	/// If `false` the contract enabled its defense against reentrance attacks.
	allows_reentry: bool,
	/// The caller of the currently executing frame which was spawned by `delegate_call`.
	delegate_caller: Option<Origin<T>>,
}

/// Used in a delegate call frame arguments in order to override the executable and caller.
struct DelegatedCall<T: Config, E> {
	/// The executable which is run instead of the contracts own `executable`.
	executable: E,
	/// The caller of the contract.
	caller: Origin<T>,
}

/// Parameter passed in when creating a new `Frame`.
///
/// It determines whether the new frame is for a call or an instantiate.
enum FrameArgs<'a, T: Config, E> {
	Call {
		/// The account id of the contract that is to be called.
		dest: T::AccountId,
		/// If `None` the contract info needs to be reloaded from storage.
		cached_info: Option<ContractInfo<T>>,
		/// This frame was created by `seal_delegate_call` and hence uses different code than
		/// what is stored at [`Self::Call::dest`]. Its caller ([`DelegatedCall::caller`]) is the
		/// account which called the caller contract
		delegated_call: Option<DelegatedCall<T, E>>,
	},
	Instantiate {
		/// The contract or signed origin which instantiates the new contract.
		sender: T::AccountId,
		/// The nonce that should be used to derive a new trie id for the contract.
		nonce: u64,
		/// The executable whose `deploy` function is run.
		executable: E,
		/// A salt used in the contract address derivation of the new contract.
		salt: &'a [u8],
		/// The input data is used in the contract address derivation of the new contract.
		input_data: &'a [u8],
	},
}

/// Describes the different states of a contract as contained in a `Frame`.
enum CachedContract<T: Config> {
	/// The cached contract is up to date with the in-storage value.
	Cached(ContractInfo<T>),
	/// A recursive call into the same contract did write to the contract info.
	///
	/// In this case the cached contract is stale and needs to be reloaded from storage.
	Invalidated,
	/// The current contract executed `terminate` and removed the contract.
	///
	/// In this case a reload is neither allowed nor possible. Please note that recursive
	/// calls cannot remove a contract as this is checked and denied.
	Terminated,
}

impl<T: Config> CachedContract<T> {
	/// Return `Some(ContractInfo)` if the contract is in cached state. `None` otherwise.
	fn into_contract(self) -> Option<ContractInfo<T>> {
		if let CachedContract::Cached(contract) = self {
			Some(contract)
		} else {
			None
		}
	}

	/// Return `Some(&mut ContractInfo)` if the contract is in cached state. `None` otherwise.
	fn as_contract(&mut self) -> Option<&mut ContractInfo<T>> {
		if let CachedContract::Cached(contract) = self {
			Some(contract)
		} else {
			None
		}
	}
}

impl<T: Config> Frame<T> {
	/// Return the `contract_info` of the current contract.
	fn contract_info(&mut self) -> &mut ContractInfo<T> {
		self.contract_info.get(&self.account_id)
	}

	/// Terminate and return the `contract_info` of the current contract.
	///
	/// # Note
	///
	/// Under no circumstances the contract is allowed to access the `contract_info` after
	/// a call to this function. This would constitute a programming error in the exec module.
	fn terminate(&mut self) -> ContractInfo<T> {
		self.contract_info.terminate(&self.account_id)
	}
}

/// Extract the contract info after loading it from storage.
///
/// This assumes that `load` was executed before calling this macro.
macro_rules! get_cached_or_panic_after_load {
	($c:expr) => {{
		if let CachedContract::Cached(contract) = $c {
			contract
		} else {
			panic!(
				"It is impossible to remove a contract that is on the call stack;\
				See implementations of terminate;\
				Therefore fetching a contract will never fail while using an account id
				that is currently active on the call stack;\
				qed"
			);
		}
	}};
}

/// Same as [`Stack::top_frame`].
///
/// We need this access as a macro because sometimes hiding the lifetimes behind
/// a function won't work out.
macro_rules! top_frame {
	($stack:expr) => {
		$stack.frames.last().unwrap_or(&$stack.first_frame)
	};
}

/// Same as [`Stack::top_frame_mut`].
///
/// We need this access as a macro because sometimes hiding the lifetimes behind
/// a function won't work out.
macro_rules! top_frame_mut {
	($stack:expr) => {
		$stack.frames.last_mut().unwrap_or(&mut $stack.first_frame)
	};
}

impl<T: Config> CachedContract<T> {
	/// Load the `contract_info` from storage if necessary.
	fn load(&mut self, account_id: &T::AccountId) {
		if let CachedContract::Invalidated = self {
			let contract = <ContractInfoOf<T>>::get(&account_id);
			if let Some(contract) = contract {
				*self = CachedContract::Cached(contract);
			}
		}
	}

	/// Return the cached contract_info.
	fn get(&mut self, account_id: &T::AccountId) -> &mut ContractInfo<T> {
		self.load(account_id);
		get_cached_or_panic_after_load!(self)
	}

	/// Terminate and return the contract info.
	fn terminate(&mut self, account_id: &T::AccountId) -> ContractInfo<T> {
		self.load(account_id);
		get_cached_or_panic_after_load!(mem::replace(self, Self::Terminated))
	}
}

impl<'a, T, E> Stack<'a, T, E>
where
	T: Config,
	E: Executable<T>,
{
	/// Create and run a new call stack by calling into `dest`.
	///
	/// # Note
	///
	/// `debug_message` should only ever be set to `Some` when executing as an RPC because
	/// it adds allocations and could be abused to drive the runtime into an OOM panic.
	///
	/// # Return Value
	///
	/// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>
	pub fn run_call(
		origin: Origin<T>,
		dest: T::AccountId,
		gas_meter: &'a mut GasMeter<T>,
		storage_meter: &'a mut storage::meter::Meter<T>,
		schedule: &'a Schedule<T>,
		value: BalanceOf<T>,
		input_data: Vec<u8>,
		debug_message: Option<&'a mut DebugBufferVec<T>>,
		determinism: Determinism,
	) -> Result<ExecReturnValue, ExecError> {
		let (mut stack, executable) = Self::new(
			FrameArgs::Call { dest, cached_info: None, delegated_call: None },
			origin,
			gas_meter,
			storage_meter,
			schedule,
			value,
			debug_message,
			determinism,
		)?;
		stack.run(executable, input_data)
	}

	/// Create and run a new call stack by instantiating a new contract.
	///
	/// # Note
	///
	/// `debug_message` should only ever be set to `Some` when executing as an RPC because
	/// it adds allocations and could be abused to drive the runtime into an OOM panic.
	///
	/// # Return Value
	///
	/// Result<(NewContractAccountId, ExecReturnValue), ExecError)>
	pub fn run_instantiate(
		origin: T::AccountId,
		executable: E,
		gas_meter: &'a mut GasMeter<T>,
		storage_meter: &'a mut storage::meter::Meter<T>,
		schedule: &'a Schedule<T>,
		value: BalanceOf<T>,
		input_data: Vec<u8>,
		salt: &[u8],
		debug_message: Option<&'a mut DebugBufferVec<T>>,
	) -> Result<(T::AccountId, ExecReturnValue), ExecError> {
		let (mut stack, executable) = Self::new(
			FrameArgs::Instantiate {
				sender: origin.clone(),
				nonce: <Nonce<T>>::get().wrapping_add(1),
				executable,
				salt,
				input_data: input_data.as_ref(),
			},
			Origin::from_account_id(origin),
			gas_meter,
			storage_meter,
			schedule,
			value,
			debug_message,
			Determinism::Enforced,
		)?;
		let account_id = stack.top_frame().account_id.clone();
		stack.run(executable, input_data).map(|ret| (account_id, ret))
	}

	/// Create a new call stack.
	fn new(
		args: FrameArgs<T, E>,
		origin: Origin<T>,
		gas_meter: &'a mut GasMeter<T>,
		storage_meter: &'a mut storage::meter::Meter<T>,
		schedule: &'a Schedule<T>,
		value: BalanceOf<T>,
		debug_message: Option<&'a mut DebugBufferVec<T>>,
		determinism: Determinism,
	) -> Result<(Self, E), ExecError> {
		let (first_frame, executable, nonce) = Self::new_frame(
			args,
			value,
			gas_meter,
			Weight::zero(),
			storage_meter,
			BalanceOf::<T>::zero(),
			determinism,
		)?;

		let stack = Self {
			origin,
			schedule,
			gas_meter,
			storage_meter,
			timestamp: T::Time::now(),
			block_number: <frame_system::Pallet<T>>::block_number(),
			nonce,
			first_frame,
			frames: Default::default(),
			debug_message,
			determinism,
			_phantom: Default::default(),
		};

		Ok((stack, executable))
	}

	/// Construct a new frame.
	///
	/// This does not take `self` because when constructing the first frame `self` is
	/// not initialized, yet.
	fn new_frame<S: storage::meter::State + Default + Debug>(
		frame_args: FrameArgs<T, E>,
		value_transferred: BalanceOf<T>,
		gas_meter: &mut GasMeter<T>,
		gas_limit: Weight,
		storage_meter: &mut storage::meter::GenericMeter<T, S>,
		deposit_limit: BalanceOf<T>,
		determinism: Determinism,
	) -> Result<(Frame<T>, E, Option<u64>), ExecError> {
		let (account_id, contract_info, executable, delegate_caller, entry_point, nonce) =
			match frame_args {
				FrameArgs::Call { dest, cached_info, delegated_call } => {
					let contract = if let Some(contract) = cached_info {
						contract
					} else {
						<ContractInfoOf<T>>::get(&dest).ok_or(<Error<T>>::ContractNotFound)?
					};

					let (executable, delegate_caller) =
						if let Some(DelegatedCall { executable, caller }) = delegated_call {
							(executable, Some(caller))
						} else {
							(E::from_storage(contract.code_hash, gas_meter)?, None)
						};

					(dest, contract, executable, delegate_caller, ExportedFunction::Call, None)
				},
				FrameArgs::Instantiate { sender, nonce, executable, salt, input_data } => {
					let account_id = Contracts::<T>::contract_address(
						&sender,
						&executable.code_hash(),
						input_data,
						salt,
					);
					let contract = ContractInfo::new(&account_id, nonce, *executable.code_hash())?;
					(
						account_id,
						contract,
						executable,
						None,
						ExportedFunction::Constructor,
						Some(nonce),
					)
				},
			};

		// `Relaxed` will only be ever set in case of off-chain execution.
		// Instantiations are never allowed even when executing off-chain.
		if !(executable.is_deterministic() ||
			(matches!(determinism, Determinism::Relaxed) &&
				matches!(entry_point, ExportedFunction::Call)))
		{
			return Err(Error::<T>::Indeterministic.into())
		}

		let frame = Frame {
			delegate_caller,
			value_transferred,
			contract_info: CachedContract::Cached(contract_info),
			account_id,
			entry_point,
			nested_gas: gas_meter.nested(gas_limit),
			nested_storage: storage_meter.nested(deposit_limit),
			allows_reentry: true,
		};

		Ok((frame, executable, nonce))
	}

	/// Create a subsequent nested frame.
	fn push_frame(
		&mut self,
		frame_args: FrameArgs<T, E>,
		value_transferred: BalanceOf<T>,
		gas_limit: Weight,
		deposit_limit: BalanceOf<T>,
	) -> Result<E, ExecError> {
		if self.frames.len() == T::CallStack::size() {
			return Err(Error::<T>::MaxCallDepthReached.into())
		}

		// We need to make sure that changes made to the contract info are not discarded.
		// See the `in_memory_changes_not_discarded` test for more information.
		// We do not store on instantiate because we do not allow to call into a contract
		// from its own constructor.
		let frame = self.top_frame();
		if let (CachedContract::Cached(contract), ExportedFunction::Call) =
			(&frame.contract_info, frame.entry_point)
		{
			<ContractInfoOf<T>>::insert(frame.account_id.clone(), contract.clone());
		}

		let frame = top_frame_mut!(self);
		let nested_gas = &mut frame.nested_gas;
		let nested_storage = &mut frame.nested_storage;
		let (frame, executable, _) = Self::new_frame(
			frame_args,
			value_transferred,
			nested_gas,
			gas_limit,
			nested_storage,
			deposit_limit,
			self.determinism,
		)?;
		self.frames.push(frame);
		Ok(executable)
	}

	/// Run the current (top) frame.
	///
	/// This can be either a call or an instantiate.
	fn run(&mut self, executable: E, input_data: Vec<u8>) -> Result<ExecReturnValue, ExecError> {
		let frame = self.top_frame();
		let entry_point = frame.entry_point;
		let delegated_code_hash =
			if frame.delegate_caller.is_some() { Some(*executable.code_hash()) } else { None };
		let do_transaction = || {
			// We need to charge the storage deposit before the initial transfer so that
			// it can create the account in case the initial transfer is < ed.
			if entry_point == ExportedFunction::Constructor {
				// Root origin can't be used to instantiate a contract, so it is safe to assume that
				// if we reached this point the origin has an associated account.
				let origin = &self.origin.account_id()?;
				let frame = top_frame_mut!(self);
				frame.nested_storage.charge_instantiate(
					origin,
					&frame.account_id,
					frame.contract_info.get(&frame.account_id),
					executable.code_info(),
				)?;
			}

			// Every non delegate call or instantiate also optionally transfers the balance.
			self.initial_transfer()?;

			let contract_address = &top_frame!(self).account_id;

			let call_span = T::Debug::new_call_span(contract_address, entry_point, &input_data);

			let output = T::Debug::intercept_call(contract_address, &entry_point, &input_data)
				.unwrap_or_else(|| {
					executable
						.execute(self, &entry_point, input_data)
						.map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })
				})?;

			call_span.after_call(&output);

			// Avoid useless work that would be reverted anyways.
			if output.did_revert() {
				return Ok(output)
			}

			// Storage limit is normally enforced as late as possible (when the last frame returns)
			// so that the ordering of storage accesses does not matter.
			// (However, if a special limit was set for a sub-call, it should be enforced right
			// after the sub-call returned. See below for this case of enforcement).
			if self.frames.is_empty() {
				let frame = &mut self.first_frame;
				frame.contract_info.load(&frame.account_id);
				let contract = frame.contract_info.as_contract();
				frame.nested_storage.enforce_limit(contract)?;
			}

			let frame = self.top_frame();
			let account_id = &frame.account_id.clone();
			match (entry_point, delegated_code_hash) {
				(ExportedFunction::Constructor, _) => {
					// It is not allowed to terminate a contract inside its constructor.
					if matches!(frame.contract_info, CachedContract::Terminated) {
						return Err(Error::<T>::TerminatedInConstructor.into())
					}

					// If a special limit was set for the sub-call, we enforce it here.
					// This is needed because contract constructor might write to storage.
					// The sub-call will be rolled back in case the limit is exhausted.
					let frame = self.top_frame_mut();
					let contract = frame.contract_info.as_contract();
					frame.nested_storage.enforce_subcall_limit(contract)?;

					let caller = self.caller().account_id()?.clone();

					// Deposit an instantiation event.
					Contracts::<T>::deposit_event(
						vec![T::Hashing::hash_of(&caller), T::Hashing::hash_of(account_id)],
						Event::Instantiated { deployer: caller, contract: account_id.clone() },
					);
				},
				(ExportedFunction::Call, Some(code_hash)) => {
					Contracts::<T>::deposit_event(
						vec![T::Hashing::hash_of(account_id), T::Hashing::hash_of(&code_hash)],
						Event::DelegateCalled { contract: account_id.clone(), code_hash },
					);
				},
				(ExportedFunction::Call, None) => {
					// If a special limit was set for the sub-call, we enforce it here.
					// The sub-call will be rolled back in case the limit is exhausted.
					let frame = self.top_frame_mut();
					let contract = frame.contract_info.as_contract();
					frame.nested_storage.enforce_subcall_limit(contract)?;

					let caller = self.caller();
					Contracts::<T>::deposit_event(
						vec![T::Hashing::hash_of(&caller), T::Hashing::hash_of(&account_id)],
						Event::Called { caller: caller.clone(), contract: account_id.clone() },
					);
				},
			}

			Ok(output)
		};

		// All changes performed by the contract are executed under a storage transaction.
		// This allows for roll back on error. Changes to the cached contract_info are
		// committed or rolled back when popping the frame.
		//
		// `with_transactional` may return an error caused by a limit in the
		// transactional storage depth.
		let transaction_outcome =
			with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
				let output = do_transaction();
				match &output {
					Ok(result) if !result.did_revert() =>
						TransactionOutcome::Commit(Ok((true, output))),
					_ => TransactionOutcome::Rollback(Ok((false, output))),
				}
			});

		let (success, output) = match transaction_outcome {
			// `with_transactional` executed successfully, and we have the expected output.
			Ok((success, output)) => (success, output),
			// `with_transactional` returned an error, and we propagate that error and note no state
			// has changed.
			Err(error) => (false, Err(error.into())),
		};

		self.pop_frame(success);
		output
	}

	/// Remove the current (top) frame from the stack.
	///
	/// This is called after running the current frame. It commits cached values to storage
	/// and invalidates all stale references to it that might exist further down the call stack.
	fn pop_frame(&mut self, persist: bool) {
		// Revert changes to the nonce in case of a failed instantiation.
		if !persist && self.top_frame().entry_point == ExportedFunction::Constructor {
			self.nonce.as_mut().map(|c| *c = c.wrapping_sub(1));
		}

		// Pop the current frame from the stack and return it in case it needs to interact
		// with duplicates that might exist on the stack.
		// A `None` means that we are returning from the `first_frame`.
		let frame = self.frames.pop();

		// Both branches do essentially the same with the exception. The difference is that
		// the else branch does consume the hardcoded `first_frame`.
		if let Some(mut frame) = frame {
			let account_id = &frame.account_id;
			let prev = top_frame_mut!(self);

			prev.nested_gas.absorb_nested(frame.nested_gas);

			// Only gas counter changes are persisted in case of a failure.
			if !persist {
				return
			}

			// Record the storage meter changes of the nested call into the parent meter.
			// If the dropped frame's contract wasn't terminated we update the deposit counter
			// in its contract info. The load is necessary to pull it from storage in case
			// it was invalidated.
			frame.contract_info.load(account_id);
			let mut contract = frame.contract_info.into_contract();
			prev.nested_storage.absorb(frame.nested_storage, account_id, contract.as_mut());

			// In case the contract wasn't terminated we need to persist changes made to it.
			if let Some(contract) = contract {
				// optimization: Predecessor is the same contract.
				// We can just copy the contract into the predecessor without a storage write.
				// This is possible when there is no other contract in-between that could
				// trigger a rollback.
				if prev.account_id == *account_id {
					prev.contract_info = CachedContract::Cached(contract);
					return
				}

				// Predecessor is a different contract: We persist the info and invalidate the first
				// stale cache we find. This triggers a reload from storage on next use. We skip(1)
				// because that case is already handled by the optimization above. Only the first
				// cache needs to be invalidated because that one will invalidate the next cache
				// when it is popped from the stack.
				<ContractInfoOf<T>>::insert(account_id, contract);
				if let Some(c) = self.frames_mut().skip(1).find(|f| f.account_id == *account_id) {
					c.contract_info = CachedContract::Invalidated;
				}
			}
		} else {
			if let Some((msg, false)) = self.debug_message.as_ref().map(|m| (m, m.is_empty())) {
				log::debug!(
					target: LOG_TARGET,
					"Execution finished with debug buffer: {}",
					core::str::from_utf8(msg).unwrap_or("<Invalid UTF8>"),
				);
			}
			self.gas_meter.absorb_nested(mem::take(&mut self.first_frame.nested_gas));
			if !persist {
				return
			}
			let mut contract = self.first_frame.contract_info.as_contract();
			self.storage_meter.absorb(
				mem::take(&mut self.first_frame.nested_storage),
				&self.first_frame.account_id,
				contract.as_deref_mut(),
			);
			if let Some(contract) = contract {
				<ContractInfoOf<T>>::insert(&self.first_frame.account_id, contract);
			}
			if let Some(nonce) = self.nonce {
				<Nonce<T>>::set(nonce);
			}
		}
	}

	/// Transfer some funds from `from` to `to`.
	fn transfer(
		preservation: Preservation,
		from: &T::AccountId,
		to: &T::AccountId,
		value: BalanceOf<T>,
	) -> DispatchResult {
		if !value.is_zero() && from != to {
			T::Currency::transfer(from, to, value, preservation)
				.map_err(|_| Error::<T>::TransferFailed)?;
		}
		Ok(())
	}

	// The transfer as performed by a call or instantiate.
	fn initial_transfer(&self) -> DispatchResult {
		let frame = self.top_frame();

		// If it is a delegate call, then we've already transferred tokens in the
		// last non-delegate frame.
		if frame.delegate_caller.is_some() {
			return Ok(())
		}

		let value = frame.value_transferred;

		// Get the account id from the caller.
		// If the caller is root there is no account to transfer from, and therefore we can't take
		// any `value` other than 0.
		let caller = match self.caller() {
			Origin::Signed(caller) => caller,
			Origin::Root if value.is_zero() => return Ok(()),
			Origin::Root => return DispatchError::RootNotAllowed.into(),
		};
		Self::transfer(Preservation::Preserve, &caller, &frame.account_id, value)
	}

	/// Reference to the current (top) frame.
	fn top_frame(&self) -> &Frame<T> {
		top_frame!(self)
	}

	/// Mutable reference to the current (top) frame.
	fn top_frame_mut(&mut self) -> &mut Frame<T> {
		top_frame_mut!(self)
	}

	/// Iterator over all frames.
	///
	/// The iterator starts with the top frame and ends with the root frame.
	fn frames(&self) -> impl Iterator<Item = &Frame<T>> {
		sp_std::iter::once(&self.first_frame).chain(&self.frames).rev()
	}

	/// Same as `frames` but with a mutable reference as iterator item.
	fn frames_mut(&mut self) -> impl Iterator<Item = &mut Frame<T>> {
		sp_std::iter::once(&mut self.first_frame).chain(&mut self.frames).rev()
	}

	/// Returns whether the current contract is on the stack multiple times.
	fn is_recursive(&self) -> bool {
		let account_id = &self.top_frame().account_id;
		self.frames().skip(1).any(|f| &f.account_id == account_id)
	}

	/// Returns whether the specified contract allows to be reentered right now.
	fn allows_reentry(&self, id: &AccountIdOf<T>) -> bool {
		!self.frames().any(|f| &f.account_id == id && !f.allows_reentry)
	}

	/// Increments and returns the next nonce. Pulls it from storage if it isn't in cache.
	fn next_nonce(&mut self) -> u64 {
		let next = self.nonce().wrapping_add(1);
		self.nonce = Some(next);
		next
	}
}

impl<'a, T, E> Ext for Stack<'a, T, E>
where
	T: Config,
	E: Executable<T>,
{
	type T = T;

	fn call(
		&mut self,
		gas_limit: Weight,
		deposit_limit: BalanceOf<T>,
		to: T::AccountId,
		value: BalanceOf<T>,
		input_data: Vec<u8>,
		allows_reentry: bool,
	) -> Result<ExecReturnValue, ExecError> {
		// Before pushing the new frame: Protect the caller contract against reentrancy attacks.
		// It is important to do this before calling `allows_reentry` so that a direct recursion
		// is caught by it.
		self.top_frame_mut().allows_reentry = allows_reentry;

		let try_call = || {
			if !self.allows_reentry(&to) {
				return Err(<Error<T>>::ReentranceDenied.into())
			}
			// We ignore instantiate frames in our search for a cached contract.
			// Otherwise it would be possible to recursively call a contract from its own
			// constructor: We disallow calling not fully constructed contracts.
			let cached_info = self
				.frames()
				.find(|f| f.entry_point == ExportedFunction::Call && f.account_id == to)
				.and_then(|f| match &f.contract_info {
					CachedContract::Cached(contract) => Some(contract.clone()),
					_ => None,
				});
			let executable = self.push_frame(
				FrameArgs::Call { dest: to, cached_info, delegated_call: None },
				value,
				gas_limit,
				deposit_limit,
			)?;
			self.run(executable, input_data)
		};

		// We need to make sure to reset `allows_reentry` even on failure.
		let result = try_call();

		// Protection is on a per call basis.
		self.top_frame_mut().allows_reentry = true;

		result
	}

	fn delegate_call(
		&mut self,
		code_hash: CodeHash<Self::T>,
		input_data: Vec<u8>,
	) -> Result<ExecReturnValue, ExecError> {
		let executable = E::from_storage(code_hash, self.gas_meter_mut())?;
		let top_frame = self.top_frame_mut();
		let contract_info = top_frame.contract_info().clone();
		let account_id = top_frame.account_id.clone();
		let value = top_frame.value_transferred;
		let executable = self.push_frame(
			FrameArgs::Call {
				dest: account_id,
				cached_info: Some(contract_info),
				delegated_call: Some(DelegatedCall { executable, caller: self.caller().clone() }),
			},
			value,
			Weight::zero(),
			BalanceOf::<T>::zero(),
		)?;
		self.run(executable, input_data)
	}

	fn instantiate(
		&mut self,
		gas_limit: Weight,
		deposit_limit: BalanceOf<Self::T>,
		code_hash: CodeHash<T>,
		value: BalanceOf<T>,
		input_data: Vec<u8>,
		salt: &[u8],
	) -> Result<(AccountIdOf<T>, ExecReturnValue), ExecError> {
		let executable = E::from_storage(code_hash, self.gas_meter_mut())?;
		let nonce = self.next_nonce();
		let executable = self.push_frame(
			FrameArgs::Instantiate {
				sender: self.top_frame().account_id.clone(),
				nonce,
				executable,
				salt,
				input_data: input_data.as_ref(),
			},
			value,
			gas_limit,
			deposit_limit,
		)?;
		let account_id = self.top_frame().account_id.clone();
		self.run(executable, input_data).map(|ret| (account_id, ret))
	}

	fn terminate(&mut self, beneficiary: &AccountIdOf<Self::T>) -> Result<(), DispatchError> {
		if self.is_recursive() {
			return Err(Error::<T>::TerminatedWhileReentrant.into())
		}
		let frame = self.top_frame_mut();
		let info = frame.terminate();
		frame.nested_storage.terminate(&info, beneficiary.clone());

		info.queue_trie_for_deletion();
		ContractInfoOf::<T>::remove(&frame.account_id);
		Self::decrement_refcount(info.code_hash);

		for (code_hash, deposit) in info.delegate_dependencies() {
			Self::decrement_refcount(*code_hash);
			frame
				.nested_storage
				.charge_deposit(frame.account_id.clone(), StorageDeposit::Refund(*deposit));
		}

		Contracts::<T>::deposit_event(
			vec![T::Hashing::hash_of(&frame.account_id), T::Hashing::hash_of(&beneficiary)],
			Event::Terminated {
				contract: frame.account_id.clone(),
				beneficiary: beneficiary.clone(),
			},
		);
		Ok(())
	}

	fn transfer(&mut self, to: &T::AccountId, value: BalanceOf<T>) -> DispatchResult {
		Self::transfer(Preservation::Preserve, &self.top_frame().account_id, to, value)
	}

	fn get_storage(&mut self, key: &Key<T>) -> Option<Vec<u8>> {
		self.top_frame_mut().contract_info().read(key)
	}

	fn get_storage_size(&mut self, key: &Key<T>) -> Option<u32> {
		self.top_frame_mut().contract_info().size(key.into())
	}

	fn set_storage(
		&mut self,
		key: &Key<T>,
		value: Option<Vec<u8>>,
		take_old: bool,
	) -> Result<WriteOutcome, DispatchError> {
		let frame = self.top_frame_mut();
		frame.contract_info.get(&frame.account_id).write(
			key.into(),
			value,
			Some(&mut frame.nested_storage),
			take_old,
		)
	}

	fn address(&self) -> &T::AccountId {
		&self.top_frame().account_id
	}

	fn caller(&self) -> Origin<T> {
		if let Some(caller) = &self.top_frame().delegate_caller {
			caller.clone()
		} else {
			self.frames()
				.nth(1)
				.map(|f| Origin::from_account_id(f.account_id.clone()))
				.unwrap_or(self.origin.clone())
		}
	}

	fn is_contract(&self, address: &T::AccountId) -> bool {
		ContractInfoOf::<T>::contains_key(&address)
	}

	fn code_hash(&self, address: &T::AccountId) -> Option<CodeHash<Self::T>> {
		<ContractInfoOf<T>>::get(&address).map(|contract| contract.code_hash)
	}

	fn own_code_hash(&mut self) -> &CodeHash<Self::T> {
		&self.top_frame_mut().contract_info().code_hash
	}

	fn caller_is_origin(&self) -> bool {
		self.origin == self.caller()
	}

	fn caller_is_root(&self) -> bool {
		// if the caller isn't origin, then it can't be root.
		self.caller_is_origin() && self.origin == Origin::Root
	}

	fn balance(&self) -> BalanceOf<T> {
		T::Currency::reducible_balance(
			&self.top_frame().account_id,
			Preservation::Preserve,
			Fortitude::Polite,
		)
	}

	fn value_transferred(&self) -> BalanceOf<T> {
		self.top_frame().value_transferred
	}

	fn random(&self, subject: &[u8]) -> (SeedOf<T>, BlockNumberFor<T>) {
		T::Randomness::random(subject)
	}

	fn now(&self) -> &MomentOf<T> {
		&self.timestamp
	}

	fn minimum_balance(&self) -> BalanceOf<T> {
		T::Currency::minimum_balance()
	}

	fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) {
		Contracts::<Self::T>::deposit_event(
			topics,
			Event::ContractEmitted { contract: self.top_frame().account_id.clone(), data },
		);
	}

	fn block_number(&self) -> BlockNumberFor<T> {
		self.block_number
	}

	fn max_value_size(&self) -> u32 {
		self.schedule.limits.payload_len
	}

	fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
		T::WeightPrice::convert(weight)
	}

	fn schedule(&self) -> &Schedule<Self::T> {
		self.schedule
	}

	fn gas_meter(&self) -> &GasMeter<Self::T> {
		&self.top_frame().nested_gas
	}

	fn gas_meter_mut(&mut self) -> &mut GasMeter<Self::T> {
		&mut self.top_frame_mut().nested_gas
	}

	fn charge_storage(&mut self, diff: &Diff) {
		self.top_frame_mut().nested_storage.charge(diff)
	}

	fn debug_buffer_enabled(&self) -> bool {
		self.debug_message.is_some()
	}

	fn append_debug_buffer(&mut self, msg: &str) -> bool {
		if let Some(buffer) = &mut self.debug_message {
			buffer
				.try_extend(&mut msg.bytes())
				.map_err(|_| {
					log::debug!(
						target: LOG_TARGET,
						"Debug buffer (of {} bytes) exhausted!",
						DebugBufferVec::<T>::bound(),
					)
				})
				.ok();
			true
		} else {
			false
		}
	}

	fn call_runtime(&self, call: <Self::T as Config>::RuntimeCall) -> DispatchResultWithPostInfo {
		let mut origin: T::RuntimeOrigin = RawOrigin::Signed(self.address().clone()).into();
		origin.add_filter(T::CallFilter::contains);
		call.dispatch(origin)
	}

	fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
		secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
	}

	fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
		sp_io::crypto::sr25519_verify(
			&SR25519Signature::from(*signature),
			message,
			&SR25519Public::from(*pub_key),
		)
	}

	fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> {
		ECDSAPublic::from(*pk).to_eth_address()
	}

	#[cfg(test)]
	fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
		self.top_frame_mut().contract_info()
	}

	fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> Result<(), DispatchError> {
		let frame = top_frame_mut!(self);
		if !E::from_storage(hash, &mut frame.nested_gas)?.is_deterministic() {
			return Err(<Error<T>>::Indeterministic.into())
		}

		let info = frame.contract_info();

		let prev_hash = info.code_hash;
		info.code_hash = hash;

		let code_info = CodeInfoOf::<T>::get(hash).ok_or(Error::<T>::CodeNotFound)?;

		let old_base_deposit = info.storage_base_deposit();
		let new_base_deposit = info.update_base_deposit(&code_info);
		let deposit = StorageDeposit::Charge(new_base_deposit)
			.saturating_sub(&StorageDeposit::Charge(old_base_deposit));

		frame.nested_storage.charge_deposit(frame.account_id.clone(), deposit);

		Self::increment_refcount(hash)?;
		Self::decrement_refcount(prev_hash);
		Contracts::<Self::T>::deposit_event(
			vec![T::Hashing::hash_of(&frame.account_id), hash, prev_hash],
			Event::ContractCodeUpdated {
				contract: frame.account_id.clone(),
				new_code_hash: hash,
				old_code_hash: prev_hash,
			},
		);
		Ok(())
	}

	fn reentrance_count(&self) -> u32 {
		let id: &AccountIdOf<Self::T> = &self.top_frame().account_id;
		self.account_reentrance_count(id).saturating_sub(1)
	}

	fn account_reentrance_count(&self, account_id: &AccountIdOf<Self::T>) -> u32 {
		self.frames()
			.filter(|f| f.delegate_caller.is_none() && &f.account_id == account_id)
			.count() as u32
	}

	fn nonce(&mut self) -> u64 {
		if let Some(current) = self.nonce {
			current
		} else {
			let current = <Nonce<T>>::get();
			self.nonce = Some(current);
			current
		}
	}

	fn increment_refcount(code_hash: CodeHash<Self::T>) -> Result<(), DispatchError> {
		<CodeInfoOf<Self::T>>::mutate(code_hash, |existing| -> Result<(), DispatchError> {
			if let Some(info) = existing {
				*info.refcount_mut() = info.refcount().saturating_add(1);
				Ok(())
			} else {
				Err(Error::<T>::CodeNotFound.into())
			}
		})
	}

	fn decrement_refcount(code_hash: CodeHash<T>) {
		<CodeInfoOf<T>>::mutate(code_hash, |existing| {
			if let Some(info) = existing {
				*info.refcount_mut() = info.refcount().saturating_sub(1);
			}
		});
	}

	fn lock_delegate_dependency(
		&mut self,
		code_hash: CodeHash<Self::T>,
	) -> Result<(), DispatchError> {
		let frame = self.top_frame_mut();
		let info = frame.contract_info.get(&frame.account_id);
		ensure!(code_hash != info.code_hash, Error::<T>::CannotAddSelfAsDelegateDependency);

		let code_info = CodeInfoOf::<T>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
		let deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit());

		info.lock_delegate_dependency(code_hash, deposit)?;
		Self::increment_refcount(code_hash)?;
		frame
			.nested_storage
			.charge_deposit(frame.account_id.clone(), StorageDeposit::Charge(deposit));
		Ok(())
	}

	fn unlock_delegate_dependency(
		&mut self,
		code_hash: &CodeHash<Self::T>,
	) -> Result<(), DispatchError> {
		let frame = self.top_frame_mut();
		let info = frame.contract_info.get(&frame.account_id);

		let deposit = info.unlock_delegate_dependency(code_hash)?;
		Self::decrement_refcount(*code_hash);
		frame
			.nested_storage
			.charge_deposit(frame.account_id.clone(), StorageDeposit::Refund(deposit));
		Ok(())
	}
}

mod sealing {
	use super::*;

	pub trait Sealed {}

	impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {}

	#[cfg(test)]
	impl Sealed for crate::wasm::MockExt {}

	#[cfg(test)]
	impl Sealed for &mut crate::wasm::MockExt {}
}

/// These tests exercise the executive layer.
///
/// In these tests the VM/loader are mocked. Instead of dealing with wasm bytecode they use simple
/// closures. This allows you to tackle executive logic more thoroughly without writing a
/// wasm VM code.
#[cfg(test)]
mod tests {
	use super::*;
	use crate::{
		exec::ExportedFunction::*,
		gas::GasMeter,
		tests::{
			test_utils::{get_balance, hash, place_contract, set_balance},
			ExtBuilder, RuntimeCall, RuntimeEvent as MetaEvent, Test, TestFilter, ALICE, BOB,
			CHARLIE, GAS_LIMIT,
		},
		Error,
	};
	use assert_matches::assert_matches;
	use codec::{Decode, Encode};
	use frame_support::{assert_err, assert_ok, parameter_types};
	use frame_system::{EventRecord, Phase};
	use pallet_contracts_uapi::ReturnFlags;
	use pretty_assertions::assert_eq;
	use sp_runtime::{traits::Hash, DispatchError};
	use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc};

	type System = frame_system::Pallet<Test>;

	type MockStack<'a> = Stack<'a, Test, MockExecutable>;

	parameter_types! {
		static Loader: MockLoader = MockLoader::default();
	}

	fn events() -> Vec<Event<Test>> {
		System::events()
			.into_iter()
			.filter_map(|meta| match meta.event {
				MetaEvent::Contracts(contract_event) => Some(contract_event),
				_ => None,
			})
			.collect()
	}

	struct MockCtx<'a> {
		ext: &'a mut MockStack<'a>,
		input_data: Vec<u8>,
	}

	#[derive(Clone)]
	struct MockExecutable {
		func: Rc<dyn for<'a> Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>,
		func_type: ExportedFunction,
		code_hash: CodeHash<Test>,
		code_info: CodeInfo<Test>,
	}

	#[derive(Default, Clone)]
	pub struct MockLoader {
		map: HashMap<CodeHash<Test>, MockExecutable>,
		counter: u64,
	}

	impl MockLoader {
		fn code_hashes() -> Vec<CodeHash<Test>> {
			Loader::get().map.keys().copied().collect()
		}

		fn insert(
			func_type: ExportedFunction,
			f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static,
		) -> CodeHash<Test> {
			Loader::mutate(|loader| {
				// Generate code hashes as monotonically increasing values.
				let hash = <Test as frame_system::Config>::Hash::from_low_u64_be(loader.counter);
				loader.counter += 1;
				loader.map.insert(
					hash,
					MockExecutable {
						func: Rc::new(f),
						func_type,
						code_hash: hash,
						code_info: CodeInfo::<Test>::new(ALICE),
					},
				);
				hash
			})
		}
	}

	impl Executable<Test> for MockExecutable {
		fn from_storage(
			code_hash: CodeHash<Test>,
			_gas_meter: &mut GasMeter<Test>,
		) -> Result<Self, DispatchError> {
			Loader::mutate(|loader| {
				loader.map.get(&code_hash).cloned().ok_or(Error::<Test>::CodeNotFound.into())
			})
		}

		fn execute<E: Ext<T = Test>>(
			self,
			ext: &mut E,
			function: &ExportedFunction,
			input_data: Vec<u8>,
		) -> ExecResult {
			if let &Constructor = function {
				E::increment_refcount(self.code_hash).unwrap();
			}
			// # Safety
			//
			// We know that we **always** call execute with a `MockStack` in this test.
			//
			// # Note
			//
			// The transmute is necessary because `execute` has to be generic over all
			// `E: Ext`. However, `MockExecutable` can't be generic over `E` as it would
			// constitute a cycle.
			let ext = unsafe { mem::transmute(ext) };
			if function == &self.func_type {
				(self.func)(MockCtx { ext, input_data }, &self)
			} else {
				exec_success()
			}
		}

		fn code_hash(&self) -> &CodeHash<Test> {
			&self.code_hash
		}

		fn code_info(&self) -> &CodeInfo<Test> {
			&self.code_info
		}

		fn code_len(&self) -> u32 {
			0
		}

		fn is_deterministic(&self) -> bool {
			true
		}
	}

	fn exec_success() -> ExecResult {
		Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
	}

	fn exec_trapped() -> ExecResult {
		Err(ExecError { error: <Error<Test>>::ContractTrapped.into(), origin: ErrorOrigin::Callee })
	}

	#[test]
	fn it_works() {
		parameter_types! {
			static TestData: Vec<usize> = vec![0];
		}

		let value = Default::default();
		let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
		let exec_ch = MockLoader::insert(Call, |_ctx, _executable| {
			TestData::mutate(|data| data.push(1));
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, exec_ch);
			let mut storage_meter =
				storage::meter::Meter::new(&Origin::from_account_id(ALICE), Some(0), value)
					.unwrap();

			assert_matches!(
				MockStack::run_call(
					Origin::from_account_id(ALICE),
					BOB,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					value,
					vec![],
					None,
					Determinism::Enforced,
				),
				Ok(_)
			);
		});

		assert_eq!(TestData::get(), vec![0, 1]);
	}

	#[test]
	fn transfer_works() {
		// This test verifies that a contract is able to transfer
		// some funds to another account.
		let origin = ALICE;
		let dest = BOB;

		ExtBuilder::default().build().execute_with(|| {
			set_balance(&origin, 100);
			set_balance(&dest, 0);

			MockStack::transfer(Preservation::Preserve, &origin, &dest, 55).unwrap();

			assert_eq!(get_balance(&origin), 45);
			assert_eq!(get_balance(&dest), 55);
		});
	}

	#[test]
	fn correct_transfer_on_call() {
		let origin = ALICE;
		let dest = BOB;
		let value = 55;

		let success_ch = MockLoader::insert(Call, move |ctx, _| {
			assert_eq!(ctx.ext.value_transferred(), value);
			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&dest, success_ch);
			set_balance(&origin, 100);
			let balance = get_balance(&dest);
			let contract_origin = Origin::from_account_id(origin.clone());
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), value).unwrap();

			let _ = MockStack::run_call(
				contract_origin.clone(),
				dest.clone(),
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				value,
				vec![],
				None,
				Determinism::Enforced,
			)
			.unwrap();

			assert_eq!(get_balance(&origin), 100 - value);
			assert_eq!(get_balance(&dest), balance + value);
		});
	}

	#[test]
	fn correct_transfer_on_delegate_call() {
		let origin = ALICE;
		let dest = BOB;
		let value = 35;

		let success_ch = MockLoader::insert(Call, move |ctx, _| {
			assert_eq!(ctx.ext.value_transferred(), value);
			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
		});

		let delegate_ch = MockLoader::insert(Call, move |ctx, _| {
			assert_eq!(ctx.ext.value_transferred(), value);
			let _ = ctx.ext.delegate_call(success_ch, Vec::new())?;
			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&dest, delegate_ch);
			set_balance(&origin, 100);
			let balance = get_balance(&dest);
			let contract_origin = Origin::from_account_id(origin.clone());
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 55).unwrap();

			let _ = MockStack::run_call(
				contract_origin.clone(),
				dest.clone(),
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				value,
				vec![],
				None,
				Determinism::Enforced,
			)
			.unwrap();

			assert_eq!(get_balance(&origin), 100 - value);
			assert_eq!(get_balance(&dest), balance + value);
		});
	}

	#[test]
	fn changes_are_reverted_on_failing_call() {
		// This test verifies that changes are reverted on a call which fails (or equally, returns
		// a non-zero status code).
		let origin = ALICE;
		let dest = BOB;

		let return_ch = MockLoader::insert(Call, |_, _| {
			Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() })
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&dest, return_ch);
			set_balance(&origin, 100);
			let balance = get_balance(&dest);
			let contract_origin = Origin::from_account_id(origin.clone());
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 55).unwrap();

			let output = MockStack::run_call(
				contract_origin.clone(),
				dest.clone(),
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				55,
				vec![],
				None,
				Determinism::Enforced,
			)
			.unwrap();

			assert!(output.did_revert());
			assert_eq!(get_balance(&origin), 100);
			assert_eq!(get_balance(&dest), balance);
		});
	}

	#[test]
	fn balance_too_low() {
		// This test verifies that a contract can't send value if it's
		// balance is too low.
		let origin = ALICE;
		let dest = BOB;

		ExtBuilder::default().build().execute_with(|| {
			set_balance(&origin, 0);

			let result = MockStack::transfer(Preservation::Preserve, &origin, &dest, 100);

			assert_eq!(result, Err(Error::<Test>::TransferFailed.into()));
			assert_eq!(get_balance(&origin), 0);
			assert_eq!(get_balance(&dest), 0);
		});
	}

	#[test]
	fn output_is_returned_on_success() {
		// Verifies that if a contract returns data with a successful exit status, this data
		// is returned from the execution context.
		let origin = ALICE;
		let dest = BOB;
		let return_ch = MockLoader::insert(Call, |_, _| {
			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] })
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			let contract_origin = Origin::from_account_id(origin);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			place_contract(&BOB, return_ch);

			let result = MockStack::run_call(
				contract_origin,
				dest,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);

			let output = result.unwrap();
			assert!(!output.did_revert());
			assert_eq!(output.data, vec![1, 2, 3, 4]);
		});
	}

	#[test]
	fn output_is_returned_on_failure() {
		// Verifies that if a contract returns data with a failing exit status, this data
		// is returned from the execution context.
		let origin = ALICE;
		let dest = BOB;
		let return_ch = MockLoader::insert(Call, |_, _| {
			Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![1, 2, 3, 4] })
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, return_ch);
			let contract_origin = Origin::from_account_id(origin);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			let result = MockStack::run_call(
				contract_origin,
				dest,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);

			let output = result.unwrap();
			assert!(output.did_revert());
			assert_eq!(output.data, vec![1, 2, 3, 4]);
		});
	}

	#[test]
	fn input_data_to_call() {
		let input_data_ch = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(ctx.input_data, &[1, 2, 3, 4]);
			exec_success()
		});

		// This one tests passing the input data into a contract via call.
		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, input_data_ch);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![1, 2, 3, 4],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn input_data_to_instantiate() {
		let input_data_ch = MockLoader::insert(Constructor, |ctx, _| {
			assert_eq!(ctx.input_data, &[1, 2, 3, 4]);
			exec_success()
		});

		// This one tests passing the input data into a contract via instantiate.
		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let executable =
					MockExecutable::from_storage(input_data_ch, &mut gas_meter).unwrap();
				set_balance(&ALICE, min_balance * 10_000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap();

				let result = MockStack::run_instantiate(
					ALICE,
					executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance,
					vec![1, 2, 3, 4],
					&[],
					None,
				);
				assert_matches!(result, Ok(_));
			});
	}

	#[test]
	fn max_depth() {
		// This test verifies that when we reach the maximal depth creation of an
		// yet another context fails.
		parameter_types! {
			static ReachedBottom: bool = false;
		}
		let value = Default::default();
		let recurse_ch = MockLoader::insert(Call, |ctx, _| {
			// Try to call into yourself.
			let r = ctx.ext.call(Weight::zero(), BalanceOf::<Test>::zero(), BOB, 0, vec![], true);

			ReachedBottom::mutate(|reached_bottom| {
				if !*reached_bottom {
					// We are first time here, it means we just reached bottom.
					// Verify that we've got proper error and set `reached_bottom`.
					assert_eq!(r, Err(Error::<Test>::MaxCallDepthReached.into()));
					*reached_bottom = true;
				} else {
					// We just unwinding stack here.
					assert_matches!(r, Ok(_));
				}
			});

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			set_balance(&BOB, 1);
			place_contract(&BOB, recurse_ch);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), value).unwrap();

			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				value,
				vec![],
				None,
				Determinism::Enforced,
			);

			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn caller_returns_proper_values() {
		let origin = ALICE;
		let dest = BOB;

		parameter_types! {
			static WitnessedCallerBob: Option<AccountIdOf<Test>> = None;
			static WitnessedCallerCharlie: Option<AccountIdOf<Test>> = None;
		}

		let bob_ch = MockLoader::insert(Call, |ctx, _| {
			// Record the caller for bob.
			WitnessedCallerBob::mutate(|caller| {
				*caller = Some(ctx.ext.caller().account_id().unwrap().clone())
			});

			// Call into CHARLIE contract.
			assert_matches!(
				ctx.ext
					.call(Weight::zero(), BalanceOf::<Test>::zero(), CHARLIE, 0, vec![], true),
				Ok(_)
			);
			exec_success()
		});
		let charlie_ch = MockLoader::insert(Call, |ctx, _| {
			// Record the caller for charlie.
			WitnessedCallerCharlie::mutate(|caller| {
				*caller = Some(ctx.ext.caller().account_id().unwrap().clone())
			});
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&dest, bob_ch);
			place_contract(&CHARLIE, charlie_ch);
			let contract_origin = Origin::from_account_id(origin.clone());
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			let result = MockStack::run_call(
				contract_origin.clone(),
				dest.clone(),
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);

			assert_matches!(result, Ok(_));
		});

		assert_eq!(WitnessedCallerBob::get(), Some(origin));
		assert_eq!(WitnessedCallerCharlie::get(), Some(dest));
	}

	#[test]
	fn is_contract_returns_proper_values() {
		let bob_ch = MockLoader::insert(Call, |ctx, _| {
			// Verify that BOB is a contract
			assert!(ctx.ext.is_contract(&BOB));
			// Verify that ALICE is not a contract
			assert!(!ctx.ext.is_contract(&ALICE));
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, bob_ch);

			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn code_hash_returns_proper_values() {
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			// ALICE is not a contract and hence they do not have a code_hash
			assert!(ctx.ext.code_hash(&ALICE).is_none());
			// BOB is a contract and hence it has a code_hash
			assert!(ctx.ext.code_hash(&BOB).is_some());
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// ALICE (not contract) -> BOB (contract)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn own_code_hash_returns_proper_values() {
		let bob_ch = MockLoader::insert(Call, |ctx, _| {
			let code_hash = ctx.ext.code_hash(&BOB).unwrap();
			assert_eq!(*ctx.ext.own_code_hash(), code_hash);
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, bob_ch);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// ALICE (not contract) -> BOB (contract)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn caller_is_origin_returns_proper_values() {
		let code_charlie = MockLoader::insert(Call, |ctx, _| {
			// BOB is not the origin of the stack call
			assert!(!ctx.ext.caller_is_origin());
			exec_success()
		});

		let code_bob = MockLoader::insert(Call, |ctx, _| {
			// ALICE is the origin of the call stack
			assert!(ctx.ext.caller_is_origin());
			// BOB calls CHARLIE
			ctx.ext
				.call(Weight::zero(), BalanceOf::<Test>::zero(), CHARLIE, 0, vec![], true)
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			place_contract(&CHARLIE, code_charlie);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// ALICE -> BOB (caller is origin) -> CHARLIE (caller is not origin)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn root_caller_succeeds() {
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			// root is the origin of the call stack.
			assert!(ctx.ext.caller_is_root());
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			let contract_origin = Origin::Root;
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// root -> BOB (caller is root)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn root_caller_does_not_succeed_when_value_not_zero() {
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			// root is the origin of the call stack.
			assert!(ctx.ext.caller_is_root());
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			let contract_origin = Origin::Root;
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// root -> BOB (caller is root)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				1,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Err(_));
		});
	}

	#[test]
	fn root_caller_succeeds_with_consecutive_calls() {
		let code_charlie = MockLoader::insert(Call, |ctx, _| {
			// BOB is not root, even though the origin is root.
			assert!(!ctx.ext.caller_is_root());
			exec_success()
		});

		let code_bob = MockLoader::insert(Call, |ctx, _| {
			// root is the origin of the call stack.
			assert!(ctx.ext.caller_is_root());
			// BOB calls CHARLIE.
			ctx.ext
				.call(Weight::zero(), BalanceOf::<Test>::zero(), CHARLIE, 0, vec![], true)
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			place_contract(&CHARLIE, code_charlie);
			let contract_origin = Origin::Root;
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			// root -> BOB (caller is root) -> CHARLIE (caller is not root)
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn address_returns_proper_values() {
		let bob_ch = MockLoader::insert(Call, |ctx, _| {
			// Verify that address matches BOB.
			assert_eq!(*ctx.ext.address(), BOB);

			// Call into charlie contract.
			assert_matches!(
				ctx.ext
					.call(Weight::zero(), BalanceOf::<Test>::zero(), CHARLIE, 0, vec![], true),
				Ok(_)
			);
			exec_success()
		});
		let charlie_ch = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(*ctx.ext.address(), CHARLIE);
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, bob_ch);
			place_contract(&CHARLIE, charlie_ch);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);

			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn refuse_instantiate_with_value_below_existential_deposit() {
		let dummy_ch = MockLoader::insert(Constructor, |_, _| exec_success());

		ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap();
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			assert_matches!(
				MockStack::run_instantiate(
					ALICE,
					executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					0, // <- zero value
					vec![],
					&[],
					None,
				),
				Err(_)
			);
		});
	}

	#[test]
	fn instantiation_work_with_success_output() {
		let dummy_ch = MockLoader::insert(Constructor, |_, _| {
			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] })
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.existential_deposit(15)
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap();
				set_balance(&ALICE, min_balance * 1000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter = storage::meter::Meter::new(
					&contract_origin,
					Some(min_balance * 100),
					min_balance,
				)
				.unwrap();

				let instantiated_contract_address = assert_matches!(
					MockStack::run_instantiate(
						ALICE,
						executable,
						&mut gas_meter,
						&mut storage_meter,
						&schedule,
						min_balance,
						vec![],
						&[],
						None,
					),
					Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address
				);

				// Check that the newly created account has the expected code hash and
				// there are instantiation event.
				assert_eq!(
					ContractInfo::<Test>::load_code_hash(&instantiated_contract_address).unwrap(),
					dummy_ch
				);
				assert_eq!(
					&events(),
					&[Event::Instantiated {
						deployer: ALICE,
						contract: instantiated_contract_address
					}]
				);
			});
	}

	#[test]
	fn instantiation_fails_with_failing_output() {
		let dummy_ch = MockLoader::insert(Constructor, |_, _| {
			Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] })
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.existential_deposit(15)
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap();
				set_balance(&ALICE, min_balance * 1000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter = storage::meter::Meter::new(
					&contract_origin,
					Some(min_balance * 100),
					min_balance,
				)
				.unwrap();

				let instantiated_contract_address = assert_matches!(
					MockStack::run_instantiate(
						ALICE,
						executable,
						&mut gas_meter,
						&mut storage_meter,
						&schedule,
						min_balance,
						vec![],
						&[],
						None,
					),
					Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address
				);

				// Check that the account has not been created.
				assert!(
					ContractInfo::<Test>::load_code_hash(&instantiated_contract_address).is_none()
				);
				assert!(events().is_empty());
			});
	}

	#[test]
	fn instantiation_from_contract() {
		let dummy_ch = MockLoader::insert(Call, |_, _| exec_success());
		let instantiated_contract_address = Rc::new(RefCell::new(None::<AccountIdOf<Test>>));
		let instantiator_ch = MockLoader::insert(Call, {
			let instantiated_contract_address = Rc::clone(&instantiated_contract_address);
			move |ctx, _| {
				// Instantiate a contract and save it's address in `instantiated_contract_address`.
				let (address, output) = ctx
					.ext
					.instantiate(
						Weight::zero(),
						BalanceOf::<Test>::zero(),
						dummy_ch,
						<Test as Config>::Currency::minimum_balance(),
						vec![],
						&[48, 49, 50],
					)
					.unwrap();

				*instantiated_contract_address.borrow_mut() = address.into();
				Ok(output)
			}
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.existential_deposit(15)
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				set_balance(&ALICE, min_balance * 100);
				place_contract(&BOB, instantiator_ch);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter = storage::meter::Meter::new(
					&contract_origin,
					Some(min_balance * 10),
					min_balance * 10,
				)
				.unwrap();

				assert_matches!(
					MockStack::run_call(
						contract_origin,
						BOB,
						&mut GasMeter::<Test>::new(GAS_LIMIT),
						&mut storage_meter,
						&schedule,
						min_balance * 10,
						vec![],
						None,
						Determinism::Enforced,
					),
					Ok(_)
				);

				let instantiated_contract_address =
					instantiated_contract_address.borrow().as_ref().unwrap().clone();

				// Check that the newly created account has the expected code hash and
				// there are instantiation event.
				assert_eq!(
					ContractInfo::<Test>::load_code_hash(&instantiated_contract_address).unwrap(),
					dummy_ch
				);
				assert_eq!(
					&events(),
					&[
						Event::Instantiated {
							deployer: BOB,
							contract: instantiated_contract_address
						},
						Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB },
					]
				);
			});
	}

	#[test]
	fn instantiation_traps() {
		let dummy_ch = MockLoader::insert(Constructor, |_, _| Err("It's a trap!".into()));
		let instantiator_ch = MockLoader::insert(Call, {
			move |ctx, _| {
				// Instantiate a contract and save it's address in `instantiated_contract_address`.
				assert_matches!(
					ctx.ext.instantiate(
						Weight::zero(),
						BalanceOf::<Test>::zero(),
						dummy_ch,
						<Test as Config>::Currency::minimum_balance(),
						vec![],
						&[],
					),
					Err(ExecError {
						error: DispatchError::Other("It's a trap!"),
						origin: ErrorOrigin::Callee,
					})
				);

				exec_success()
			}
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.existential_deposit(15)
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				set_balance(&ALICE, 1000);
				set_balance(&BOB, 100);
				place_contract(&BOB, instantiator_ch);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, Some(200), 0).unwrap();

				assert_matches!(
					MockStack::run_call(
						contract_origin,
						BOB,
						&mut GasMeter::<Test>::new(GAS_LIMIT),
						&mut storage_meter,
						&schedule,
						0,
						vec![],
						None,
						Determinism::Enforced,
					),
					Ok(_)
				);

				// The contract wasn't instantiated so we don't expect to see an instantiation
				// event here.
				assert_eq!(
					&events(),
					&[Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB },]
				);
			});
	}

	#[test]
	fn termination_from_instantiate_fails() {
		let terminate_ch = MockLoader::insert(Constructor, |ctx, _| {
			ctx.ext.terminate(&ALICE).unwrap();
			exec_success()
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.existential_deposit(15)
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let executable =
					MockExecutable::from_storage(terminate_ch, &mut gas_meter).unwrap();
				set_balance(&ALICE, 10_000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, None, 100).unwrap();

				assert_eq!(
					MockStack::run_instantiate(
						ALICE,
						executable,
						&mut gas_meter,
						&mut storage_meter,
						&schedule,
						100,
						vec![],
						&[],
						None,
					),
					Err(Error::<Test>::TerminatedInConstructor.into())
				);

				assert_eq!(&events(), &[]);
			});
	}

	#[test]
	fn in_memory_changes_not_discarded() {
		// Call stack: BOB -> CHARLIE (trap) -> BOB' (success)
		// This tests verifies some edge case of the contract info cache:
		// We change some value in our contract info before calling into a contract
		// that calls into ourself. This triggers a case where BOBs contract info
		// is written to storage and invalidated by the successful execution of BOB'.
		// The trap of CHARLIE reverts the storage changes to BOB. When the root BOB regains
		// control it reloads its contract info from storage. We check that changes that
		// are made before calling into CHARLIE are not discarded.
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			if ctx.input_data[0] == 0 {
				let info = ctx.ext.contract_info();
				assert_eq!(info.storage_byte_deposit, 0);
				info.storage_byte_deposit = 42;
				assert_eq!(
					ctx.ext.call(
						Weight::zero(),
						BalanceOf::<Test>::zero(),
						CHARLIE,
						0,
						vec![],
						true
					),
					exec_trapped()
				);
				assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42);
			}
			exec_success()
		});
		let code_charlie = MockLoader::insert(Call, |ctx, _| {
			assert!(ctx
				.ext
				.call(Weight::zero(), BalanceOf::<Test>::zero(), BOB, 0, vec![99], true)
				.is_ok());
			exec_trapped()
		});

		// This one tests passing the input data into a contract via call.
		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			place_contract(&CHARLIE, code_charlie);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![0],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn recursive_call_during_constructor_fails() {
		let code = MockLoader::insert(Constructor, |ctx, _| {
			assert_matches!(
				ctx.ext.call(Weight::zero(), BalanceOf::<Test>::zero(), ctx.ext.address().clone(), 0, vec![], true),
				Err(ExecError{error, ..}) if error == <Error<Test>>::ContractNotFound.into()
			);
			exec_success()
		});

		// This one tests passing the input data into a contract via instantiate.
		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let executable = MockExecutable::from_storage(code, &mut gas_meter).unwrap();
				set_balance(&ALICE, min_balance * 10_000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap();

				let result = MockStack::run_instantiate(
					ALICE,
					executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance,
					vec![],
					&[],
					None,
				);
				assert_matches!(result, Ok(_));
			});
	}

	#[test]
	fn printing_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			ctx.ext.append_debug_buffer("This is a test");
			ctx.ext.append_debug_buffer("More text");
			exec_success()
		});

		let mut debug_buffer = DebugBufferVec::<Test>::try_from(Vec::new()).unwrap();

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 10);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				Some(&mut debug_buffer),
				Determinism::Enforced,
			)
			.unwrap();
		});

		assert_eq!(&String::from_utf8(debug_buffer.to_vec()).unwrap(), "This is a testMore text");
	}

	#[test]
	fn printing_works_on_fail() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			ctx.ext.append_debug_buffer("This is a test");
			ctx.ext.append_debug_buffer("More text");
			exec_trapped()
		});

		let mut debug_buffer = DebugBufferVec::<Test>::try_from(Vec::new()).unwrap();

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 10);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				Some(&mut debug_buffer),
				Determinism::Enforced,
			);
			assert!(result.is_err());
		});

		assert_eq!(&String::from_utf8(debug_buffer.to_vec()).unwrap(), "This is a testMore text");
	}

	#[test]
	fn debug_buffer_is_limited() {
		let code_hash = MockLoader::insert(Call, move |ctx, _| {
			ctx.ext.append_debug_buffer("overflowing bytes");
			exec_success()
		});

		// Pre-fill the buffer almost up to its limit, leaving not enough space to the message
		let debug_buf_before =
			DebugBufferVec::<Test>::try_from(vec![0u8; DebugBufferVec::<Test>::bound() - 5])
				.unwrap();
		let mut debug_buf_after = debug_buf_before.clone();

		ExtBuilder::default().build().execute_with(|| {
			let schedule: Schedule<Test> = <Test as Config>::Schedule::get();
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 10);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				Some(&mut debug_buf_after),
				Determinism::Enforced,
			)
			.unwrap();
			assert_eq!(debug_buf_before, debug_buf_after);
		});
	}

	#[test]
	fn call_reentry_direct_recursion() {
		// call the contract passed as input with disabled reentry
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			let dest = Decode::decode(&mut ctx.input_data.as_ref()).unwrap();
			ctx.ext.call(Weight::zero(), BalanceOf::<Test>::zero(), dest, 0, vec![], false)
		});

		let code_charlie = MockLoader::insert(Call, |_, _| exec_success());

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			place_contract(&CHARLIE, code_charlie);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			// Calling another contract should succeed
			assert_ok!(MockStack::run_call(
				contract_origin.clone(),
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				CHARLIE.encode(),
				None,
				Determinism::Enforced
			));

			// Calling into oneself fails
			assert_err!(
				MockStack::run_call(
					contract_origin,
					BOB,
					&mut GasMeter::<Test>::new(GAS_LIMIT),
					&mut storage_meter,
					&schedule,
					0,
					BOB.encode(),
					None,
					Determinism::Enforced
				)
				.map_err(|e| e.error),
				<Error<Test>>::ReentranceDenied,
			);
		});
	}

	#[test]
	fn call_deny_reentry() {
		let code_bob = MockLoader::insert(Call, |ctx, _| {
			if ctx.input_data[0] == 0 {
				ctx.ext
					.call(Weight::zero(), BalanceOf::<Test>::zero(), CHARLIE, 0, vec![], false)
			} else {
				exec_success()
			}
		});

		// call BOB with input set to '1'
		let code_charlie = MockLoader::insert(Call, |ctx, _| {
			ctx.ext.call(Weight::zero(), BalanceOf::<Test>::zero(), BOB, 0, vec![1], true)
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_bob);
			place_contract(&CHARLIE, code_charlie);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();

			// BOB -> CHARLIE -> BOB fails as BOB denies reentry.
			assert_err!(
				MockStack::run_call(
					contract_origin,
					BOB,
					&mut GasMeter::<Test>::new(GAS_LIMIT),
					&mut storage_meter,
					&schedule,
					0,
					vec![0],
					None,
					Determinism::Enforced
				)
				.map_err(|e| e.error),
				<Error<Test>>::ReentranceDenied,
			);
		});
	}

	#[test]
	fn call_runtime_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			let call = RuntimeCall::System(frame_system::Call::remark_with_event {
				remark: b"Hello World".to_vec(),
			});
			ctx.ext.call_runtime(call).unwrap();
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 10);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			System::reset_events();
			MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			)
			.unwrap();

			let remark_hash = <Test as frame_system::Config>::Hashing::hash(b"Hello World");
			assert_eq!(
				System::events(),
				vec![
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::System(frame_system::Event::Remarked {
							sender: BOB,
							hash: remark_hash
						}),
						topics: vec![],
					},
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::Contracts(crate::Event::Called {
							caller: Origin::from_account_id(ALICE),
							contract: BOB,
						}),
						topics: vec![hash(&Origin::<Test>::from_account_id(ALICE)), hash(&BOB)],
					},
				]
			);
		});
	}

	#[test]
	fn call_runtime_filter() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			use frame_system::Call as SysCall;
			use pallet_balances::Call as BalanceCall;
			use pallet_utility::Call as UtilCall;

			// remark should still be allowed
			let allowed_call =
				RuntimeCall::System(SysCall::remark_with_event { remark: b"Hello".to_vec() });

			// transfers are disallowed by the `TestFiler` (see below)
			let forbidden_call = RuntimeCall::Balances(BalanceCall::transfer_allow_death {
				dest: CHARLIE,
				value: 22,
			});

			// simple cases: direct call
			assert_err!(
				ctx.ext.call_runtime(forbidden_call.clone()),
				frame_system::Error::<Test>::CallFiltered
			);

			// as part of a patch: return is OK (but it interrupted the batch)
			assert_ok!(ctx.ext.call_runtime(RuntimeCall::Utility(UtilCall::batch {
				calls: vec![allowed_call.clone(), forbidden_call, allowed_call]
			})),);

			// the transfer wasn't performed
			assert_eq!(get_balance(&CHARLIE), 0);

			exec_success()
		});

		TestFilter::set_filter(|call| match call {
			RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) => false,
			_ => true,
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 10);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			System::reset_events();
			MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			)
			.unwrap();

			let remark_hash = <Test as frame_system::Config>::Hashing::hash(b"Hello");
			assert_eq!(
				System::events(),
				vec![
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::System(frame_system::Event::Remarked {
							sender: BOB,
							hash: remark_hash
						}),
						topics: vec![],
					},
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::Utility(pallet_utility::Event::ItemCompleted),
						topics: vec![],
					},
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::Utility(pallet_utility::Event::BatchInterrupted {
							index: 1,
							error: frame_system::Error::<Test>::CallFiltered.into()
						},),
						topics: vec![],
					},
					EventRecord {
						phase: Phase::Initialization,
						event: MetaEvent::Contracts(crate::Event::Called {
							caller: Origin::from_account_id(ALICE),
							contract: BOB,
						}),
						topics: vec![hash(&Origin::<Test>::from_account_id(ALICE)), hash(&BOB)],
					},
				]
			);
		});
	}

	#[test]
	fn nonce() {
		let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped());
		let success_code = MockLoader::insert(Constructor, |_, _| exec_success());
		let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| {
			ctx.ext
				.instantiate(
					Weight::zero(),
					BalanceOf::<Test>::zero(),
					fail_code,
					ctx.ext.minimum_balance() * 100,
					vec![],
					&[],
				)
				.ok();
			exec_success()
		});
		let succ_succ_code = MockLoader::insert(Constructor, move |ctx, _| {
			let (account_id, _) = ctx
				.ext
				.instantiate(
					Weight::zero(),
					BalanceOf::<Test>::zero(),
					success_code,
					ctx.ext.minimum_balance() * 100,
					vec![],
					&[],
				)
				.unwrap();

			// a plain call should not influence the account counter
			ctx.ext
				.call(Weight::zero(), BalanceOf::<Test>::zero(), account_id, 0, vec![], false)
				.unwrap();

			exec_success()
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.build()
			.execute_with(|| {
				let schedule = <Test as Config>::Schedule::get();
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				let fail_executable =
					MockExecutable::from_storage(fail_code, &mut gas_meter).unwrap();
				let success_executable =
					MockExecutable::from_storage(success_code, &mut gas_meter).unwrap();
				let succ_fail_executable =
					MockExecutable::from_storage(succ_fail_code, &mut gas_meter).unwrap();
				let succ_succ_executable =
					MockExecutable::from_storage(succ_succ_code, &mut gas_meter).unwrap();
				set_balance(&ALICE, min_balance * 10_000);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, None, min_balance * 100).unwrap();

				MockStack::run_instantiate(
					ALICE,
					fail_executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance * 100,
					vec![],
					&[],
					None,
				)
				.ok();
				assert_eq!(<Nonce<Test>>::get(), 0);

				assert_ok!(MockStack::run_instantiate(
					ALICE,
					success_executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance * 100,
					vec![],
					&[],
					None,
				));
				assert_eq!(<Nonce<Test>>::get(), 1);

				assert_ok!(MockStack::run_instantiate(
					ALICE,
					succ_fail_executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance * 200,
					vec![],
					&[],
					None,
				));
				assert_eq!(<Nonce<Test>>::get(), 2);

				assert_ok!(MockStack::run_instantiate(
					ALICE,
					succ_succ_executable,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					min_balance * 200,
					vec![],
					&[],
					None,
				));
				assert_eq!(<Nonce<Test>>::get(), 4);
			});
	}

	#[test]
	fn set_storage_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			// Write
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([1; 32]), Some(vec![1, 2, 3]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![4, 5, 6]), true),
				Ok(WriteOutcome::New)
			);
			assert_eq!(ctx.ext.set_storage(&Key::Fix([3; 32]), None, false), Ok(WriteOutcome::New));
			assert_eq!(ctx.ext.set_storage(&Key::Fix([4; 32]), None, true), Ok(WriteOutcome::New));
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([5; 32]), Some(vec![]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([6; 32]), Some(vec![]), true),
				Ok(WriteOutcome::New)
			);

			// Overwrite
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([1; 32]), Some(vec![42]), false),
				Ok(WriteOutcome::Overwritten(3))
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![48]), true),
				Ok(WriteOutcome::Taken(vec![4, 5, 6]))
			);
			assert_eq!(ctx.ext.set_storage(&Key::Fix([3; 32]), None, false), Ok(WriteOutcome::New));
			assert_eq!(ctx.ext.set_storage(&Key::Fix([4; 32]), None, true), Ok(WriteOutcome::New));
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([5; 32]), Some(vec![]), false),
				Ok(WriteOutcome::Overwritten(0))
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([6; 32]), Some(vec![]), true),
				Ok(WriteOutcome::Taken(vec![]))
			);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn set_storage_varsized_key_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			// Write
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([1; 64].to_vec()).unwrap(),
					Some(vec![1, 2, 3]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([2; 19].to_vec()).unwrap(),
					Some(vec![4, 5, 6]),
					true
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([3; 19].to_vec()).unwrap(),
					None,
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([4; 64].to_vec()).unwrap(),
					None,
					true
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([5; 30].to_vec()).unwrap(),
					Some(vec![]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([6; 128].to_vec()).unwrap(),
					Some(vec![]),
					true
				),
				Ok(WriteOutcome::New)
			);

			// Overwrite
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([1; 64].to_vec()).unwrap(),
					Some(vec![42, 43, 44]),
					false
				),
				Ok(WriteOutcome::Overwritten(3))
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([2; 19].to_vec()).unwrap(),
					Some(vec![48]),
					true
				),
				Ok(WriteOutcome::Taken(vec![4, 5, 6]))
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([3; 19].to_vec()).unwrap(),
					None,
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([4; 64].to_vec()).unwrap(),
					None,
					true
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([5; 30].to_vec()).unwrap(),
					Some(vec![]),
					false
				),
				Ok(WriteOutcome::Overwritten(0))
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([6; 128].to_vec()).unwrap(),
					Some(vec![]),
					true
				),
				Ok(WriteOutcome::Taken(vec![]))
			);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn get_storage_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([1; 32]), Some(vec![1, 2, 3]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(ctx.ext.get_storage(&Key::Fix([1; 32])), Some(vec![1, 2, 3]));
			assert_eq!(ctx.ext.get_storage(&Key::Fix([2; 32])), Some(vec![]));
			assert_eq!(ctx.ext.get_storage(&Key::Fix([3; 32])), None);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn get_storage_size_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([1; 32]), Some(vec![1, 2, 3]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![]), false),
				Ok(WriteOutcome::New)
			);
			assert_eq!(ctx.ext.get_storage_size(&Key::Fix([1; 32])), Some(3));
			assert_eq!(ctx.ext.get_storage_size(&Key::Fix([2; 32])), Some(0));
			assert_eq!(ctx.ext.get_storage_size(&Key::Fix([3; 32])), None);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn get_storage_varsized_key_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([1; 19].to_vec()).unwrap(),
					Some(vec![1, 2, 3]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([2; 16].to_vec()).unwrap(),
					Some(vec![]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.get_storage(&Key::<Test>::try_from_var([1; 19].to_vec()).unwrap()),
				Some(vec![1, 2, 3])
			);
			assert_eq!(
				ctx.ext.get_storage(&Key::<Test>::try_from_var([2; 16].to_vec()).unwrap()),
				Some(vec![])
			);
			assert_eq!(
				ctx.ext.get_storage(&Key::<Test>::try_from_var([3; 8].to_vec()).unwrap()),
				None
			);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn get_storage_size_varsized_key_works() {
		let code_hash = MockLoader::insert(Call, |ctx, _| {
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([1; 19].to_vec()).unwrap(),
					Some(vec![1, 2, 3]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.set_storage(
					&Key::<Test>::try_from_var([2; 16].to_vec()).unwrap(),
					Some(vec![]),
					false
				),
				Ok(WriteOutcome::New)
			);
			assert_eq!(
				ctx.ext.get_storage_size(&Key::<Test>::try_from_var([1; 19].to_vec()).unwrap()),
				Some(3)
			);
			assert_eq!(
				ctx.ext.get_storage_size(&Key::<Test>::try_from_var([2; 16].to_vec()).unwrap()),
				Some(0)
			);
			assert_eq!(
				ctx.ext.get_storage_size(&Key::<Test>::try_from_var([3; 8].to_vec()).unwrap()),
				None
			);

			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let min_balance = <Test as Config>::Currency::minimum_balance();
			let schedule = <Test as Config>::Schedule::get();
			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
			set_balance(&ALICE, min_balance * 1000);
			place_contract(&BOB, code_hash);
			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
			assert_ok!(MockStack::run_call(
				contract_origin,
				BOB,
				&mut gas_meter,
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced
			));
		});
	}

	#[test]
	fn ecdsa_to_eth_address_returns_proper_value() {
		let bob_ch = MockLoader::insert(Call, |ctx, _| {
			let pubkey_compressed = array_bytes::hex2array_unchecked(
				"028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91",
			);
			assert_eq!(
				ctx.ext.ecdsa_to_eth_address(&pubkey_compressed).unwrap(),
				array_bytes::hex2array_unchecked::<_, 20>(
					"09231da7b19A016f9e576d23B16277062F4d46A8"
				)
			);
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, bob_ch);

			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}

	#[test]
	fn nonce_api_works() {
		let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped());
		let success_code = MockLoader::insert(Constructor, |_, _| exec_success());
		let code_hash = MockLoader::insert(Call, move |ctx, _| {
			// It is set to one when this contract was instantiated by `place_contract`
			assert_eq!(ctx.ext.nonce(), 1);
			// Should not change without any instantiation in-between
			assert_eq!(ctx.ext.nonce(), 1);
			// Should not change with a failed instantiation
			assert_err!(
				ctx.ext.instantiate(
					Weight::zero(),
					BalanceOf::<Test>::zero(),
					fail_code,
					0,
					vec![],
					&[],
				),
				ExecError {
					error: <Error<Test>>::ContractTrapped.into(),
					origin: ErrorOrigin::Callee
				}
			);
			assert_eq!(ctx.ext.nonce(), 1);
			// Successful instantiation increments
			ctx.ext
				.instantiate(
					Weight::zero(),
					BalanceOf::<Test>::zero(),
					success_code,
					0,
					vec![],
					&[],
				)
				.unwrap();
			assert_eq!(ctx.ext.nonce(), 2);
			exec_success()
		});

		ExtBuilder::default()
			.with_code_hashes(MockLoader::code_hashes())
			.build()
			.execute_with(|| {
				let min_balance = <Test as Config>::Currency::minimum_balance();
				let schedule = <Test as Config>::Schedule::get();
				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
				set_balance(&ALICE, min_balance * 1000);
				place_contract(&BOB, code_hash);
				let contract_origin = Origin::from_account_id(ALICE);
				let mut storage_meter =
					storage::meter::Meter::new(&contract_origin, None, 0).unwrap();
				assert_ok!(MockStack::run_call(
					contract_origin,
					BOB,
					&mut gas_meter,
					&mut storage_meter,
					&schedule,
					0,
					vec![],
					None,
					Determinism::Enforced
				));
			});
	}

	/// This works even though random interface is deprecated, as the check to ban deprecated
	/// functions happens in the wasm stack which is mocked for exec tests.
	#[test]
	fn randomness_works() {
		let subject = b"nice subject".as_ref();
		let code_hash = MockLoader::insert(Call, move |ctx, _| {
			let rand = <Test as Config>::Randomness::random(subject);
			assert_eq!(rand, ctx.ext.random(subject));
			exec_success()
		});

		ExtBuilder::default().build().execute_with(|| {
			let schedule = <Test as Config>::Schedule::get();
			place_contract(&BOB, code_hash);

			let contract_origin = Origin::from_account_id(ALICE);
			let mut storage_meter =
				storage::meter::Meter::new(&contract_origin, Some(0), 0).unwrap();
			let result = MockStack::run_call(
				contract_origin,
				BOB,
				&mut GasMeter::<Test>::new(GAS_LIMIT),
				&mut storage_meter,
				&schedule,
				0,
				vec![],
				None,
				Determinism::Enforced,
			);
			assert_matches!(result, Ok(_));
		});
	}
}
