runtime.rs 70.6 KiB
Newer Older
	/// Set the value at the given key in the contract storage.
	/// See [`pallet_contracts_uapi::HostFn::set_storage_v1`]
		key_ptr: u32,
		value_ptr: u32,
		value_len: u32,
	) -> Result<u32, TrapReason> {
		ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len)
	/// Set the value at the given key in the contract storage.
	/// See [`pallet_contracts_uapi::HostFn::set_storage_v2`]
		key_ptr: u32,
		key_len: u32,
		value_ptr: u32,
		value_len: u32,
	) -> Result<u32, TrapReason> {
		ctx.set_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len)
	/// Clear the value at the given key in the contract storage.
	/// See [`pallet_contracts_uapi::HostFn::clear_storage`]
	fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> {
		ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ())
	/// Clear the value at the given key in the contract storage.
	/// See [`pallet_contracts_uapi::HostFn::clear_storage_v1`]
	fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
		ctx.clear_storage(memory, KeyType::Var(key_len), key_ptr)
	/// Retrieve the value under the given key from storage.
	/// See [`pallet_contracts_uapi::HostFn::get_storage`]
		key_ptr: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.get_storage(memory, KeyType::Fix, key_ptr, out_ptr, out_len_ptr)
	/// Retrieve the value under the given key from storage.
	/// See [`pallet_contracts_uapi::HostFn::get_storage_v1`]
		key_ptr: u32,
		key_len: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.get_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
	/// Checks whether there is a value stored under the given key.
	/// See [`pallet_contracts_uapi::HostFn::contains_storage`]
	fn contains_storage(ctx: _, memory: _, key_ptr: u32) -> Result<u32, TrapReason> {
		ctx.contains_storage(memory, KeyType::Fix, key_ptr)
	/// Checks whether there is a value stored under the given key.
	/// See [`pallet_contracts_uapi::HostFn::contains_storage_v1`]
	fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
		ctx.contains_storage(memory, KeyType::Var(key_len), key_ptr)
	/// Retrieve and remove the value under the given key from storage.
	/// See [`pallet_contracts_uapi::HostFn::take_storage`]
		key_ptr: u32,
		key_len: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?;
		ensure!(
			key_len <= <<E as Ext>::T as Config>::MaxStorageKeyLen::get(),
			Error::<E::T>::DecodingFailed
		);
		let key = ctx.read_sandbox_memory(memory, key_ptr, key_len)?;
		if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage(
			&Key::<E::T>::try_from_var(key).map_err(|_| Error::<E::T>::DecodingFailed)?,
			ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32));
			ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?;
			Ok(ReturnErrorCode::Success)
			ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
			Ok(ReturnErrorCode::KeyNotFound)
	/// Transfer some value to another account.
	/// See [`pallet_contracts_uapi::HostFn::transfer`].
		account_ptr: u32,
		value_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.charge_gas(RuntimeCosts::Transfer)?;
		let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(memory, account_ptr)?;
		let value: BalanceOf<<E as Ext>::T> = ctx.read_sandbox_memory_as(memory, value_ptr)?;
		let result = ctx.ext.transfer(&callee, value);
			Ok(()) => Ok(ReturnErrorCode::Success),
			Err(err) => {
				let code = Runtime::<E>::err_into_return_code(err)?;
				Ok(code)
	/// Make a call to another contract.
	///
	/// # Note
	///
	/// The values `_callee_len` and `_value_len` are ignored because the encoded sizes of those
	/// types are fixed through [`codec::MaxEncodedLen`]. The fields exist for backwards
	/// compatibility. Consider switching to the newest version of this function.
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
			CallType::Call {
				callee_ptr,
				value_ptr,
				deposit_ptr: SENTINEL,
				weight: Weight::from_parts(gas, 0),
			},
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	}

	/// Make a call to another contract.
	/// See [`pallet_contracts_uapi::HostFn::call_v1`].
	#[version(1)]
	#[prefixed_alias]
	fn call(
		ctx: _,
		memory: _,
		flags: u32,
		callee_ptr: u32,
		gas: u64,
		value_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
		output_len_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.call(
			memory,
			CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
			CallType::Call {
				callee_ptr,
				value_ptr,
				deposit_ptr: SENTINEL,
				weight: Weight::from_parts(gas, 0),
			},
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	/// Make a call to another contract.
	/// See [`pallet_contracts_uapi::HostFn::call_v2`].
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		callee_ptr: u32,
		ref_time_limit: u64,
		proof_size_limit: u64,
		deposit_ptr: u32,
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		value_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
			CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
			CallType::Call {
				callee_ptr,
				value_ptr,
				deposit_ptr,
				weight: Weight::from_parts(ref_time_limit, proof_size_limit),
			},
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	/// Execute code in the context (storage, caller, value) of the current contract.
	/// See [`pallet_contracts_uapi::HostFn::delegate_call`].
		flags: u32,
		code_hash_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
			CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
			CallType::DelegateCall { code_hash_ptr },
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	/// Instantiate a contract with the specified code hash.
	/// See [`pallet_contracts_uapi::HostFn::instantiate`].
	///
	/// # Note
	///
	/// The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes
	/// of those types are fixed through [`codec::MaxEncodedLen`]. The fields exist
	/// for backwards compatibility. Consider switching to the newest version of this function.
		code_hash_ptr: u32,
		_code_hash_len: u32,
		gas: u64,
		value_ptr: u32,
		_value_len: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		address_ptr: u32,
		address_len_ptr: u32,
		output_ptr: u32,
		output_len_ptr: u32,
		salt_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
			Weight::from_parts(gas, 0),
			SENTINEL,
			value_ptr,
			input_data_ptr,
			input_data_len,
			address_ptr,
			address_len_ptr,
			output_ptr,
			output_len_ptr,
			salt_ptr,
			salt_len,
		)
	}

	/// Instantiate a contract with the specified code hash.
	/// See [`pallet_contracts_uapi::HostFn::instantiate_v1`].
	#[version(1)]
	#[prefixed_alias]
	fn instantiate(
		ctx: _,
		memory: _,
		code_hash_ptr: u32,
		gas: u64,
		value_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		address_ptr: u32,
		address_len_ptr: u32,
		output_ptr: u32,
		output_len_ptr: u32,
		salt_ptr: u32,
		salt_len: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.instantiate(
			memory,
			code_hash_ptr,
			Weight::from_parts(gas, 0),
			SENTINEL,
			value_ptr,
			input_data_ptr,
			input_data_len,
			address_ptr,
			address_len_ptr,
			output_ptr,
			output_len_ptr,
			salt_ptr,
			salt_len,
		)
	/// Instantiate a contract with the specified code hash.
	/// See [`pallet_contracts_uapi::HostFn::instantiate_v2`].
		code_hash_ptr: u32,
		ref_time_limit: u64,
		proof_size_limit: u64,
		deposit_ptr: u32,
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		value_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		address_ptr: u32,
		address_len_ptr: u32,
		output_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
			Weight::from_parts(ref_time_limit, proof_size_limit),
			deposit_ptr,
			value_ptr,
			input_data_ptr,
			input_data_len,
			address_ptr,
			address_len_ptr,
			output_ptr,
			output_len_ptr,
			salt_ptr,
			salt_len,
		)
	/// Remove the calling account and transfer remaining balance.
	/// See [`pallet_contracts_uapi::HostFn::terminate`].
	///
	/// # Note
	///
	/// The value `_beneficiary_len` is ignored because the encoded sizes
	/// this type is fixed through `[`MaxEncodedLen`]. The field exist for backwards
	/// compatibility. Consider switching to the newest version of this function.
		beneficiary_ptr: u32,
		_beneficiary_len: u32,
	) -> Result<(), TrapReason> {
	/// Remove the calling account and transfer remaining **free** balance.
	/// See [`pallet_contracts_uapi::HostFn::terminate_v1`].
	fn terminate(ctx: _, memory: _, beneficiary_ptr: u32) -> Result<(), TrapReason> {
		ctx.terminate(memory, beneficiary_ptr)
	/// Stores the input passed by the caller into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::input`].
	fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::InputBase)?;
		if let Some(input) = ctx.input_data.take() {
			ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| {
				Some(RuntimeCosts::CopyToContract(len))
			Err(Error::<E::T>::InputForwarded.into())
	/// Cease contract execution and save a data buffer as a result of the execution.
	/// See [`pallet_contracts_uapi::HostFn::return_value`].
		flags: u32,
		data_ptr: u32,
		data_len: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Return(data_len))?;
			data: ctx.read_sandbox_memory(memory, data_ptr, data_len)?,
	/// Stores the address of the caller into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::caller`].
	fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Caller)?;
		let caller = ctx.ext.caller().account_id()?.clone();
	/// Checks whether a specified address belongs to a contract.
	/// See [`pallet_contracts_uapi::HostFn::is_contract`].
	fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
		ctx.charge_gas(RuntimeCosts::IsContract)?;
		let address: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(memory, account_ptr)?;
	/// Retrieve the code hash for a specified contract address.
	/// See [`pallet_contracts_uapi::HostFn::code_hash`].
		account_ptr: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<ReturnErrorCode, TrapReason> {
		ctx.charge_gas(RuntimeCosts::CodeHash)?;
		let address: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(memory, account_ptr)?;
		if let Some(value) = ctx.ext.code_hash(&address) {
				out_ptr,
				out_len_ptr,
				&value.encode(),
				false,
				already_charged,
			)?;
			Ok(ReturnErrorCode::Success)
			Ok(ReturnErrorCode::KeyNotFound)
	/// Retrieve the code hash of the currently executing contract.
	/// See [`pallet_contracts_uapi::HostFn::own_code_hash`].
	fn own_code_hash(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::OwnCodeHash)?;
		let code_hash_encoded = &ctx.ext.own_code_hash().encode();
		Ok(ctx.write_sandbox_output(
			out_ptr,
			out_len_ptr,
			code_hash_encoded,
			false,
			already_charged,
		)?)
	}
	/// Checks whether the caller of the current contract is the origin of the whole call stack.
	/// See [`pallet_contracts_uapi::HostFn::caller_is_origin`].
	fn caller_is_origin(ctx: _, _memory: _) -> Result<u32, TrapReason> {
		ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
		Ok(ctx.ext.caller_is_origin() as u32)
	/// Checks whether the caller of the current contract is root.
	/// See [`pallet_contracts_uapi::HostFn::caller_is_root`].
	fn caller_is_root(ctx: _, _memory: _) -> Result<u32, TrapReason> {
		ctx.charge_gas(RuntimeCosts::CallerIsRoot)?;
		Ok(ctx.ext.caller_is_root() as u32)
	}

	/// Stores the address of the current contract into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::address`].
	fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Address)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.address().encode(),
			false,
			already_charged,
	/// Stores the price for the specified amount of gas into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::weight_to_fee`].
	#[prefixed_alias]
	fn weight_to_fee(
		ctx: _,
		memory: _,
		gas: u64,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		let gas = Weight::from_parts(gas, 0);
		ctx.charge_gas(RuntimeCosts::WeightToFee)?;
		Ok(ctx.write_sandbox_output(
			memory,
			out_ptr,
			out_len_ptr,
			&ctx.ext.get_weight_price(gas).encode(),
			false,
			already_charged,
		)?)
	}

	/// Stores the price for the specified amount of weight into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::weight_to_fee_v1`].
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
		ctx.charge_gas(RuntimeCosts::WeightToFee)?;
			&ctx.ext.get_weight_price(weight).encode(),
			false,
			already_charged,
		)?)
	}

	/// Stores the weight left into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::gas_left`].
	#[prefixed_alias]
	fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::GasLeft)?;
		let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode();
		Ok(ctx.write_sandbox_output(
			memory,
			out_ptr,
			out_len_ptr,
			gas_left,
	/// Stores the amount of weight left into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::gas_left_v1`].
	fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::GasLeft)?;
		let gas_left = &ctx.ext.gas_meter().gas_left().encode();
		Ok(ctx.write_sandbox_output(
			memory,
			out_ptr,
			out_len_ptr,
			gas_left,
			false,
			already_charged,
		)?)
	/// Stores the *free* balance of the current account into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::balance`].
	fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Balance)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.balance().encode(),
			false,
			already_charged,
	/// Stores the value transferred along with this call/instantiate into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::value_transferred`].
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::ValueTransferred)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.value_transferred().encode(),
			false,
			already_charged,
	/// Stores a random number for the current block and the given subject into the supplied buffer.
	///
	/// The value is stored to linear memory at the address pointed to by `out_ptr`.
	/// `out_len_ptr` must point to a u32 value that describes the available space at
	/// `out_ptr`. This call overwrites it with the size of the value. If the available
	/// space at `out_ptr` is less than the size of the value a trap is triggered.
	///
		subject_ptr: u32,
		subject_len: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Random)?;
		if subject_len > ctx.ext.schedule().limits.subject_len {
			return Err(Error::<E::T>::RandomSubjectTooLong.into())
		let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
		Ok(ctx.write_sandbox_output(
			out_ptr,
			out_len_ptr,
			&ctx.ext.random(&subject_buf).0.encode(),
			false,
			already_charged,
	/// Stores a random number for the current block and the given subject into the supplied buffer.
	///
	/// The value is stored to linear memory at the address pointed to by `out_ptr`.
	/// `out_len_ptr` must point to a u32 value that describes the available space at
	/// `out_ptr`. This call overwrites it with the size of the value. If the available
	/// space at `out_ptr` is less than the size of the value a trap is triggered.
	///
	/// The data is encoded as (T::Hash, frame_system::pallet_prelude::BlockNumberFor::<T>).
	///
	/// # Changes from v0
	///
	/// In addition to the seed it returns the block number since which it was determinable
	/// by chain observers.
	///
	/// # Note
	///
	/// The returned seed should only be used to distinguish commitments made before
	/// the returned block number. If the block number is too early (i.e. commitments were
	/// made afterwards), then ensure no further commitments may be made and repeatedly
	/// call this on later blocks until the block number returned is later than the latest
	/// commitment.
	#[version(1)]
		subject_ptr: u32,
		subject_len: u32,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Random)?;
		if subject_len > ctx.ext.schedule().limits.subject_len {
			return Err(Error::<E::T>::RandomSubjectTooLong.into())
		let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.random(&subject_buf).encode(),
			false,
			already_charged,
	/// Load the latest block timestamp into the supplied buffer
	/// See [`pallet_contracts_uapi::HostFn::now`].
	fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Now)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.now().encode(),
			false,
			already_charged,
	/// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::minimum_balance`].
	fn minimum_balance(
		ctx: _,
		memory: _,
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::MinimumBalance)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.minimum_balance().encode(),
			false,
			already_charged,
	/// Stores the tombstone deposit into the supplied buffer.
	///
	/// The value is stored to linear memory at the address pointed to by `out_ptr`.
	/// `out_len_ptr` must point to a u32 value that describes the available space at
	/// `out_ptr`. This call overwrites it with the size of the value. If the available
	/// space at `out_ptr` is less than the size of the value a trap is triggered.
	///
	/// There is no longer a tombstone deposit. This function always returns `0`.
		out_ptr: u32,
		out_len_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Balance)?;
		let deposit = <BalanceOf<E::T>>::zero().encode();
		Ok(ctx.write_sandbox_output(
			memory,
			out_ptr,
			out_len_ptr,
			&deposit,
			false,
			already_charged,
		)?)
	/// Was used to restore the given destination contract sacrificing the caller.
	///
	/// # Note
	///
	/// The state rent functionality was removed. This is stub only exists for
	/// backwards compatibility
		_dest_ptr: u32,
		_code_hash_ptr: u32,
		_rent_allowance_ptr: u32,
		_rent_allowance_len: u32,
		_delta_ptr: u32,
		_delta_count: u32,
	) -> Result<(), TrapReason> {
	/// Was used to restore the given destination contract sacrificing the caller.
	///
	/// # Note
	///
	/// The state rent functionality was removed. This is stub only exists for
	/// backwards compatibility
		_dest_ptr: u32,
		_code_hash_ptr: u32,
		_rent_allowance_ptr: u32,
		_delta_ptr: u32,
		_delta_count: u32,
	) -> Result<(), TrapReason> {
	/// Was used to set rent allowance of the contract.
	///
	/// # Note
	///
	/// The state rent functionality was removed. This is stub only exists for
	/// backwards compatibility.
		_value_ptr: u32,
		_value_len: u32,
	) -> Result<(), TrapReason> {
	/// Was used to set rent allowance of the contract.
	///
	/// # Note
	///
	/// The state rent functionality was removed. This is stub only exists for
	/// backwards compatibility.
	fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> {
	/// Was used to store the rent allowance into the supplied buffer.
	///
	/// # Note
	///
	/// The state rent functionality was removed. This is stub only exists for
	/// backwards compatibility.
	fn rent_allowance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::Balance)?;
		let rent_allowance = <BalanceOf<E::T>>::max_value().encode();
			out_ptr,
			out_len_ptr,
			&rent_allowance,
			false,
			already_charged,
	/// Deposit a contract event with the data buffer and optional list of topics.
	/// See [pallet_contracts_uapi::HostFn::deposit_event]
	#[prefixed_alias]
	fn deposit_event(
		ctx: _,
		memory: _,
		topics_ptr: u32,
		topics_len: u32,
		data_ptr: u32,
		data_len: u32,
	) -> Result<(), TrapReason> {
		let num_topic = topics_len
			.checked_div(sp_std::mem::size_of::<TopicOf<E::T>>() as u32)
			.ok_or("Zero sized topics are not allowed")?;
		ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
		if data_len > ctx.ext.max_value_size() {
			return Err(Error::<E::T>::ValueTooLarge.into())
		}

		let topics: Vec<TopicOf<<E as Ext>::T>> = match topics_len {
			0 => Vec::new(),
			_ => ctx.read_sandbox_memory_as_unbounded(memory, topics_ptr, topics_len)?,
		};

		// If there are more than `event_topics`, then trap.
		if topics.len() > ctx.ext.schedule().limits.event_topics as usize {
			return Err(Error::<E::T>::TooManyTopics.into())
		}

		let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?;

		ctx.ext.deposit_event(topics, event_data);

		Ok(())
	}

	/// Stores the current block number of the current contract into the supplied buffer.
	/// See [`pallet_contracts_uapi::HostFn::block_number`].
	fn block_number(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::BlockNumber)?;
			out_ptr,
			out_len_ptr,
			&ctx.ext.block_number().encode(),
			false,
			already_charged,
	/// Computes the SHA2 256-bit hash on the given input buffer.
	/// See [`pallet_contracts_uapi::HostFn::hash_sha2_256`].
		input_ptr: u32,
		input_len: u32,
		output_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(
			memory, sha2_256, input_ptr, input_len, output_ptr,
		)?)
	/// Computes the KECCAK 256-bit hash on the given input buffer.
	/// See [`pallet_contracts_uapi::HostFn::hash_keccak_256`].
		input_ptr: u32,
		input_len: u32,
		output_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(
			memory, keccak_256, input_ptr, input_len, output_ptr,
		)?)
	/// Computes the BLAKE2 256-bit hash on the given input buffer.
	/// See [`pallet_contracts_uapi::HostFn::hash_blake2_256`].
		input_ptr: u32,
		input_len: u32,
		output_ptr: u32,
	) -> Result<(), TrapReason> {
		ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(
			memory, blake2_256, input_ptr, input_len, output_ptr,