Newer
Older
key_ptr: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
ctx.set_storage(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.
#[unstable]
Sasha Gryaznov
committed
#[prefixed_alias]
fn set_storage(
ctx: Runtime<E>,
key_ptr: u32,
key_len: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn clear_storage(ctx: Runtime<E>, key_ptr: u32) -> Result<(), TrapReason> {
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]
Sasha Gryaznov
committed
#[prefixed_alias]
fn clear_storage(ctx: Runtime<E>, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
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`
Sasha Gryaznov
committed
#[prefixed_alias]
fn get_storage(
ctx: Runtime<E>,
key_ptr: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
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]
Sasha Gryaznov
committed
#[prefixed_alias]
fn get_storage(
ctx: Runtime<E>,
key_ptr: u32,
key_len: u32,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
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.
///
/// # 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 contains_storage(ctx: Runtime<E>, key_ptr: u32) -> Result<u32, TrapReason> {
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]
Sasha Gryaznov
committed
#[prefixed_alias]
fn contains_storage(ctx: Runtime<E>, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
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]
Sasha Gryaznov
committed
#[prefixed_alias]
fn take_storage(
ctx: Runtime<E>,
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()))?;
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)?;
Ok(ReturnCode::Success)
} else {
ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
Ok(ReturnCode::KeyNotFound)
}
}
/// 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.
///
/// # Errors
///
/// `ReturnCode::TransferFailed`
Sasha Gryaznov
committed
#[prefixed_alias]
fn transfer(
ctx: Runtime<E>,
_value_len: u32,
) -> Result<ReturnCode, TrapReason> {
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);
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.
///
/// # Deprecation
///
/// 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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn call(
ctx: Runtime<E>,
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(
CallFlags::ALLOW_REENTRY,
CallType::Call { callee_ptr, value_ptr, gas },
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
/// 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 documenation of the supported flags.
/// - 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`
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn call(
ctx: Runtime<E>,
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(
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
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
/// 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`
Sasha Gryaznov
committed
#[prefixed_alias]
fn delegate_call(
ctx: Runtime<E>,
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(
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.
///
/// # 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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn instantiate(
ctx: Runtime<E>,
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(
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,
)
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
/// 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.
/// - 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.
///
/// # 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.
///
/// `ReturnCode::CalleeReverted`: Output buffer is returned.
/// `ReturnCode::CalleeTrapped`
/// `ReturnCode::TransferFailed`
/// `ReturnCode::CodeNotFound`
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn instantiate(
ctx: Runtime<E>,
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> {
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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn terminate(
ctx: Runtime<E>,
beneficiary_ptr: u32,
_beneficiary_len: u32,
) -> Result<(), TrapReason> {
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.
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn terminate(ctx: Runtime<E>, beneficiary_ptr: u32) -> Result<(), TrapReason> {
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`.
Sasha Gryaznov
committed
#[prefixed_alias]
fn input(ctx: Runtime<E>, 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(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:
/// ```
/// 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(
Sasha Gryaznov
committed
ctx: Runtime<E>,
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 {
data: ctx.read_sandbox_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]
fn caller(ctx: Runtime<E>, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Caller)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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
///
/// - 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).
Sasha Gryaznov
committed
#[prefixed_alias]
fn is_contract(ctx: Runtime<E>, 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 =
ctx.read_sandbox_memory_as(account_ptr)?;
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
///
/// `ReturnCode::KeyNotFound`
Sasha Gryaznov
committed
#[prefixed_alias]
fn code_hash(
ctx: Runtime<E>,
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 =
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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn own_code_hash(ctx: Runtime<E>, 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.
///
/// 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).
Sasha Gryaznov
committed
#[prefixed_alias]
fn caller_is_origin(ctx: Runtime<E>) -> 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]
fn address(ctx: Runtime<E>, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Address)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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.
///
/// 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(
ctx: Runtime<E>,
gas: u64,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<(), TrapReason> {
let gas = Weight::from_ref_time(gas);
ctx.charge_gas(RuntimeCosts::WeightToFee)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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]
fn gas_left(ctx: Runtime<E>, 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(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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn balance(ctx: Runtime<E>, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Balance)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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`.
/// `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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn value_transferred(
ctx: Runtime<E>,
out_ptr: u32,
out_len_ptr: u32,
) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::ValueTransferred)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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.
///
/// The data is encoded as T::Hash.
///
/// # Deprecation
///
/// This function is deprecated. Users should migrate to the version in the "seal1" module.
Sasha Gryaznov
committed
#[prefixed_alias]
fn random(
ctx: Runtime<E>,
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(subject_ptr, subject_len)?;
Ok(ctx.write_sandbox_output(
out_ptr,
out_len_ptr,
&ctx.ext.random(&subject_buf).0.encode(),
false,
already_charged,
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
/// 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]
fn random(
ctx: Runtime<E>,
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(subject_ptr, subject_len)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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]
fn now(ctx: Runtime<E>, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::Now)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
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.
///
/// The data is encoded as T::Balance.
Sasha Gryaznov
committed
#[prefixed_alias]
fn minimum_balance(ctx: Runtime<E>, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::MinimumBalance)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr,
out_len_ptr,
&ctx.ext.minimum_balance().encode(),
false,
already_charged,
Alexander Theißen
committed
)?)
/// 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.
///
/// # Deprecation
///
/// There is no longer a tombstone deposit. This function always returns 0.
Sasha Gryaznov
committed
#[prefixed_alias]
fn tombstone_deposit(
ctx: Runtime<E>,
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(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 compatiblity
Sasha Gryaznov
committed
#[prefixed_alias]
fn restore_to(
ctx: Runtime<E>,
_rent_allowance_len: u32,
_delta_count: u32,
) -> Result<(), TrapReason> {
ctx.charge_gas(RuntimeCosts::DebugMessage)?;
Ok(())
/// 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 compatiblity
#[version(1)]
Sasha Gryaznov
committed
#[prefixed_alias]
fn restore_to(
ctx: Runtime<E>,
_dest_ptr: u32,
_code_hash_ptr: u32,
_rent_allowance_ptr: u32,
_delta_ptr: u32,
_delta_count: u32,
) -> Result<(), TrapReason> {
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.
Sasha Gryaznov
committed
#[prefixed_alias]
fn deposit_event(
ctx: Runtime<E>,
topics_ptr: u32,
topics_len: u32,
data_ptr: u32,
data_len: u32,
) -> Result<(), TrapReason> {
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 {