Newer
Older
// This is the API exposed to contracts.
//
// # Note
//
// Any input that leads to a out of bound error (reading or writing) or failing to decode
// data passed to the supervisor will lead to a trap. This is not documented explicitly
// for every function.
Sasha Gryaznov
committed
#[define_env(doc)]
pub mod env {
/// Account for used gas. Traps if gas used is greater than gas limit.
///
/// NOTE: This is a implementation defined call and is NOT a part of the public API.
/// This call is supposed to be called only by instrumentation injected code.
///
Sasha Gryaznov
committed
/// - `amount`: How much gas is used.
Alexander Theißen
committed
fn gas(ctx: _, _memory: _, amount: u64) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?;
Ok(())
/// Set the value at the given key in the contract storage.
///
Sasha Gryaznov
committed
/// Equivalent to the newer version [`super::seal1::Api::set_storage`] with the exception of the
/// return type. Still a valid thing to call when not interested in the return value.
Sasha Gryaznov
committed
#[prefixed_alias]
fn set_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
value_ptr: u32,
value_len: u32,
) -> Result<(), TrapReason> {
Alexander Theißen
committed
ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// Set the value at the given key in the contract 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 value length must not exceed the maximum defined by the contracts module parameters.
/// Specifying a `value_len` of zero will store an empty value.
///
/// # Parameters
///
/// - `key_ptr`: pointer into the linear memory where the location to store the value is placed.
/// - `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.
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn set_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
Alexander Theißen
committed
ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len)
/// Set the value at the given key in the contract storage.
///
/// The key and value lengths must not exceed the maximums defined by the contracts module
/// parameters. Specifying a `value_len` of zero will store an empty value.
///
/// # Parameters
///
/// - `key_ptr`: pointer into the linear memory where the location to store the value is placed.
/// - `key_len`: the length of the key in bytes.
/// - `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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn set_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
key_len: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
Alexander Theißen
committed
ctx.set_storage(memory, KeyType::Variable(key_len), key_ptr, value_ptr, value_len)
/// Clear the value at the given key in the contract storage.
///
Sasha Gryaznov
committed
/// Equivalent to the newer version [`super::seal1::Api::clear_storage`] with the exception of
/// the return type. Still a valid thing to call when not interested in the return value.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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.
///
/// # 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
ctx.clear_storage(memory, 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`
Sasha Gryaznov
committed
#[prefixed_alias]
fn get_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
Alexander Theißen
committed
ctx.get_storage(memory, 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
///
Sasha Gryaznov
committed
/// - `ReturnCode::KeyNotFound`
Sasha Gryaznov
committed
#[prefixed_alias]
fn get_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
key_len: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
Alexander Theißen
committed
ctx.get_storage(memory, 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.
///
/// # Return Value
///
/// Returns the size of the pre-existing value at the specified key if any. Otherwise
/// `SENTINEL` is returned as a sentinel value.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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.
///
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
ctx.contains_storage(memory, 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
///
Sasha Gryaznov
committed
/// - `ReturnCode::KeyNotFound`
Sasha Gryaznov
committed
#[prefixed_alias]
fn take_storage(
Alexander Theißen
committed
ctx: _,
memory: _,
key_ptr: u32,
key_len: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?;
Alexander Theißen
committed
let key = ctx.read_sandbox_memory(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));
Alexander Theißen
committed
ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?;
Ok(ReturnCode::Success)
} else {
ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
Ok(ReturnCode::KeyNotFound)
}
/// Transfer some value to another account.
///
/// # Parameters
///
Sasha Gryaznov
committed
/// - `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.
///
/// # Errors
///
Sasha Gryaznov
committed
/// - `ReturnCode::TransferFailed`
Sasha Gryaznov
committed
#[prefixed_alias]
fn transfer(
Alexander Theißen
committed
ctx: _,
memory: _,
_value_len: u32,
) -> Result<ReturnCode, TrapReason> {
ctx.charge_gas(RuntimeCosts::Transfer)?;
let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
Alexander Theißen
committed
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);
Alexander Theißen
committed
match result {
Ok(()) => Ok(ReturnCode::Success),
Err(err) => {
let code = Runtime::<E>::err_into_return_code(err)?;
Ok(code)
Alexander Theißen
committed
}
/// Make a call to another contract.
///
/// # New version available
///
/// 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
Sasha Gryaznov
committed
/// of those types are fixed through
/// [`codec::MaxEncodedLen`]. The fields exist
/// for backwards compatibility. Consider switching to the newest version of this function.
Sasha Gryaznov
committed
#[prefixed_alias]
fn call(
Alexander Theißen
committed
ctx: _,
memory: _,
callee_ptr: u32,
gas: u64,
value_ptr: u32,
input_data_ptr: u32,
input_data_len: u32,
output_ptr: u32,
output_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
ctx.call(
Alexander Theißen
committed
memory,
CallFlags::ALLOW_REENTRY,
CallType::Call { callee_ptr, value_ptr, gas },
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
/// 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 `crate::wasm::runtime::CallFlags` for a documentation of the supported flags.
Sasha Gryaznov
committed
/// - `callee_ptr`: a pointer to the address of the callee contract. Should be decodable as an
/// `T::AccountId`. Traps otherwise.
Sasha Gryaznov
committed
/// - `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.
///
Sasha Gryaznov
committed
/// - `ReturnCode::CalleeReverted`: Output buffer is returned.
/// - `ReturnCode::CalleeTrapped`
/// - `ReturnCode::TransferFailed`
/// - `ReturnCode::NotCallable`
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn call(
Alexander Theißen
committed
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<ReturnCode, TrapReason> {
ctx.call(
Alexander Theißen
committed
memory,
CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
CallType::Call { callee_ptr, value_ptr, gas },
Yarik Bratashchuk
committed
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
Yarik Bratashchuk
committed
/// 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
///
Sasha Gryaznov
committed
/// - `flags`: see `crate::wasm::runtime::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.
///
Sasha Gryaznov
committed
/// - `ReturnCode::CalleeReverted`: Output buffer is returned.
/// - `ReturnCode::CalleeTrapped`
/// - `ReturnCode::CodeNotFound`
Sasha Gryaznov
committed
#[prefixed_alias]
fn delegate_call(
Alexander Theißen
committed
ctx: _,
memory: _,
Yarik Bratashchuk
committed
flags: u32,
code_hash_ptr: u32,
input_data_ptr: u32,
input_data_len: u32,
output_ptr: u32,
output_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
Yarik Bratashchuk
committed
ctx.call(
Alexander Theißen
committed
memory,
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.
///
/// # New version available
///
/// 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
Sasha Gryaznov
committed
/// of those types are fixed through
/// [`codec::MaxEncodedLen`]. The fields exist
/// for backwards compatibility. Consider switching to the newest version of this function.
Sasha Gryaznov
committed
#[prefixed_alias]
fn instantiate(
Alexander Theißen
committed
ctx: _,
memory: _,
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,
) -> Result<ReturnCode, TrapReason> {
ctx.instantiate(
Alexander Theißen
committed
memory,
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
///
Sasha Gryaznov
committed
/// - `code_hash_ptr`: a pointer to the buffer that contains the initializer code.
/// - `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.
Sasha Gryaznov
committed
/// - `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.
Sasha Gryaznov
committed
/// - `salt_ptr`: Pointer to raw bytes used for address derivation. See `fn contract_address`.
/// - `salt_len`: length in bytes of the supplied salt.
///
/// # Errors
///
/// 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.
///
Sasha Gryaznov
committed
/// - `ReturnCode::CalleeReverted`: Output buffer is returned.
/// - `ReturnCode::CalleeTrapped`
/// - `ReturnCode::TransferFailed`
/// - `ReturnCode::CodeNotFound`
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn instantiate(
Alexander Theißen
committed
ctx: _,
memory: _,
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<ReturnCode, TrapReason> {
Alexander Theißen
committed
memory,
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.
///
/// # New version available
///
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn terminate(
Alexander Theißen
committed
ctx: _,
memory: _,
beneficiary_ptr: u32,
_beneficiary_len: u32,
) -> Result<(), TrapReason> {
Alexander Theißen
committed
ctx.terminate(memory, 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.
///
Sasha Gryaznov
committed
/// - `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.
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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.
///
/// 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
///
Sasha Gryaznov
committed
/// This function traps if the input was previously forwarded by a [`call()`][`Self::call()`].
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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() {
Alexander Theißen
committed
ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| {
Some(RuntimeCosts::CopyToContract(len))
Alexander Theißen
committed
})?;
ctx.input_data = Some(input);
Alexander Theißen
committed
Ok(())
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:
Sasha Gryaznov
committed
/// ```nocompile
/// seal_return(0, 0, 0);
/// ```
///
/// 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.
fn seal_return(
Alexander Theißen
committed
ctx: _,
memory: _,
flags: u32,
data_ptr: u32,
data_len: u32,
) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Return(data_len))?;
Alexander Theißen
committed
Err(TrapReason::Return(ReturnData {
Alexander Theißen
committed
data: ctx.read_sandbox_memory(memory, data_ptr, data_len)?,
Alexander Theißen
committed
}))
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Caller)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.caller().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// Checks whether a specified address belongs to a contract.
///
/// # Parameters
///
Sasha Gryaznov
committed
/// - `account_ptr`: a pointer to the address of the beneficiary account Should be decodable as
/// an `T::AccountId`. Traps otherwise.
Sasha Gryaznov
committed
/// Returned value is a `u32`-encoded boolean: (0 = false, 1 = true).
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
Sasha Gryaznov
committed
ctx.charge_gas(RuntimeCosts::IsContract)?;
let address: <<E as Ext>::T as frame_system::Config>::AccountId =
Alexander Theißen
committed
ctx.read_sandbox_memory_as(memory, account_ptr)?;
Sasha Gryaznov
committed
Ok(ctx.ext.is_contract(&address) as u32)
Sasha Gryaznov
committed
/// 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
///
Sasha Gryaznov
committed
/// - `ReturnCode::KeyNotFound`
Sasha Gryaznov
committed
#[prefixed_alias]
fn code_hash(
Alexander Theißen
committed
ctx: _,
memory: _,
account_ptr: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
ctx.charge_gas(RuntimeCosts::CodeHash)?;
let address: <<E as Ext>::T as frame_system::Config>::AccountId =
Alexander Theißen
committed
ctx.read_sandbox_memory_as(memory, account_ptr)?;
if let Some(value) = ctx.ext.code_hash(&address) {
ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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(
Alexander Theißen
committed
memory,
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.
///
Sasha Gryaznov
committed
/// Prefer this over [`is_contract()`][`Self::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.
Sasha Gryaznov
committed
/// 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.
///
Sasha Gryaznov
committed
/// Returned value is a `u32`-encoded boolean: (`0 = false`, `1 = true`).
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn caller_is_origin(ctx: _, _memory: _) -> Result<u32, TrapReason> {
Sasha Gryaznov
committed
ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
Ok(ctx.ext.caller_is_origin() as u32)
Sasha Gryaznov
committed
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Address)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.address().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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.
///
Sasha Gryaznov
committed
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn weight_to_fee(
Alexander Theißen
committed
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)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.get_weight_price(gas).encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
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();
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
memory,
out_ptr,
out_len_ptr,
gas_left,
false,
already_charged,
)?)
Sasha Gryaznov
committed
/// 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.
///
Sasha Gryaznov
committed
/// The data is encoded as `T::Balance`.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Balance)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.balance().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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`.
Sasha Gryaznov
committed
/// `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.
///
Sasha Gryaznov
committed
/// The data is encoded as `T::Balance`.
Sasha Gryaznov
committed
#[prefixed_alias]
fn value_transferred(
Alexander Theißen
committed
ctx: _,
memory: _,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::ValueTransferred)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.value_transferred().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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.
///
Sasha Gryaznov
committed
/// The data is encoded as `T::Hash`.
Sasha Gryaznov
committed
#[prefixed_alias]
Sasha Gryaznov
committed
fn random(
Alexander Theißen
committed
ctx: _,
memory: _,
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())
Alexander Theißen
committed
let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.random(&subject_buf).0.encode(),
false,
already_charged,
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
/// 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.
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
Sasha Gryaznov
committed
fn random(
Alexander Theißen
committed
ctx: _,
memory: _,
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())
Alexander Theißen
committed
let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.random(&subject_buf).encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Now)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.now().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer.
///
Sasha Gryaznov
committed
/// The data is encoded as `T::Balance`.
Sasha Gryaznov
committed
#[prefixed_alias]
Alexander Theißen
committed
fn minimum_balance(
ctx: _,
memory: _,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::MinimumBalance)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
Alexander Theißen
committed
memory,
out_ptr,
out_len_ptr,
&ctx.ext.minimum_balance().encode(),