runtime.rs 81.1 KiB
Newer Older
	// - `value_ptr`: pointer into the linear memory where the value to set is placed.
	// - `value_len`: the length of the value in bytes.
	//
	// # Return Value
	//
	// Returns the size of the pre-existing value at the specified key if any. Otherwise
	// `SENTINEL` is returned as a sentinel value.
	[__unstable__] seal_set_storage(ctx, key_ptr: u32, key_len: u32, value_ptr: u32, value_len: u32) -> u32 => {
		ctx.set_storage(KeyType::Variable(key_len), key_ptr, value_ptr, value_len)
	},

	// Clear the value at the given key in the contract storage.
	//
	// Equivalent to the newer version of `seal_clear_storage` with the exception of the return
	// type. Still a valid thing to call when not interested in the return value.
	[seal0] seal_clear_storage(ctx, key_ptr: u32) => {
		ctx.clear_storage(KeyType::Fix, key_ptr).map(|_| ())
	// Clear the value at the given key in the contract storage.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key is placed.
	// - `key_len`: the length of the key in bytes.
	//
	// # Return Value
	//
	// Returns the size of the pre-existing value at the specified key if any. Otherwise
	// `SENTINEL` is returned as a sentinel value.
	[__unstable__] seal_clear_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => {
		ctx.clear_storage(KeyType::Variable(key_len), key_ptr)
	// Retrieve the value under the given key from storage.
	// This version is to be used with a fixed sized storage key. For runtimes supporting transparent
	// hashing, please use the newer version of this function.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed.
	// - `out_ptr`: pointer to the linear memory where the value is written to.
	// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
	//   is read from and the value length is written to.
	//
	// # Errors
	//
	// `ReturnCode::KeyNotFound`
	[seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
		ctx.get_storage(KeyType::Fix, key_ptr, out_ptr, out_len_ptr)
	},

	// Retrieve the value under the given key from storage.
	//
	// This version is to be used with a fixed sized storage key. For runtimes supporting transparent
	// hashing, please use the newer version of this function.
	//
	// The key length must not exceed the maximum defined by the contracts module parameter.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed.
	// - `key_len`: the length of the key in bytes.
	// - `out_ptr`: pointer to the linear memory where the value is written to.
	// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
	//   is read from and the value length is written to.
	//
	// # Errors
	//
	// `ReturnCode::KeyNotFound`
	[__unstable__] seal_get_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
		ctx.get_storage(KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr)
	// Checks whether there is a value stored under the given key.
	//
	// This version is to be used with a fixed sized storage key. For runtimes supporting transparent
	// hashing, please use the newer version of this function.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed.
	//
	// Returns the size of the pre-existing value at the specified key if any. Otherwise
	// `SENTINEL` is returned as a sentinel value.
	[seal0] seal_contains_storage(ctx, key_ptr: u32) -> u32 => {
		ctx.contains_storage(KeyType::Fix, key_ptr)
	},

	// Checks whether there is a value stored under the given key.
	//
	// The key length must not exceed the maximum defined by the contracts module parameter.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed.
	// - `key_len`: the length of the key in bytes.
	//
	// # Return Value
	//
	// Returns the size of the pre-existing value at the specified key if any. Otherwise
	// `SENTINEL` is returned as a sentinel value.
	[__unstable__] seal_contains_storage(ctx, key_ptr: u32, key_len: u32) -> u32 => {
		ctx.contains_storage(KeyType::Variable(key_len), key_ptr)
	},

	// Retrieve and remove the value under the given key from storage.
	//
	// # Parameters
	//
	// - `key_ptr`: pointer into the linear memory where the key of the requested value is placed.
	// - `key_len`: the length of the key in bytes.
	// - `out_ptr`: pointer to the linear memory where the value is written to.
	// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
	//   is read from and the value length is written to.
	//
	// # Errors
	//
	// `ReturnCode::KeyNotFound`
	[__unstable__] seal_take_storage(ctx, key_ptr: u32, key_len: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
		let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?;
		let key = ctx.read_sandbox_memory(key_ptr, key_len)?;
		if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage_transparent(&VarSizedKey::<E::T>::try_from(key).map_err(|_| Error::<E::T>::DecodingFailed)?, None, true)? {
			ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32));
			ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, already_charged)?;
			ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
	// Transfer some value to another account.
	//
	// # Parameters
	//
	// - account_ptr: a pointer to the address of the beneficiary account
	//   Should be decodable as an `T::AccountId`. Traps otherwise.
	// - account_len: length of the address buffer.
	// - value_ptr: a pointer to the buffer with value, how much value to send.
	//   Should be decodable as a `T::Balance`. Traps otherwise.
	// - value_len: length of the value buffer.
	// `ReturnCode::TransferFailed`
	[seal0] seal_transfer(
		ctx,
		account_ptr: u32,
		value_ptr: u32,
		ctx.charge_gas(RuntimeCosts::Transfer)?;
		let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(account_ptr)?;
		let value: BalanceOf<<E as Ext>::T> =
			ctx.read_sandbox_memory_as(value_ptr)?;
		let result = ctx.ext.transfer(&callee, value);
		match result {
			Ok(()) => Ok(ReturnCode::Success),
			Err(err) => {
				let code = Runtime::<E>::err_into_return_code(err)?;
				Ok(code)
			}
		}
	// Make a call to another contract.
	//
	// This is equivalent to calling the newer version of this function with
	// `flags` set to `ALLOW_REENTRY`. See the newer version for documentation.
	//
	// # Note
	//
	// The values `_callee_len` and `_value_len` are ignored because the encoded sizes
	// of those types are fixed through `[`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,
		output_len_ptr: u32
	) -> ReturnCode => {
		ctx.call(
			CallFlags::ALLOW_REENTRY,
			CallType::Call{callee_ptr, value_ptr, gas},
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	},

Sergey Pepyakin's avatar
Sergey Pepyakin committed
	// Make a call to another contract.
	//
	// The callees output buffer is copied to `output_ptr` and its length to `output_len_ptr`.
	// The copy of the output buffer can be skipped by supplying the sentinel value
	// of `SENTINEL` to `output_ptr`.
	// # Parameters
	// - flags: See [`CallFlags`] for a documentation of the supported flags.
Sergey Pepyakin's avatar
Sergey Pepyakin committed
	// - callee_ptr: a pointer to the address of the callee contract.
	//   Should be decodable as an `T::AccountId`. Traps otherwise.
	// - gas: how much gas to devote to the execution.
	// - value_ptr: a pointer to the buffer with value, how much value to send.
	//   Should be decodable as a `T::Balance`. Traps otherwise.
	// - input_data_ptr: a pointer to a buffer to be used as input data to the callee.
	// - input_data_len: length of the input data buffer.
	// - output_ptr: a pointer where the output buffer is copied to.
	// - output_len_ptr: in-out pointer to where the length of the buffer is read from
	//   and the actual length is written to.
	//
	// # Errors
	//
	// An error means that the call wasn't successful output buffer is returned unless
	// stated otherwise.
	// `ReturnCode::CalleeReverted`: Output buffer is returned.
	// `ReturnCode::CalleeTrapped`
	// `ReturnCode::TransferFailed`
	// `ReturnCode::NotCallable`
	[seal1] seal_call(
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		ctx,
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		callee_ptr: u32,
		gas: u64,
		value_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
		output_len_ptr: u32
	) -> ReturnCode => {
			CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
			CallType::Call{callee_ptr, value_ptr, gas},
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	},

	// Execute code in the context (storage, caller, value) of the current contract.
	//
	// Reentrancy protection is always disabled since the callee is allowed
	// to modify the callers storage. This makes going through a reentrancy attack
	// unnecessary for the callee when it wants to exploit the caller.
	//
	// # Parameters
	//
	// - flags: See [`CallFlags`] for a documentation of the supported flags.
	// - code_hash: a pointer to the hash of the code to be called.
	// - input_data_ptr: a pointer to a buffer to be used as input data to the callee.
	// - input_data_len: length of the input data buffer.
	// - output_ptr: a pointer where the output buffer is copied to.
	// - output_len_ptr: in-out pointer to where the length of the buffer is read from
	//   and the actual length is written to.
	//
	// # Errors
	//
	// An error means that the call wasn't successful and no output buffer is returned unless
	// stated otherwise.
	//
	// `ReturnCode::CalleeReverted`: Output buffer is returned.
	// `ReturnCode::CalleeTrapped`
	// `ReturnCode::CodeNotFound`
	[seal0] seal_delegate_call(
		ctx,
		flags: u32,
		code_hash_ptr: u32,
		input_data_ptr: u32,
		input_data_len: u32,
		output_ptr: u32,
		output_len_ptr: u32
	) -> ReturnCode => {
		ctx.call(
			CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
			input_data_ptr,
			input_data_len,
			output_ptr,
			output_len_ptr,
		)
	// Instantiate a contract with the specified code hash.
	//
	// # Deprecation
	//
	// This is equivalent to calling the newer version of this function. The newer version
	// drops the now unnecessary length fields.
	//
	// # Note
	//
	// The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes
	// of those types are fixed through `[`MaxEncodedLen`]. The fields exist for backwards
	// compatibility. Consider switching to the newest version of this function.
	[seal0] seal_instantiate(
		ctx,
		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,
		salt_len: u32
	) -> ReturnCode => {
		ctx.instantiate (
			code_hash_ptr,
			gas,
			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.
	// This function creates an account and executes the constructor defined in the code specified
	// by the code hash. The address of this new account is copied to `address_ptr` and its length
	// to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its
	// length to `output_len_ptr`. The copy of the output buffer and address can be skipped by
	// supplying the sentinel value of `SENTINEL` to `output_ptr` or `address_ptr`.
	// `value` must be at least the minimum balance. Otherwise the instantiation fails and the
	// contract is not created.
	// # Parameters
	// - code_hash_ptr: a pointer to the buffer that contains the initializer code.
Sergey Pepyakin's avatar
Sergey Pepyakin committed
	// - gas: how much gas to devote to the execution of the initializer code.
	// - value_ptr: a pointer to the buffer with value, how much value to send.
	//   Should be decodable as a `T::Balance`. Traps otherwise.
	// - input_data_ptr: a pointer to a buffer to be used as input data to the initializer code.
	// - input_data_len: length of the input data buffer.
	// - address_ptr: a pointer where the new account's address is copied to.
	// - address_len_ptr: in-out pointer to where the length of the buffer is read from
	//		and the actual length is written to.
	// - output_ptr: a pointer where the output buffer is copied to.
	// - output_len_ptr: in-out pointer to where the length of the buffer is read from
	//   and the actual length is written to.
	// - salt_ptr: Pointer to raw bytes used for address derivation. See `fn contract_address`.
	// - salt_len: length in bytes of the supplied salt.
	// Please consult the `ReturnCode` enum declaration for more information on those
	// errors. Here we only note things specific to this function.
	// An error means that the account wasn't created and no address or output buffer
	// is returned unless stated otherwise.
	// `ReturnCode::CalleeReverted`: Output buffer is returned.
	// `ReturnCode::CalleeTrapped`
	// `ReturnCode::TransferFailed`
	// `ReturnCode::CodeNotFound`
	[seal1] seal_instantiate(
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		ctx,
		code_hash_ptr: u32,
Sergey Pepyakin's avatar
Sergey Pepyakin committed
		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
	) -> ReturnCode => {
		ctx.instantiate(
			code_hash_ptr,
			gas,
			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.
	//
	// # Deprecation
	//
	// This is equivalent to calling the newer version of this function. The newer version
	// drops the now unnecessary length fields.
	//
	// # 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.
	[seal0] seal_terminate(ctx, beneficiary_ptr: u32, _beneficiary_len: u32) => {
		ctx.terminate(beneficiary_ptr)
	// Remove the calling account and transfer remaining **free** balance.
	//
	// This function never returns. Either the termination was successful and the
	// execution of the destroyed contract is halted. Or it failed during the termination
	// which is considered fatal and results in a trap + rollback.
	//
	// - beneficiary_ptr: a pointer to the address of the beneficiary account where all
	//   where all remaining funds of the caller are transferred.
	//   Should be decodable as an `T::AccountId`. Traps otherwise.
	//
	// # Traps
	//
	// - The contract is live i.e is already on the call stack.
	// - Failed to send the balance to the beneficiary.
	// - The deletion queue is full.
	[seal1] seal_terminate(ctx, beneficiary_ptr: u32) => {
		ctx.terminate(beneficiary_ptr)
	// Stores the input passed by the caller 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.
	//
	// # Note
	//
	// This function traps if the input was previously forwarded by a `seal_call`.
	[seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::InputBase)?;
		if let Some(input) = ctx.input_data.take() {
			ctx.write_sandbox_output(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.
	//
	// This function never returns as it stops execution of the caller.
	// This is the only way to return a data buffer to the caller. Returning from
	// execution without calling this function is equivalent to calling:
	// ```
	// The flags argument is a bitfield that can be used to signal special return
	// conditions to the supervisor:
	// --- lsb ---
	// bit 0      : REVERT - Revert all storage changes made by the caller.
	// bit [1, 31]: Reserved for future use.
	// --- msb ---
	//
	// Using a reserved bit triggers a trap.
	[seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
		ctx.charge_gas(RuntimeCosts::Return(data_len))?;
			data: ctx.read_sandbox_memory(data_ptr, data_len)?,
	// Stores the address of the caller 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.
	// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the
	// extrinsic will be returned. Otherwise, if this call is initiated by another contract then the
	// address of the contract will be returned. The value is encoded as T::AccountId.
	[seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::Caller)?;
			out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged
	// Checks whether a specified address belongs to a contract.
	//
	// # Parameters
	//
	// - account_ptr: a pointer to the address of the beneficiary account
	//   Should be decodable as an `T::AccountId`. Traps otherwise.
	//
	// Returned value is a u32-encoded boolean: (0 = false, 1 = true).
	[seal0] seal_is_contract(ctx, account_ptr: u32) -> u32 => {
		ctx.charge_gas(RuntimeCosts::IsContract)?;
		let address: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(account_ptr)?;

		Ok(ctx.ext.is_contract(&address) as u32)
	},

	// Retrieve the code hash for a specified contract address.
	//
	// # Parameters
	//
	// - `account_ptr`: a pointer to the address in question.
	//   Should be decodable as an `T::AccountId`. Traps otherwise.
	// - `out_ptr`: pointer to the linear memory where the returning value is written to.
	// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
	//   is read from and the value length is written to.
	//
	// # Errors
	//
	// `ReturnCode::KeyNotFound`
	[seal0] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
		ctx.charge_gas(RuntimeCosts::CodeHash)?;
		let address: <<E as Ext>::T as frame_system::Config>::AccountId =
			ctx.read_sandbox_memory_as(account_ptr)?;
		if let Some(value) = ctx.ext.code_hash(&address) {
			ctx.write_sandbox_output(out_ptr, out_len_ptr, &value.encode(), false, already_charged)?;
			Ok(ReturnCode::Success)
		} else {
			Ok(ReturnCode::KeyNotFound)
		}
	},

	// Retrieve the code hash of the currently executing contract.
	//
	// # Parameters
	//
	// - `out_ptr`: pointer to the linear memory where the returning value is written to.
	// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
	//   is read from and the value length is written to.
	[seal0] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	//
	// Prefer this over `seal_is_contract` when checking whether your contract is being called by a contract
	// or a plain account. The reason is that it performs better since it does not need to
	// do any storage lookups.
	//
	// A return value of`true` indicates that this contract is being called by a plain account
	// and `false` indicates that the caller is another contract.
	//
	// Returned value is a u32-encoded boolean: (0 = false, 1 = true).
	[seal0] seal_caller_is_origin(ctx) -> u32 => {
		ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
		Ok(ctx.ext.caller_is_origin() as u32)
	},

	// Stores the address of the current contract 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.
	[seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	//
	// 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::Balance.
	//
	// # Note
	// It is recommended to avoid specifying very small values for `gas` as the prices for a single
	// gas can be smaller than one.
	[seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::WeightToFee)?;
			out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged
	// Stores the amount of gas left 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 Gas.
	[seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::GasLeft)?;
		let gas_left = &ctx.ext.gas_meter().gas_left().encode();
			out_ptr, out_len_ptr, gas_left, false, already_charged,
	// Stores the **free* balance of the current account 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::Balance.
	[seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	// 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::Balance.
	[seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	// The data is encoded as T::Hash.
	//
	// # Deprecation
	//
	// This function is deprecated. Users should migrate to the version in the "seal1" module.
	[seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
		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(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, T::BlockNumber).
	//
	// # 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.
	[seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
		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(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
	//
	// 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.
	[seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	// The data is encoded as T::Balance.
	[seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	[seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::Balance)?;
		let deposit = <BalanceOf<E::T>>::zero().encode();
		Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, &deposit, false, already_charged)?)
	// Was used to restore the given destination contract sacrificing the caller.
	// The state rent functionality was removed. This is stub only exists for
	// backwards compatibility
	[seal0] seal_restore_to(
		ctx,
		_dest_ptr: u32,
		_code_hash_ptr: u32,
		_rent_allowance_ptr: u32,
		_rent_allowance_len: u32,
		_delta_ptr: u32,
		_delta_count: u32
		ctx.charge_gas(RuntimeCosts::DebugMessage)?;
		Ok(())
	// Was used to restore the given destination contract sacrificing the caller.
	// The state rent functionality was removed. This is stub only exists for
	// backwards compatibility
	[seal1] seal_restore_to(
		_dest_ptr: u32,
		_code_hash_ptr: u32,
		_rent_allowance_ptr: u32,
		_delta_ptr: u32,
		_delta_count: u32
		ctx.charge_gas(RuntimeCosts::DebugMessage)?;
		Ok(())
	// Deposit a contract event with the data buffer and optional list of topics. There is a limit
	// on the maximum number of topics specified by `event_topics`.
	//
	// - topics_ptr - a pointer to the buffer of topics encoded as `Vec<T::Hash>`. The value of this
	//   is ignored if `topics_len` is set to 0. The topics list can't contain duplicates.
	// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector.
	// - data_ptr - a pointer to a raw data buffer which will saved along the event.
	// - data_len - the length of the data buffer.
	[seal0] seal_deposit_event(
		ctx,
		topics_ptr: u32,
		topics_len: u32,
		data_ptr: u32,
		data_len: u32
	) => {
		fn has_duplicates<T: Ord>(items: &mut Vec<T>) -> bool {
			// # Warning
			//
			// Unstable sorts are non-deterministic across architectures. The usage here is OK
			// because we are rejecting duplicates which removes the non determinism.
			items.sort_unstable();
			// Find any two consecutive equal elements.
			items.windows(2).any(|w| {
				match &w {
					&[a, b] => a == b,
					_ => false,
				}
			})
		}

		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 mut topics: Vec::<TopicOf<<E as Ext>::T>> = match topics_len {
			0 => Vec::new(),
			_ => ctx.read_sandbox_memory_as_unbounded(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());
		}

		// Check for duplicate topics. If there are any, then trap.
		// Complexity O(n * log(n)) and no additional allocations.
		// This also sorts the topics.
		if has_duplicates(&mut topics) {
			return Err(Error::<E::T>::DuplicateTopics.into());
		let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?;

		ctx.ext.deposit_event(topics, event_data);
	// Was used to set rent allowance of the contract.
	// The state rent functionality was removed. This is stub only exists for
	// backwards compatibility.
	[seal0] seal_set_rent_allowance(ctx, _value_ptr: u32, _value_len: u32) => {
		ctx.charge_gas(RuntimeCosts::DebugMessage)?;
	// Was used to set rent allowance of the contract.
	// # Note
	//
	// The state rent functionality was removed. This is stub only exists for
	// backwards compatibility.
	[seal1] seal_set_rent_allowance(ctx, _value_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::DebugMessage)?;
	// Was used to store the rent allowance into the supplied buffer.
	// The state rent functionality was removed. This is stub only exists for
	// backwards compatibility.
	[seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::Balance)?;
		let rent_allowance = <BalanceOf<E::T>>::max_value().encode();
			out_ptr, out_len_ptr, &rent_allowance, false, already_charged
	// Stores the current block number of the current contract 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.
	[seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
		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.
	//
	// Returns the result directly into the given output buffer.
	//
	// # Note
	//
	// - The `input` and `output` buffer may overlap.
	// - The output buffer is expected to hold at least 32 bytes (256 bits).
	// - It is the callers responsibility to provide an output buffer that
	//   is large enough to hold the expected amount of bytes returned by the
	//   chosen hash function.
	//
	// # Parameters
	//
	// - `input_ptr`: the pointer into the linear memory where the input
	//                data is placed.
	// - `input_len`: the length of the input data in bytes.
	// - `output_ptr`: the pointer into the linear memory where the output
	//                 data is placed. The function will write the result
	//                 directly into this buffer.
	[seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
	},

	// Computes the KECCAK 256-bit hash on the given input buffer.
	//
	// Returns the result directly into the given output buffer.
	//
	// # Note
	//
	// - The `input` and `output` buffer may overlap.
	// - The output buffer is expected to hold at least 32 bytes (256 bits).
	// - It is the callers responsibility to provide an output buffer that
	//   is large enough to hold the expected amount of bytes returned by the
	//   chosen hash function.
	//
	// # Parameters
	//
	// - `input_ptr`: the pointer into the linear memory where the input
	//                data is placed.
	// - `input_len`: the length of the input data in bytes.
	// - `output_ptr`: the pointer into the linear memory where the output
	//                 data is placed. The function will write the result
	//                 directly into this buffer.
	[seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
	},

	// Computes the BLAKE2 256-bit hash on the given input buffer.
	//
	// Returns the result directly into the given output buffer.
	//
	// # Note
	//
	// - The `input` and `output` buffer may overlap.
	// - The output buffer is expected to hold at least 32 bytes (256 bits).
	// - It is the callers responsibility to provide an output buffer that
	//   is large enough to hold the expected amount of bytes returned by the
	//   chosen hash function.
	//
	// # Parameters
	//
	// - `input_ptr`: the pointer into the linear memory where the input
	//                data is placed.
	// - `input_len`: the length of the input data in bytes.
	// - `output_ptr`: the pointer into the linear memory where the output
	//                 data is placed. The function will write the result
	//                 directly into this buffer.
	[seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
		ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?;
		Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
	},

	// Computes the BLAKE2 128-bit hash on the given input buffer.
	//
	// Returns the result directly into the given output buffer.
	//
	// # Note
	//
	// - The `input` and `output` buffer may overlap.
	// - The output buffer is expected to hold at least 16 bytes (128 bits).
	// - It is the callers responsibility to provide an output buffer that
	//   is large enough to hold the expected amount of bytes returned by the
	//   chosen hash function.
	//
	// # Parameters
	//
	// - `input_ptr`: the pointer into the linear memory where the input
	//                data is placed.
	// - `input_len`: the length of the input data in bytes.
	// - `output_ptr`: the pointer into the linear memory where the output
	//                 data is placed. The function will write the result