git.delta.rocks / unique-network / refs/commits / e8fdadb89923

difftreelog

source

pallets/contracts/src/exec.rs52.7 KiBsourcehistory
1// This file is part of Substrate.23// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.1718use crate::{19	CodeHash, Event, Config, Pallet as Contracts, TrieId, BalanceOf, ContractInfo,20	gas::GasMeter,21	rent::Rent,22	storage::{self, Storage},23	Error, ContractInfoOf, Schedule, AliveContractInfo,24};25use sp_core::crypto::UncheckedFrom;26use sp_std::{prelude::*, marker::PhantomData};27use sp_runtime::{28	Perbill,29	traits::{Bounded, Zero, Convert, Saturating},30};31use frame_support::{32	dispatch::{DispatchResult, DispatchError},33	traits::{ExistenceRequirement, Currency, Time, Randomness, Get},34	weights::Weight,35	ensure,36};37use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};3839pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;40pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;41pub type SeedOf<T> = <T as frame_system::Config>::Hash;42pub type BlockNumberOf<T> = <T as frame_system::Config>::BlockNumber;43pub type StorageKey = [u8; 32];44pub type ExecResult = Result<ExecReturnValue, ExecError>;4546/// A type that represents a topic of an event. At the moment a hash is used.47pub type TopicOf<T> = <T as frame_system::Config>::Hash;4849/// Origin of the error.50///51/// Call or instantiate both called into other contracts and pass through errors happening52/// in those to the caller. This enum is for the caller to distinguish whether the error53/// happened during the execution of the callee or in the current execution context.54#[cfg_attr(test, derive(Debug, PartialEq))]55pub enum ErrorOrigin {56	/// Caller error origin.57	///58	/// The error happened in the current exeuction context rather than in the one59	/// of the contract that is called into.60	Caller,61	/// The error happened during execution of the called contract.62	Callee,63}6465/// Error returned by contract exection.66#[cfg_attr(test, derive(Debug, PartialEq))]67pub struct ExecError {68	/// The reason why the execution failed.69	pub error: DispatchError,70	/// Origin of the error.71	pub origin: ErrorOrigin,72}7374impl<T: Into<DispatchError>> From<T> for ExecError {75	fn from(error: T) -> Self {76		Self {77			error: error.into(),78			origin: ErrorOrigin::Caller,79		}80	}81}8283/// Information needed for rent calculations that can be requested by a contract.84#[derive(codec::Encode)]85#[cfg_attr(test, derive(Debug, PartialEq))]86pub struct RentParams<T: Config> {87	/// The total balance of the contract. Includes the balance transferred from the caller.88	total_balance: BalanceOf<T>,89	/// The free balance of the contract. Includes the balance transferred from the caller.90	free_balance: BalanceOf<T>,91	/// See crate [`Contracts::subsistence_threshold()`].92	subsistence_threshold: BalanceOf<T>,93	/// See crate [`Config::DepositPerContract`].94	deposit_per_contract: BalanceOf<T>,95	/// See crate [`Config::DepositPerStorageByte`].96	deposit_per_storage_byte: BalanceOf<T>,97	/// See crate [`Config::DepositPerStorageItem`].98	deposit_per_storage_item: BalanceOf<T>,99	/// See crate [`Ext::rent_allowance()`].100	rent_allowance: BalanceOf<T>,101	/// See crate [`Config::RentFraction`].102	rent_fraction: Perbill,103	/// See crate [`AliveContractInfo::storage_size`].104	storage_size: u32,105	/// See crate [`Executable::aggregate_code_len()`].106	code_size: u32,107	/// See crate [`Executable::refcount()`].108	code_refcount: u32,109	/// Reserved for backwards compatible changes to this data structure.110	_reserved: Option<()>,111}112113impl<T> RentParams<T>114where115	T: Config,116	T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,117{118	fn new<E: Executable<T>>(119		account_id: &T::AccountId,120		contract: &AliveContractInfo<T>,121		executable: &E,122	) -> Self {123		Self {124			total_balance: T::Currency::total_balance(account_id),125			free_balance: T::Currency::free_balance(account_id),126			subsistence_threshold: <Contracts<T>>::subsistence_threshold(),127			deposit_per_contract: T::DepositPerContract::get(),128			deposit_per_storage_byte: T::DepositPerStorageByte::get(),129			deposit_per_storage_item: T::DepositPerStorageItem::get(),130			rent_allowance: contract.rent_allowance,131			rent_fraction: T::RentFraction::get(),132			storage_size: contract.storage_size,133			code_size: executable.aggregate_code_len(),134			code_refcount: executable.refcount(),135			_reserved: None,136		}137	}138}139140/// We cannot derive `Default` because `T` does not necessarily implement `Default`.141#[cfg(test)]142impl<T: Config> Default for RentParams<T> {143	fn default() -> Self {144		Self {145			total_balance: Default::default(),146			free_balance: Default::default(),147			subsistence_threshold: Default::default(),148			deposit_per_contract: Default::default(),149			deposit_per_storage_byte: Default::default(),150			deposit_per_storage_item: Default::default(),151			rent_allowance: Default::default(),152			rent_fraction: Default::default(),153			storage_size: Default::default(),154			code_size: Default::default(),155			code_refcount: Default::default(),156			_reserved: Default::default(),157		}158	}159}160161/// An interface that provides access to the external environment in which the162/// smart-contract is executed.163///164/// This interface is specialized to an account of the executing code, so all165/// operations are implicitly performed on that account.166///167/// # Note168///169/// This trait is sealed and cannot be implemented by downstream crates.170pub trait Ext: sealing::Sealed {171	type T: Config;172173	/// Returns the storage entry of the executing account by the given `key`.174	///175	/// Returns `None` if the `key` wasn't previously set by `set_storage` or176	/// was deleted.177	fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>>;178179	/// Sets the storage entry by the given key to the specified value. If `value` is `None` then180	/// the storage entry is deleted.181	fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> DispatchResult;182183	/// Instantiate a contract from the given code.184	///185	/// Returns the original code size of the called contract.186	/// The newly created account will be associated with `code`. `value` specifies the amount of value187	/// transferred from this to the newly created account (also known as endowment).188	///189	/// # Return Value190	///191	/// Result<(AccountId, ExecReturnValue, CodeSize), (ExecError, CodeSize)>192	fn instantiate(193		&mut self,194		code: CodeHash<Self::T>,195		value: BalanceOf<Self::T>,196		gas_meter: &mut GasMeter<Self::T>,197		input_data: Vec<u8>,198		salt: &[u8],199	) -> Result<(AccountIdOf<Self::T>, ExecReturnValue, u32), (ExecError, u32)>;200201	/// Transfer some amount of funds into the specified account.202	fn transfer(&mut self, to: &AccountIdOf<Self::T>, value: BalanceOf<Self::T>) -> DispatchResult;203204	/// Transfer all funds to `beneficiary` and delete the contract.205	///206	/// Returns the original code size of the terminated contract.207	/// Since this function removes the self contract eagerly, if succeeded, no further actions should208	/// be performed on this `Ext` instance.209	///210	/// This function will fail if the same contract is present on the contract211	/// call stack.212	///213	/// # Return Value214	///215	/// Result<CodeSize, (DispatchError, CodeSize)>216	fn terminate(217		&mut self,218		beneficiary: &AccountIdOf<Self::T>,219	) -> Result<u32, (DispatchError, u32)>;220221	/// Call (possibly transferring some amount of funds) into the specified account.222	///223	/// Returns the original code size of the called contract.224	///225	/// # Return Value226	///227	/// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>228	fn call(229		&mut self,230		to: &AccountIdOf<Self::T>,231		value: BalanceOf<Self::T>,232		gas_meter: &mut GasMeter<Self::T>,233		input_data: Vec<u8>,234	) -> Result<(ExecReturnValue, u32), (ExecError, u32)>;235236	/// Restores the given destination contract sacrificing the current one.237	///238	/// Since this function removes the self contract eagerly, if succeeded, no further actions should239	/// be performed on this `Ext` instance.240	///241	/// This function will fail if the same contract is present242	/// on the contract call stack.243	///244	/// # Return Value245	///246	/// Result<(CallerCodeSize, DestCodeSize), (DispatchError, CallerCodeSize, DestCodesize)>247	fn restore_to(248		&mut self,249		dest: AccountIdOf<Self::T>,250		code_hash: CodeHash<Self::T>,251		rent_allowance: BalanceOf<Self::T>,252		delta: Vec<StorageKey>,253	) -> Result<(u32, u32), (DispatchError, u32, u32)>;254255	/// Returns a reference to the account id of the caller.256	fn caller(&self) -> &AccountIdOf<Self::T>;257258	/// Returns a reference to the account id of the current contract.259	fn address(&self) -> &AccountIdOf<Self::T>;260261	/// Returns the balance of the current contract.262	///263	/// The `value_transferred` is already added.264	fn balance(&self) -> BalanceOf<Self::T>;265266	/// Returns the value transferred along with this call or as endowment.267	fn value_transferred(&self) -> BalanceOf<Self::T>;268269	/// Returns a reference to the timestamp of the current block270	fn now(&self) -> &MomentOf<Self::T>;271272	/// Returns the minimum balance that is required for creating an account.273	fn minimum_balance(&self) -> BalanceOf<Self::T>;274275	/// Returns the deposit required to create a tombstone upon contract eviction.276	fn tombstone_deposit(&self) -> BalanceOf<Self::T>;277278	/// Returns a random number for the current block with the given subject.279	fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberOf<Self::T>);280281	/// Deposit an event with the given topics.282	///283	/// There should not be any duplicates in `topics`.284	fn deposit_event(&mut self, topics: Vec<TopicOf<Self::T>>, data: Vec<u8>);285286	/// Set rent allowance of the contract287	fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<Self::T>);288289	/// Rent allowance of the contract290	fn rent_allowance(&self) -> BalanceOf<Self::T>;291292	/// Returns the current block number.293	fn block_number(&self) -> BlockNumberOf<Self::T>;294295	/// Returns the maximum allowed size of a storage item.296	fn max_value_size(&self) -> u32;297298	/// Returns the price for the specified amount of weight.299	fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T>;300301	/// Get a reference to the schedule used by the current call.302	fn schedule(&self) -> &Schedule<Self::T>;303304	/// Information needed for rent calculations.305	fn rent_params(&self) -> &RentParams<Self::T>;306}307308/// Describes the different functions that can be exported by an [`Executable`].309#[cfg_attr(test, derive(Clone, Copy, PartialEq))]310pub enum ExportedFunction {311	/// The constructor function which is executed on deployment of a contract.312	Constructor,313	/// The function which is executed when a contract is called.314	Call,315}316317/// A trait that represents something that can be executed.318///319/// In the on-chain environment this would be represented by a wasm module. This trait exists in320/// order to be able to mock the wasm logic for testing.321pub trait Executable<T: Config>: Sized {322	/// Load the executable from storage.323	fn from_storage(324		code_hash: CodeHash<T>,325		schedule: &Schedule<T>,326		gas_meter: &mut GasMeter<T>,327	) -> Result<Self, DispatchError>;328329	/// Load the module from storage without re-instrumenting it.330	///331	/// A code module is re-instrumented on-load when it was originally instrumented with332	/// an older schedule. This skips this step for cases where the code storage is333	/// queried for purposes other than execution.334	fn from_storage_noinstr(code_hash: CodeHash<T>) -> Result<Self, DispatchError>;335336	/// Decrements the refcount by one and deletes the code if it drops to zero.337	fn drop_from_storage(self);338339	/// Increment the refcount by one. Fails if the code does not exist on-chain.340	///341	/// Returns the size of the original code.342	fn add_user(code_hash: CodeHash<T>) -> Result<u32, DispatchError>;343344	/// Decrement the refcount by one and remove the code when it drops to zero.345	///346	/// Returns the size of the original code.347	fn remove_user(code_hash: CodeHash<T>) -> u32;348349	/// Execute the specified exported function and return the result.350	///351	/// When the specified function is `Constructor` the executable is stored and its352	/// refcount incremented.353	///354	/// # Note355	///356	/// This functions expects to be executed in a storage transaction that rolls back357	/// all of its emitted storage changes.358	fn execute<E: Ext<T = T>>(359		self,360		ext: E,361		function: &ExportedFunction,362		input_data: Vec<u8>,363		gas_meter: &mut GasMeter<T>,364	) -> ExecResult;365366	/// The code hash of the executable.367	fn code_hash(&self) -> &CodeHash<T>;368369	/// The storage that is occupied by the instrumented executable and its pristine source.370	///371	/// The returned size is already divided by the number of users who share the code.372	/// This is essentially `aggregate_code_len() / refcount()`.373	///374	/// # Note375	///376	/// This works with the current in-memory value of refcount. When calling any contract377	/// without refetching this from storage the result can be inaccurate as it might be378	/// working with a stale value. Usually this inaccuracy is tolerable.379	fn occupied_storage(&self) -> u32;380381	/// Size of the instrumented code in bytes.382	fn code_len(&self) -> u32;383384	/// Sum of instrumented and pristine code len.385	fn aggregate_code_len(&self) -> u32;386387	// The number of contracts using this executable.388	fn refcount(&self) -> u32;389}390391pub struct ExecutionContext<'a, T: Config + 'a, E> {392	caller: Option<&'a ExecutionContext<'a, T, E>>,393	self_account: T::AccountId,394	self_trie_id: Option<TrieId>,395	depth: usize,396	schedule: &'a Schedule<T>,397	timestamp: MomentOf<T>,398	block_number: T::BlockNumber,399	_phantom: PhantomData<E>,400}401402impl<'a, T, E> ExecutionContext<'a, T, E>403where404	T: Config,405	T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,406	E: Executable<T>,407{408	/// Create the top level execution context.409	///410	/// The specified `origin` address will be used as `sender` for. The `origin` must be a regular411	/// account (not a contract).412	pub fn top_level(origin: T::AccountId, schedule: &'a Schedule<T>) -> Self {413		ExecutionContext {414			caller: None,415			self_trie_id: None,416			self_account: origin,417			depth: 0,418			schedule,419			timestamp: T::Time::now(),420			block_number: <frame_system::Pallet<T>>::block_number(),421			_phantom: Default::default(),422		}423	}424425	fn nested<'b, 'c: 'b>(426		&'c self,427		dest: T::AccountId,428		trie_id: TrieId,429	) -> ExecutionContext<'b, T, E> {430		ExecutionContext {431			caller: Some(self),432			self_trie_id: Some(trie_id),433			self_account: dest,434			depth: self.depth + 1,435			schedule: self.schedule,436			timestamp: self.timestamp.clone(),437			block_number: self.block_number.clone(),438			_phantom: Default::default(),439		}440	}441442	/// Make a call to the specified address, optionally transferring some funds.443	///444	/// # Return Value445	///446	/// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>447	pub fn call(448		&mut self,449		dest: T::AccountId,450		value: BalanceOf<T>,451		gas_meter: &mut GasMeter<T>,452		input_data: Vec<u8>,453	) -> Result<(ExecReturnValue, u32), (ExecError, u32)> {454		if self.depth == T::MaxDepth::get() as usize {455			return Err((Error::<T>::MaxCallDepthReached.into(), 0));456		}457458		let contract = <ContractInfoOf<T>>::get(&dest)459			.and_then(|contract| contract.get_alive())460			.ok_or((Error::<T>::NotCallable.into(), 0))?;461462		let executable = E::from_storage(contract.code_hash, &self.schedule, gas_meter)463			.map_err(|e| (e.into(), 0))?;464		let code_len = executable.code_len();465466		// This charges the rent and denies access to a contract that is in need of467		// eviction by returning `None`. We cannot evict eagerly here because those468		// changes would be rolled back in case this contract is called by another469		// contract.470		// See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324471		let contract = Rent::<T, E>::charge(&dest, contract, executable.occupied_storage())472			.map_err(|e| (e.into(), code_len))?473			.ok_or((Error::<T>::NotCallable.into(), code_len))?;474475		let transactor_kind = self.transactor_kind();476		let caller = self.self_account.clone();477478		let result = self479			.with_nested_context(dest.clone(), contract.trie_id.clone(), |nested| {480				if value > BalanceOf::<T>::zero() {481					transfer::<T>(TransferCause::Call, transactor_kind, &caller, &dest, value)?482				}483484				let call_context =485					nested.new_call_context(caller, &dest, value, &contract, &executable);486487				let output = executable488					.execute(call_context, &ExportedFunction::Call, input_data, gas_meter)489					.map_err(|e| ExecError {490						error: e.error,491						origin: ErrorOrigin::Callee,492					})?;493				Ok(output)494			})495			.map_err(|e| (e, code_len))?;496		Ok((result, code_len))497	}498499	pub fn instantiate(500		&mut self,501		endowment: BalanceOf<T>,502		gas_meter: &mut GasMeter<T>,503		executable: E,504		input_data: Vec<u8>,505		salt: &[u8],506	) -> Result<(T::AccountId, ExecReturnValue), ExecError> {507		if self.depth == T::MaxDepth::get() as usize {508			Err(Error::<T>::MaxCallDepthReached)?509		}510511		let transactor_kind = self.transactor_kind();512		let caller = self.self_account.clone();513		let dest = Contracts::<T>::contract_address(&caller, executable.code_hash(), salt);514515		let output = frame_support::storage::with_transaction(|| {516			// Generate the trie id in a new transaction to only increment the counter on success.517			let dest_trie_id = Storage::<T>::generate_trie_id(&dest);518519			let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| {520				let contract = Storage::<T>::place_contract(521					&dest,522					nested523						.self_trie_id524						.clone()525						.expect("the nested context always has to have self_trie_id"),526					executable.code_hash().clone(),527				)?;528529				// Send funds unconditionally here. If the `endowment` is below existential_deposit530				// then error will be returned here.531				transfer::<T>(532					TransferCause::Instantiate,533					transactor_kind,534					&caller,535					&dest,536					endowment,537				)?;538539				// Cache the value before calling into the constructor because that540				// consumes the value. If the constructor creates additional contracts using541				// the same code hash we still charge the "1 block rent" as if they weren't542				// spawned. This is OK as overcharging is always safe.543				let occupied_storage = executable.occupied_storage();544545				let call_context = nested.new_call_context(546					caller.clone(),547					&dest,548					endowment,549					&contract,550					&executable,551				);552553				let output = executable554					.execute(555						call_context,556						&ExportedFunction::Constructor,557						input_data,558						gas_meter,559					)560					.map_err(|e| ExecError {561						error: e.error,562						origin: ErrorOrigin::Callee,563					})?;564565				// We need to re-fetch the contract because changes are written to storage566				// eagerly during execution.567				let contract = <ContractInfoOf<T>>::get(&dest)568					.and_then(|contract| contract.get_alive())569					.ok_or(Error::<T>::NotCallable)?;570571				// Collect the rent for the first block to prevent the creation of very large572				// contracts that never intended to pay for even one block.573				// This also makes sure that it is above the subsistence threshold574				// in order to keep up the guarantuee that we always leave a tombstone behind575				// with the exception of a contract that called `seal_terminate`.576				Rent::<T, E>::charge(&dest, contract, occupied_storage)?577					.ok_or(Error::<T>::NewContractNotFunded)?;578579				// Deposit an instantiation event.580				deposit_event::<T>(vec![], Event::Instantiated(caller.clone(), dest.clone()));581582				Ok(output)583			});584585			use frame_support::storage::TransactionOutcome::*;586			match output {587				Ok(_) => Commit(output),588				Err(_) => Rollback(output),589			}590		})?;591592		Ok((dest, output))593	}594595	fn new_call_context<'b>(596		&'b mut self,597		caller: T::AccountId,598		dest: &T::AccountId,599		value: BalanceOf<T>,600		contract: &AliveContractInfo<T>,601		executable: &E,602	) -> CallContext<'b, 'a, T, E> {603		let timestamp = self.timestamp.clone();604		let block_number = self.block_number.clone();605		CallContext {606			ctx: self,607			caller,608			value_transferred: value,609			timestamp,610			block_number,611			rent_params: RentParams::new(dest, contract, executable),612			_phantom: Default::default(),613		}614	}615616	/// Execute the given closure within a nested execution context.617	fn with_nested_context<F>(&mut self, dest: T::AccountId, trie_id: TrieId, func: F) -> ExecResult618	where619		F: FnOnce(&mut ExecutionContext<T, E>) -> ExecResult,620	{621		use frame_support::storage::TransactionOutcome::*;622		let mut nested = self.nested(dest, trie_id);623		frame_support::storage::with_transaction(|| {624			let output = func(&mut nested);625			match output {626				Ok(ref rv) if !rv.flags.contains(ReturnFlags::REVERT) => Commit(output),627				_ => Rollback(output),628			}629		})630	}631632	/// Returns whether a contract, identified by address, is currently live in the execution633	/// stack, meaning it is in the middle of an execution.634	fn is_live(&self, account: &T::AccountId) -> bool {635		&self.self_account == account || self.caller.map_or(false, |caller| caller.is_live(account))636	}637638	fn transactor_kind(&self) -> TransactorKind {639		if self.depth == 0 {640			debug_assert!(self.self_trie_id.is_none());641			debug_assert!(self.caller.is_none());642			debug_assert!(ContractInfoOf::<T>::get(&self.self_account).is_none());643			TransactorKind::PlainAccount644		} else {645			TransactorKind::Contract646		}647	}648}649650/// Describes whether we deal with a contract or a plain account.651enum TransactorKind {652	/// Transaction was initiated from a plain account. That can be either be through a653	/// signed transaction or through RPC.654	PlainAccount,655	/// The call was initiated by a contract account.656	Contract,657}658659/// Describes possible transfer causes.660enum TransferCause {661	Call,662	Instantiate,663	Terminate,664}665666/// Transfer some funds from `transactor` to `dest`.667///668/// We only allow allow for draining all funds of the sender if `cause` is669/// is specified as `Terminate`. Otherwise, any transfer that would bring the sender below the670/// subsistence threshold (for contracts) or the existential deposit (for plain accounts)671/// results in an error.672fn transfer<T: Config>(673	cause: TransferCause,674	origin: TransactorKind,675	transactor: &T::AccountId,676	dest: &T::AccountId,677	value: BalanceOf<T>,678) -> DispatchResult679where680	T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,681{682	use self::TransferCause::*;683	use self::TransactorKind::*;684685	// Only seal_terminate is allowed to bring the sender below the subsistence686	// threshold or even existential deposit.687	let existence_requirement = match (cause, origin) {688		(Terminate, _) => ExistenceRequirement::AllowDeath,689		(_, Contract) => {690			ensure!(691				T::Currency::total_balance(transactor).saturating_sub(value)692					>= Contracts::<T>::subsistence_threshold(),693				Error::<T>::BelowSubsistenceThreshold,694			);695			ExistenceRequirement::KeepAlive696		}697		(_, PlainAccount) => ExistenceRequirement::KeepAlive,698	};699700	T::Currency::transfer(transactor, dest, value, existence_requirement)701		.map_err(|_| Error::<T>::TransferFailed)?;702703	Ok(())704}705706/// A context that is active within a call.707///708/// This context has some invariants that must be held at all times. Specifically:709///`ctx` always points to a context of an alive contract. That implies that it has an existent710/// `self_trie_id`.711///712/// Be advised that there are brief time spans where these invariants could be invalidated.713/// For example, when a contract requests self-termination the contract is removed eagerly. That714/// implies that the control won't be returned to the contract anymore, but there is still some code715/// on the path of the return from that call context. Therefore, care must be taken in these716/// situations.717struct CallContext<'a, 'b: 'a, T: Config + 'b, E> {718	ctx: &'a mut ExecutionContext<'b, T, E>,719	caller: T::AccountId,720	value_transferred: BalanceOf<T>,721	timestamp: MomentOf<T>,722	block_number: T::BlockNumber,723	rent_params: RentParams<T>,724	_phantom: PhantomData<E>,725}726727impl<'a, 'b: 'a, T, E> Ext for CallContext<'a, 'b, T, E>728where729	T: Config + 'b,730	T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,731	E: Executable<T>,732{733	type T = T;734735	fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {736		let trie_id = self.ctx.self_trie_id.as_ref().expect(737			"`ctx.self_trie_id` points to an alive contract within the `CallContext`;\738				it cannot be `None`;\739				expect can't fail;\740				qed",741		);742		Storage::<T>::read(trie_id, key)743	}744745	fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> DispatchResult {746		let trie_id = self.ctx.self_trie_id.as_ref().expect(747			"`ctx.self_trie_id` points to an alive contract within the `CallContext`;\748				it cannot be `None`;\749				expect can't fail;\750				qed",751		);752		// write panics if the passed account is not alive.753		// the contract must be in the alive state within the `CallContext`;\754		// the contract cannot be absent in storage;755		// write cannot return `None`;756		// qed757		Storage::<T>::write(&self.ctx.self_account, trie_id, &key, value)758	}759760	fn instantiate(761		&mut self,762		code_hash: CodeHash<T>,763		endowment: BalanceOf<T>,764		gas_meter: &mut GasMeter<T>,765		input_data: Vec<u8>,766		salt: &[u8],767	) -> Result<(AccountIdOf<T>, ExecReturnValue, u32), (ExecError, u32)> {768		let executable =769			E::from_storage(code_hash, &self.ctx.schedule, gas_meter).map_err(|e| (e.into(), 0))?;770		let code_len = executable.code_len();771		self.ctx772			.instantiate(endowment, gas_meter, executable, input_data, salt)773			.map(|r| (r.0, r.1, code_len))774			.map_err(|e| (e, code_len))775	}776777	fn transfer(&mut self, to: &T::AccountId, value: BalanceOf<T>) -> DispatchResult {778		transfer::<T>(779			TransferCause::Call,780			TransactorKind::Contract,781			&self.ctx.self_account.clone(),782			to,783			value,784		)785	}786787	fn terminate(788		&mut self,789		beneficiary: &AccountIdOf<Self::T>,790	) -> Result<u32, (DispatchError, u32)> {791		let self_id = self.ctx.self_account.clone();792		let value = T::Currency::free_balance(&self_id);793		if let Some(caller_ctx) = self.ctx.caller {794			if caller_ctx.is_live(&self_id) {795				return Err((Error::<T>::ReentranceDenied.into(), 0));796			}797		}798		transfer::<T>(799			TransferCause::Terminate,800			TransactorKind::Contract,801			&self_id,802			beneficiary,803			value,804		)805		.map_err(|e| (e, 0))?;806		if let Some(ContractInfo::Alive(info)) = ContractInfoOf::<T>::take(&self_id) {807			Storage::<T>::queue_trie_for_deletion(&info).map_err(|e| (e, 0))?;808			let code_len = E::remove_user(info.code_hash);809			Contracts::<T>::deposit_event(Event::Terminated(self_id, beneficiary.clone()));810			Ok(code_len)811		} else {812			panic!(813				"this function is only invoked by in the context of a contract;\814				this contract is therefore alive;\815				qed"816			);817		}818	}819820	fn call(821		&mut self,822		to: &T::AccountId,823		value: BalanceOf<T>,824		gas_meter: &mut GasMeter<T>,825		input_data: Vec<u8>,826	) -> Result<(ExecReturnValue, u32), (ExecError, u32)> {827		self.ctx.call(to.clone(), value, gas_meter, input_data)828	}829830	fn restore_to(831		&mut self,832		dest: AccountIdOf<Self::T>,833		code_hash: CodeHash<Self::T>,834		rent_allowance: BalanceOf<Self::T>,835		delta: Vec<StorageKey>,836	) -> Result<(u32, u32), (DispatchError, u32, u32)> {837		if let Some(caller_ctx) = self.ctx.caller {838			if caller_ctx.is_live(&self.ctx.self_account) {839				return Err((Error::<T>::ReentranceDenied.into(), 0, 0));840			}841		}842843		let result = Rent::<T, E>::restore_to(844			self.ctx.self_account.clone(),845			dest.clone(),846			code_hash.clone(),847			rent_allowance,848			delta,849		);850		if let Ok(_) = result {851			deposit_event::<Self::T>(852				vec![],853				Event::Restored(854					self.ctx.self_account.clone(),855					dest,856					code_hash,857					rent_allowance,858				),859			);860		}861		result862	}863864	fn address(&self) -> &T::AccountId {865		&self.ctx.self_account866	}867868	fn caller(&self) -> &T::AccountId {869		&self.caller870	}871872	fn balance(&self) -> BalanceOf<T> {873		T::Currency::free_balance(&self.ctx.self_account)874	}875876	fn value_transferred(&self) -> BalanceOf<T> {877		self.value_transferred878	}879880	fn random(&self, subject: &[u8]) -> (SeedOf<T>, BlockNumberOf<T>) {881		T::Randomness::random(subject)882	}883884	fn now(&self) -> &MomentOf<T> {885		&self.timestamp886	}887888	fn minimum_balance(&self) -> BalanceOf<T> {889		T::Currency::minimum_balance()890	}891892	fn tombstone_deposit(&self) -> BalanceOf<T> {893		T::TombstoneDeposit::get()894	}895896	fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) {897		deposit_event::<Self::T>(898			topics,899			Event::ContractEmitted(self.ctx.self_account.clone(), data),900		);901	}902903	fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<T>) {904		if let Err(storage::ContractAbsentError) =905			Storage::<T>::set_rent_allowance(&self.ctx.self_account, rent_allowance)906		{907			panic!(908				"`self_account` points to an alive contract within the `CallContext`;909					set_rent_allowance cannot return `Err`; qed"910			);911		}912	}913914	fn rent_allowance(&self) -> BalanceOf<T> {915		Storage::<T>::rent_allowance(&self.ctx.self_account)916			.unwrap_or_else(|_| <BalanceOf<T>>::max_value()) // Must never be triggered actually917	}918919	fn block_number(&self) -> T::BlockNumber {920		self.block_number921	}922923	fn max_value_size(&self) -> u32 {924		T::MaxValueSize::get()925	}926927	fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {928		T::WeightPrice::convert(weight)929	}930931	fn schedule(&self) -> &Schedule<Self::T> {932		&self.ctx.schedule933	}934935	fn rent_params(&self) -> &RentParams<Self::T> {936		&self.rent_params937	}938}939940fn deposit_event<T: Config>(topics: Vec<T::Hash>, event: Event<T>) {941	<frame_system::Pallet<T>>::deposit_event_indexed(942		&*topics,943		<T as Config>::Event::from(event).into(),944	)945}946947mod sealing {948	use super::*;949950	pub trait Sealed {}951952	impl<'a, 'b: 'a, T: Config, E> Sealed for CallContext<'a, 'b, T, E> {}953954	#[cfg(test)]955	impl Sealed for crate::wasm::MockExt {}956957	#[cfg(test)]958	impl Sealed for &mut crate::wasm::MockExt {}959}960961/// These tests exercise the executive layer.962///963/// In these tests the VM/loader are mocked. Instead of dealing with wasm bytecode they use simple closures.964/// This allows you to tackle executive logic more thoroughly without writing a965/// wasm VM code.966#[cfg(test)]967mod tests {968	use super::*;969	use crate::{970		gas::GasMeter,971		tests::{ExtBuilder, Test, Event as MetaEvent},972		storage::{Storage, ContractAbsentError},973		tests::{974			ALICE, BOB, CHARLIE,975			test_utils::{place_contract, set_balance, get_balance},976		},977		exec::ExportedFunction::*,978		Error, Weight, CurrentSchedule,979	};980	use sp_core::Bytes;981	use frame_support::assert_noop;982	use sp_runtime::DispatchError;983	use assert_matches::assert_matches;984	use std::{cell::RefCell, collections::HashMap, rc::Rc};985	use pretty_assertions::{assert_eq, assert_ne};986987	type MockContext<'a> = ExecutionContext<'a, Test, MockExecutable>;988989	const GAS_LIMIT: Weight = 10_000_000_000;990991	thread_local! {992		static LOADER: RefCell<MockLoader> = RefCell::new(MockLoader::default());993	}994995	fn events() -> Vec<Event<Test>> {996		<frame_system::Pallet<Test>>::events()997			.into_iter()998			.filter_map(|meta| match meta.event {999				MetaEvent::pallet_contracts(contract_event) => Some(contract_event),1000				_ => None,1001			})1002			.collect()1003	}10041005	struct MockCtx<'a> {1006		ext: &'a mut dyn Ext<T = Test>,1007		input_data: Vec<u8>,1008		gas_meter: &'a mut GasMeter<Test>,1009	}10101011	#[derive(Clone)]1012	struct MockExecutable {1013		func: Rc<dyn Fn(MockCtx, &Self) -> ExecResult + 'static>,1014		func_type: ExportedFunction,1015		code_hash: CodeHash<Test>,1016		refcount: u64,1017	}10181019	#[derive(Default)]1020	struct MockLoader {1021		map: HashMap<CodeHash<Test>, MockExecutable>,1022		counter: u64,1023	}10241025	impl MockLoader {1026		fn insert(1027			func_type: ExportedFunction,1028			f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static,1029		) -> CodeHash<Test> {1030			LOADER.with(|loader| {1031				let mut loader = loader.borrow_mut();1032				// Generate code hashes as monotonically increasing values.1033				let hash = <Test as frame_system::Config>::Hash::from_low_u64_be(loader.counter);1034				loader.counter += 1;1035				loader.map.insert(1036					hash,1037					MockExecutable {1038						func: Rc::new(f),1039						func_type,1040						code_hash: hash.clone(),1041						refcount: 1,1042					},1043				);1044				hash1045			})1046		}10471048		fn increment_refcount(code_hash: CodeHash<Test>) {1049			LOADER.with(|loader| {1050				let mut loader = loader.borrow_mut();1051				loader1052					.map1053					.entry(code_hash)1054					.and_modify(|executable| executable.refcount += 1)1055					.or_insert_with(|| panic!("code_hash does not exist"));1056			});1057		}10581059		fn decrement_refcount(code_hash: CodeHash<Test>) {1060			use std::collections::hash_map::Entry::Occupied;1061			LOADER.with(|loader| {1062				let mut loader = loader.borrow_mut();1063				let mut entry = match loader.map.entry(code_hash) {1064					Occupied(e) => e,1065					_ => panic!("code_hash does not exist"),1066				};1067				let refcount = &mut entry.get_mut().refcount;1068				*refcount -= 1;1069				if *refcount == 0 {1070					entry.remove();1071				}1072			});1073		}10741075		fn refcount(code_hash: &CodeHash<Test>) -> u32 {1076			LOADER.with(|loader| {1077				loader1078					.borrow()1079					.map1080					.get(code_hash)1081					.expect("code_hash does not exist")1082					.refcount()1083			})1084		}1085	}10861087	impl Executable<Test> for MockExecutable {1088		fn from_storage(1089			code_hash: CodeHash<Test>,1090			_schedule: &Schedule<Test>,1091			_gas_meter: &mut GasMeter<Test>,1092		) -> Result<Self, DispatchError> {1093			Self::from_storage_noinstr(code_hash)1094		}10951096		fn from_storage_noinstr(code_hash: CodeHash<Test>) -> Result<Self, DispatchError> {1097			LOADER.with(|loader| {1098				loader1099					.borrow_mut()1100					.map1101					.get(&code_hash)1102					.cloned()1103					.ok_or(Error::<Test>::CodeNotFound.into())1104			})1105		}11061107		fn drop_from_storage(self) {1108			MockLoader::decrement_refcount(self.code_hash);1109		}11101111		fn add_user(code_hash: CodeHash<Test>) -> Result<u32, DispatchError> {1112			MockLoader::increment_refcount(code_hash);1113			Ok(0)1114		}11151116		fn remove_user(code_hash: CodeHash<Test>) -> u32 {1117			MockLoader::decrement_refcount(code_hash);1118			01119		}11201121		fn execute<E: Ext<T = Test>>(1122			self,1123			mut ext: E,1124			function: &ExportedFunction,1125			input_data: Vec<u8>,1126			gas_meter: &mut GasMeter<Test>,1127		) -> ExecResult {1128			if let &Constructor = function {1129				MockLoader::increment_refcount(self.code_hash);1130			}1131			if function == &self.func_type {1132				(self.func)(1133					MockCtx {1134						ext: &mut ext,1135						input_data,1136						gas_meter,1137					},1138					&self,1139				)1140			} else {1141				exec_success()1142			}1143		}11441145		fn code_hash(&self) -> &CodeHash<Test> {1146			&self.code_hash1147		}11481149		fn occupied_storage(&self) -> u32 {1150			01151		}11521153		fn code_len(&self) -> u32 {1154			01155		}11561157		fn aggregate_code_len(&self) -> u32 {1158			01159		}11601161		fn refcount(&self) -> u32 {1162			self.refcount as u321163		}1164	}11651166	fn exec_success() -> ExecResult {1167		Ok(ExecReturnValue {1168			flags: ReturnFlags::empty(),1169			data: Bytes(Vec::new()),1170		})1171	}11721173	#[test]1174	fn it_works() {1175		thread_local! {1176			static TEST_DATA: RefCell<Vec<usize>> = RefCell::new(vec![0]);1177		}11781179		let value = Default::default();1180		let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1181		let exec_ch = MockLoader::insert(Call, |_ctx, _executable| {1182			TEST_DATA.with(|data| data.borrow_mut().push(1));1183			exec_success()1184		});11851186		ExtBuilder::default().build().execute_with(|| {1187			let schedule = <CurrentSchedule<Test>>::get();1188			let mut ctx = MockContext::top_level(ALICE, &schedule);1189			place_contract(&BOB, exec_ch);11901191			assert_matches!(ctx.call(BOB, value, &mut gas_meter, vec![]), Ok(_));1192		});11931194		TEST_DATA.with(|data| assert_eq!(*data.borrow(), vec![0, 1]));1195	}11961197	#[test]1198	fn transfer_works() {1199		// This test verifies that a contract is able to transfer1200		// some funds to another account.1201		let origin = ALICE;1202		let dest = BOB;12031204		ExtBuilder::default().build().execute_with(|| {1205			set_balance(&origin, 100);1206			set_balance(&dest, 0);12071208			super::transfer::<Test>(1209				super::TransferCause::Call,1210				super::TransactorKind::PlainAccount,1211				&origin,1212				&dest,1213				55,1214			)1215			.unwrap();12161217			assert_eq!(get_balance(&origin), 45);1218			assert_eq!(get_balance(&dest), 55);1219		});1220	}12211222	#[test]1223	fn changes_are_reverted_on_failing_call() {1224		// This test verifies that changes are reverted on a call which fails (or equally, returns1225		// a non-zero status code).1226		let origin = ALICE;1227		let dest = BOB;12281229		let return_ch = MockLoader::insert(Call, |_, _| {1230			Ok(ExecReturnValue {1231				flags: ReturnFlags::REVERT,1232				data: Bytes(Vec::new()),1233			})1234		});12351236		ExtBuilder::default().build().execute_with(|| {1237			let schedule = <CurrentSchedule<Test>>::get();1238			let mut ctx = MockContext::top_level(origin.clone(), &schedule);1239			place_contract(&BOB, return_ch);1240			set_balance(&origin, 100);1241			let balance = get_balance(&dest);12421243			let output = ctx1244				.call(1245					dest.clone(),1246					55,1247					&mut GasMeter::<Test>::new(GAS_LIMIT),1248					vec![],1249				)1250				.unwrap();12511252			assert!(!output.0.is_success());1253			assert_eq!(get_balance(&origin), 100);12541255			// the rent is still charged1256			assert!(get_balance(&dest) < balance);1257		});1258	}12591260	#[test]1261	fn balance_too_low() {1262		// This test verifies that a contract can't send value if it's1263		// balance is too low.1264		let origin = ALICE;1265		let dest = BOB;12661267		ExtBuilder::default().build().execute_with(|| {1268			set_balance(&origin, 0);12691270			let result = super::transfer::<Test>(1271				super::TransferCause::Call,1272				super::TransactorKind::PlainAccount,1273				&origin,1274				&dest,1275				100,1276			);12771278			assert_eq!(result, Err(Error::<Test>::TransferFailed.into()));1279			assert_eq!(get_balance(&origin), 0);1280			assert_eq!(get_balance(&dest), 0);1281		});1282	}12831284	#[test]1285	fn output_is_returned_on_success() {1286		// Verifies that if a contract returns data with a successful exit status, this data1287		// is returned from the execution context.1288		let origin = ALICE;1289		let dest = BOB;1290		let return_ch = MockLoader::insert(Call, |_, _| {1291			Ok(ExecReturnValue {1292				flags: ReturnFlags::empty(),1293				data: Bytes(vec![1, 2, 3, 4]),1294			})1295		});12961297		ExtBuilder::default().build().execute_with(|| {1298			let schedule = <CurrentSchedule<Test>>::get();1299			let mut ctx = MockContext::top_level(origin, &schedule);1300			place_contract(&BOB, return_ch);13011302			let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);13031304			let output = result.unwrap();1305			assert!(output.0.is_success());1306			assert_eq!(output.0.data, Bytes(vec![1, 2, 3, 4]));1307		});1308	}13091310	#[test]1311	fn output_is_returned_on_failure() {1312		// Verifies that if a contract returns data with a failing exit status, this data1313		// is returned from the execution context.1314		let origin = ALICE;1315		let dest = BOB;1316		let return_ch = MockLoader::insert(Call, |_, _| {1317			Ok(ExecReturnValue {1318				flags: ReturnFlags::REVERT,1319				data: Bytes(vec![1, 2, 3, 4]),1320			})1321		});13221323		ExtBuilder::default().build().execute_with(|| {1324			let schedule = <CurrentSchedule<Test>>::get();1325			let mut ctx = MockContext::top_level(origin, &schedule);1326			place_contract(&BOB, return_ch);13271328			let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);13291330			let output = result.unwrap();1331			assert!(!output.0.is_success());1332			assert_eq!(output.0.data, Bytes(vec![1, 2, 3, 4]));1333		});1334	}13351336	#[test]1337	fn input_data_to_call() {1338		let input_data_ch = MockLoader::insert(Call, |ctx, _| {1339			assert_eq!(ctx.input_data, &[1, 2, 3, 4]);1340			exec_success()1341		});13421343		// This one tests passing the input data into a contract via call.1344		ExtBuilder::default().build().execute_with(|| {1345			let schedule = <CurrentSchedule<Test>>::get();1346			let mut ctx = MockContext::top_level(ALICE, &schedule);1347			place_contract(&BOB, input_data_ch);13481349			let result = ctx.call(1350				BOB,1351				0,1352				&mut GasMeter::<Test>::new(GAS_LIMIT),1353				vec![1, 2, 3, 4],1354			);1355			assert_matches!(result, Ok(_));1356		});1357	}13581359	#[test]1360	fn input_data_to_instantiate() {1361		let input_data_ch = MockLoader::insert(Constructor, |ctx, _| {1362			assert_eq!(ctx.input_data, &[1, 2, 3, 4]);1363			exec_success()1364		});13651366		// This one tests passing the input data into a contract via instantiate.1367		ExtBuilder::default().build().execute_with(|| {1368			let schedule = <CurrentSchedule<Test>>::get();1369			let subsistence = Contracts::<Test>::subsistence_threshold();1370			let mut ctx = MockContext::top_level(ALICE, &schedule);1371			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1372			let executable =1373				MockExecutable::from_storage(input_data_ch, &schedule, &mut gas_meter).unwrap();13741375			set_balance(&ALICE, subsistence * 10);13761377			let result = ctx.instantiate(1378				subsistence * 3,1379				&mut gas_meter,1380				executable,1381				vec![1, 2, 3, 4],1382				&[],1383			);1384			assert_matches!(result, Ok(_));1385		});1386	}13871388	#[test]1389	fn max_depth() {1390		// This test verifies that when we reach the maximal depth creation of an1391		// yet another context fails.1392		thread_local! {1393			static REACHED_BOTTOM: RefCell<bool> = RefCell::new(false);1394		}1395		let value = Default::default();1396		let recurse_ch = MockLoader::insert(Call, |ctx, _| {1397			// Try to call into yourself.1398			let r = ctx.ext.call(&BOB, 0, ctx.gas_meter, vec![]);13991400			REACHED_BOTTOM.with(|reached_bottom| {1401				let mut reached_bottom = reached_bottom.borrow_mut();1402				if !*reached_bottom {1403					// We are first time here, it means we just reached bottom.1404					// Verify that we've got proper error and set `reached_bottom`.1405					assert_eq!(r, Err((Error::<Test>::MaxCallDepthReached.into(), 0)));1406					*reached_bottom = true;1407				} else {1408					// We just unwinding stack here.1409					assert_matches!(r, Ok(_));1410				}1411			});14121413			exec_success()1414		});14151416		ExtBuilder::default().build().execute_with(|| {1417			let schedule = <CurrentSchedule<Test>>::get();1418			let mut ctx = MockContext::top_level(ALICE, &schedule);1419			set_balance(&BOB, 1);1420			place_contract(&BOB, recurse_ch);14211422			let result = ctx.call(BOB, value, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);14231424			assert_matches!(result, Ok(_));1425		});1426	}14271428	#[test]1429	fn caller_returns_proper_values() {1430		let origin = ALICE;1431		let dest = BOB;14321433		thread_local! {1434			static WITNESSED_CALLER_BOB: RefCell<Option<AccountIdOf<Test>>> = RefCell::new(None);1435			static WITNESSED_CALLER_CHARLIE: RefCell<Option<AccountIdOf<Test>>> = RefCell::new(None);1436		}14371438		let bob_ch = MockLoader::insert(Call, |ctx, _| {1439			// Record the caller for bob.1440			WITNESSED_CALLER_BOB1441				.with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone()));14421443			// Call into CHARLIE contract.1444			assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));1445			exec_success()1446		});1447		let charlie_ch = MockLoader::insert(Call, |ctx, _| {1448			// Record the caller for charlie.1449			WITNESSED_CALLER_CHARLIE1450				.with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone()));1451			exec_success()1452		});14531454		ExtBuilder::default().build().execute_with(|| {1455			let schedule = <CurrentSchedule<Test>>::get();1456			let mut ctx = MockContext::top_level(origin.clone(), &schedule);1457			place_contract(&dest, bob_ch);1458			place_contract(&CHARLIE, charlie_ch);14591460			let result = ctx.call(1461				dest.clone(),1462				0,1463				&mut GasMeter::<Test>::new(GAS_LIMIT),1464				vec![],1465			);14661467			assert_matches!(result, Ok(_));1468		});14691470		WITNESSED_CALLER_BOB.with(|caller| assert_eq!(*caller.borrow(), Some(origin)));1471		WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest)));1472	}14731474	#[test]1475	fn address_returns_proper_values() {1476		let bob_ch = MockLoader::insert(Call, |ctx, _| {1477			// Verify that address matches BOB.1478			assert_eq!(*ctx.ext.address(), BOB);14791480			// Call into charlie contract.1481			assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));1482			exec_success()1483		});1484		let charlie_ch = MockLoader::insert(Call, |ctx, _| {1485			assert_eq!(*ctx.ext.address(), CHARLIE);1486			exec_success()1487		});14881489		ExtBuilder::default().build().execute_with(|| {1490			let schedule = <CurrentSchedule<Test>>::get();1491			let mut ctx = MockContext::top_level(ALICE, &schedule);1492			place_contract(&BOB, bob_ch);1493			place_contract(&CHARLIE, charlie_ch);14941495			let result = ctx.call(BOB, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);14961497			assert_matches!(result, Ok(_));1498		});1499	}15001501	#[test]1502	fn refuse_instantiate_with_value_below_existential_deposit() {1503		let dummy_ch = MockLoader::insert(Constructor, |_, _| exec_success());15041505		ExtBuilder::default()1506			.existential_deposit(15)1507			.build()1508			.execute_with(|| {1509				let schedule = <CurrentSchedule<Test>>::get();1510				let mut ctx = MockContext::top_level(ALICE, &schedule);1511				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1512				let executable =1513					MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();15141515				assert_matches!(1516					ctx.instantiate(1517						0, // <- zero endowment1518						&mut gas_meter,1519						executable,1520						vec![],1521						&[],1522					),1523					Err(_)1524				);1525			});1526	}15271528	#[test]1529	fn instantiation_work_with_success_output() {1530		let dummy_ch = MockLoader::insert(Constructor, |_, _| {1531			Ok(ExecReturnValue {1532				flags: ReturnFlags::empty(),1533				data: Bytes(vec![80, 65, 83, 83]),1534			})1535		});15361537		ExtBuilder::default()1538			.existential_deposit(15)1539			.build()1540			.execute_with(|| {1541				let schedule = <CurrentSchedule<Test>>::get();1542				let mut ctx = MockContext::top_level(ALICE, &schedule);1543				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1544				let executable =1545					MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();1546				set_balance(&ALICE, 1000);15471548				let instantiated_contract_address = assert_matches!(1549					ctx.instantiate(1550						100,1551						&mut gas_meter,1552						executable,1553						vec![],1554						&[],1555					),1556					Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address1557				);15581559				// Check that the newly created account has the expected code hash and1560				// there are instantiation event.1561				assert_eq!(1562					Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(),1563					dummy_ch1564				);1565				assert_eq!(1566					&events(),1567					&[Event::Instantiated(ALICE, instantiated_contract_address)]1568				);1569			});1570	}15711572	#[test]1573	fn instantiation_fails_with_failing_output() {1574		let dummy_ch = MockLoader::insert(Constructor, |_, _| {1575			Ok(ExecReturnValue {1576				flags: ReturnFlags::REVERT,1577				data: Bytes(vec![70, 65, 73, 76]),1578			})1579		});15801581		ExtBuilder::default()1582			.existential_deposit(15)1583			.build()1584			.execute_with(|| {1585				let schedule = <CurrentSchedule<Test>>::get();1586				let mut ctx = MockContext::top_level(ALICE, &schedule);1587				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1588				let executable =1589					MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();1590				set_balance(&ALICE, 1000);15911592				let instantiated_contract_address = assert_matches!(1593					ctx.instantiate(1594						100,1595						&mut gas_meter,1596						executable,1597						vec![],1598						&[],1599					),1600					Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address1601				);16021603				// Check that the account has not been created.1604				assert_noop!(1605					Storage::<Test>::code_hash(&instantiated_contract_address),1606					ContractAbsentError,1607				);1608				assert!(events().is_empty());1609			});1610	}16111612	#[test]1613	fn instantiation_from_contract() {1614		let dummy_ch = MockLoader::insert(Call, |_, _| exec_success());1615		let instantiated_contract_address = Rc::new(RefCell::new(None::<AccountIdOf<Test>>));1616		let instantiator_ch = MockLoader::insert(Call, {1617			let dummy_ch = dummy_ch.clone();1618			let instantiated_contract_address = Rc::clone(&instantiated_contract_address);1619			move |ctx, _| {1620				// Instantiate a contract and save it's address in `instantiated_contract_address`.1621				let (address, output, _) = ctx1622					.ext1623					.instantiate(1624						dummy_ch,1625						Contracts::<Test>::subsistence_threshold() * 3,1626						ctx.gas_meter,1627						vec![],1628						&[48, 49, 50],1629					)1630					.unwrap();16311632				*instantiated_contract_address.borrow_mut() = address.into();1633				Ok(output)1634			}1635		});16361637		ExtBuilder::default()1638			.existential_deposit(15)1639			.build()1640			.execute_with(|| {1641				let schedule = <CurrentSchedule<Test>>::get();1642				let mut ctx = MockContext::top_level(ALICE, &schedule);1643				set_balance(&ALICE, Contracts::<Test>::subsistence_threshold() * 100);1644				place_contract(&BOB, instantiator_ch);16451646				assert_matches!(1647					ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),1648					Ok(_)1649				);16501651				let instantiated_contract_address = instantiated_contract_address1652					.borrow()1653					.as_ref()1654					.unwrap()1655					.clone();16561657				// Check that the newly created account has the expected code hash and1658				// there are instantiation event.1659				assert_eq!(1660					Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(),1661					dummy_ch1662				);1663				assert_eq!(1664					&events(),1665					&[Event::Instantiated(BOB, instantiated_contract_address)]1666				);1667			});1668	}16691670	#[test]1671	fn instantiation_traps() {1672		let dummy_ch = MockLoader::insert(Constructor, |_, _| Err("It's a trap!".into()));1673		let instantiator_ch = MockLoader::insert(Call, {1674			let dummy_ch = dummy_ch.clone();1675			move |ctx, _| {1676				// Instantiate a contract and save it's address in `instantiated_contract_address`.1677				assert_matches!(1678					ctx.ext1679						.instantiate(dummy_ch, 15u64, ctx.gas_meter, vec![], &[],),1680					Err((1681						ExecError {1682							error: DispatchError::Other("It's a trap!"),1683							origin: ErrorOrigin::Callee,1684						},1685						01686					))1687				);16881689				exec_success()1690			}1691		});16921693		ExtBuilder::default()1694			.existential_deposit(15)1695			.build()1696			.execute_with(|| {1697				let schedule = <CurrentSchedule<Test>>::get();1698				let mut ctx = MockContext::top_level(ALICE, &schedule);1699				set_balance(&ALICE, 1000);1700				set_balance(&BOB, 100);1701				place_contract(&BOB, instantiator_ch);17021703				assert_matches!(1704					ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),1705					Ok(_)1706				);17071708				// The contract wasn't instantiated so we don't expect to see an instantiation1709				// event here.1710				assert_eq!(&events(), &[]);1711			});1712	}17131714	#[test]1715	fn termination_from_instantiate_fails() {1716		let terminate_ch = MockLoader::insert(Constructor, |ctx, _| {1717			ctx.ext.terminate(&ALICE).unwrap();1718			exec_success()1719		});17201721		ExtBuilder::default()1722			.existential_deposit(15)1723			.build()1724			.execute_with(|| {1725				let schedule = <CurrentSchedule<Test>>::get();1726				let mut ctx = MockContext::top_level(ALICE, &schedule);1727				let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1728				let executable =1729					MockExecutable::from_storage(terminate_ch, &schedule, &mut gas_meter).unwrap();1730				set_balance(&ALICE, 1000);17311732				assert_eq!(1733					ctx.instantiate(100, &mut gas_meter, executable, vec![], &[],),1734					Err(Error::<Test>::NotCallable.into())1735				);17361737				assert_eq!(&events(), &[]);1738			});1739	}17401741	#[test]1742	fn rent_allowance() {1743		let rent_allowance_ch = MockLoader::insert(Constructor, |ctx, _| {1744			let subsistence = Contracts::<Test>::subsistence_threshold();1745			let allowance = subsistence * 3;1746			assert_eq!(ctx.ext.rent_allowance(), <BalanceOf<Test>>::max_value());1747			ctx.ext.set_rent_allowance(allowance);1748			assert_eq!(ctx.ext.rent_allowance(), allowance);1749			exec_success()1750		});17511752		ExtBuilder::default().build().execute_with(|| {1753			let subsistence = Contracts::<Test>::subsistence_threshold();1754			let schedule = <CurrentSchedule<Test>>::get();1755			let mut ctx = MockContext::top_level(ALICE, &schedule);1756			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1757			let executable =1758				MockExecutable::from_storage(rent_allowance_ch, &schedule, &mut gas_meter).unwrap();1759			set_balance(&ALICE, subsistence * 10);17601761			let result = ctx.instantiate(subsistence * 5, &mut gas_meter, executable, vec![], &[]);1762			assert_matches!(result, Ok(_));1763		});1764	}17651766	#[test]1767	fn rent_params_works() {1768		let code_hash = MockLoader::insert(Call, |ctx, executable| {1769			let address = ctx.ext.address();1770			let contract = <ContractInfoOf<Test>>::get(address)1771				.and_then(|c| c.get_alive())1772				.unwrap();1773			assert_eq!(1774				ctx.ext.rent_params(),1775				&RentParams::new(address, &contract, executable)1776			);1777			exec_success()1778		});17791780		ExtBuilder::default().build().execute_with(|| {1781			let subsistence = Contracts::<Test>::subsistence_threshold();1782			let schedule = <CurrentSchedule<Test>>::get();1783			let mut ctx = MockContext::top_level(ALICE, &schedule);1784			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1785			set_balance(&ALICE, subsistence * 10);1786			place_contract(&BOB, code_hash);1787			ctx.call(BOB, 0, &mut gas_meter, vec![]).unwrap();1788		});1789	}17901791	#[test]1792	fn rent_params_snapshotted() {1793		let code_hash = MockLoader::insert(Call, |ctx, executable| {1794			let subsistence = Contracts::<Test>::subsistence_threshold();1795			let address = ctx.ext.address();1796			let contract = <ContractInfoOf<Test>>::get(address)1797				.and_then(|c| c.get_alive())1798				.unwrap();1799			let rent_params = RentParams::new(address, &contract, executable);18001801			// Changing the allowance during the call: rent params stay unchanged.1802			let allowance = 42;1803			assert_ne!(allowance, rent_params.rent_allowance);1804			ctx.ext.set_rent_allowance(allowance);1805			assert_eq!(ctx.ext.rent_params(), &rent_params);18061807			// Creating another instance from the same code_hash increases the refcount.1808			// This is also not reflected in the rent params.1809			assert_eq!(MockLoader::refcount(&executable.code_hash), 1);1810			ctx.ext1811				.instantiate(1812					executable.code_hash,1813					subsistence * 25,1814					&mut GasMeter::<Test>::new(GAS_LIMIT),1815					vec![],1816					&[],1817				)1818				.unwrap();1819			assert_eq!(MockLoader::refcount(&executable.code_hash), 2);1820			assert_eq!(ctx.ext.rent_params(), &rent_params);18211822			exec_success()1823		});18241825		ExtBuilder::default().build().execute_with(|| {1826			let subsistence = Contracts::<Test>::subsistence_threshold();1827			let schedule = <CurrentSchedule<Test>>::get();1828			let mut ctx = MockContext::top_level(ALICE, &schedule);1829			let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);1830			set_balance(&ALICE, subsistence * 100);1831			place_contract(&BOB, code_hash);1832			ctx.call(BOB, subsistence * 50, &mut gas_meter, vec![])1833				.unwrap();1834		});1835	}1836}