Newer
Older
// address of the contract will be returned. The value is encoded as T::AccountId.
Alexander Theißen
committed
seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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
)?)
},
// 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.
Alexander Theißen
committed
seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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.
Alexander Theißen
committed
seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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.
Alexander Theißen
committed
seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::GasLeft)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged
Alexander Theißen
committed
)?)
// Stores the 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.
Alexander Theißen
committed
seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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 or as endowment 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.
Alexander Theißen
committed
seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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.
Alexander Theißen
committed
seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Random)?;
if subject_len > ctx.schedule.limits.subject_len {
Alexander Theißen
committed
Err(Error::<E::T>::RandomSubjectTooLong)?;
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.
Alexander Theißen
committed
seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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.
Alexander Theißen
committed
seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::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.
// The data is encoded as T::Balance.
//
// # Note
//
// The tombstone deposit is on top of the existential deposit. So in order for
// a contract to leave a tombstone the balance of the contract must not go
// below the sum of existential deposit and the tombstone deposit. The sum
// is commonly referred as subsistence threshold in code.
Alexander Theißen
committed
seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::TombstoneDeposit)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged
Alexander Theißen
committed
)?)
// Try to restore the given destination contract sacrificing the caller.
// This function will compute a tombstone hash from the caller's storage and the given code hash
// and if the hash matches the hash found in the tombstone at the specified address - kill
// the caller contract and restore the destination contract and set the specified `rent_allowance`.
// All caller's funds are transfered to the destination.
// The tombstone hash is derived as `hash(code_hash, storage_root_hash)`. In order to match
// this hash to its own hash the restorer must make its storage equal to the one of the
// evicted destination contract. In order to allow for additional storage items in the
// restoring contract a delta can be specified to this function. All keys specified as
// delta are disregarded when calculating the storage root hash.
//
// On success, the destination contract is restored. This function is diverging and
// stops execution even on success.
// - `dest_ptr`, `dest_len` - the pointer and the length of a buffer that encodes `T::AccountId`
// with the address of the to be restored contract.
// - `code_hash_ptr`, `code_hash_len` - the pointer and the length of a buffer that encodes
// a code hash of the to be restored contract.
// - `rent_allowance_ptr`, `rent_allowance_len` - the pointer and the length of a buffer that
// encodes the rent allowance that must be set in the case of successful restoration.
// - `delta_ptr` is the pointer to the start of a buffer that has `delta_count` storage keys
// laid out sequentially.
//
// # Traps
//
// - There is no tombstone at the destination address.
// - Tombstone hashes do not match.
// - The calling contract is already present on the call stack.
// - The supplied code_hash does not exist on-chain.
Alexander Theißen
committed
seal_restore_to(
ctx,
dest_ptr: u32,
dest_len: u32,
code_hash_ptr: u32,
code_hash_len: u32,
rent_allowance_ptr: u32,
rent_allowance_len: u32,
delta_ptr: u32,
delta_count: u32
) => {
ctx.charge_gas(RuntimeToken::RestoreTo(delta_count))?;
let dest: <<E as Ext>::T as frame_system::Config>::AccountId =
ctx.read_sandbox_memory_as(dest_ptr, dest_len)?;
let code_hash: CodeHash<<E as Ext>::T> =
ctx.read_sandbox_memory_as(code_hash_ptr, code_hash_len)?;
let rent_allowance: BalanceOf<<E as Ext>::T> =
ctx.read_sandbox_memory_as(rent_allowance_ptr, rent_allowance_len)?;
const KEY_SIZE: usize = 32;
// We can eagerly allocate because we charged for the complete delta count already
// We still need to make sure that the allocation isn't larger than the memory
// allocator can handle.
ensure!(
delta_count
.saturating_mul(KEY_SIZE as u32) <= ctx.schedule.limits.max_memory_size(),
Error::<E::T>::OutOfBounds,
);
let mut delta = vec![[0; KEY_SIZE]; delta_count as usize];
let mut key_ptr = delta_ptr;
for i in 0..delta_count {
// Read the delta into the provided buffer
// This cannot panic because of the loop condition
ctx.read_sandbox_memory_into_buf(key_ptr, &mut delta[i as usize])?;
// Offset key_ptr to the next element.
Alexander Theißen
committed
key_ptr = key_ptr.checked_add(KEY_SIZE as u32).ok_or(Error::<E::T>::OutOfBounds)?;
}
delta
};
Alexander Theißen
committed
ctx.ext.restore_to(dest, code_hash, rent_allowance, delta)?;
Err(TrapReason::Restoration)
// 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.
Alexander Theißen
committed
seal_deposit_event(ctx, topics_ptr: u32, topics_len: u32, data_ptr: u32, data_len: u32) => {
let num_topic = topics_len
.checked_div(sp_std::mem::size_of::<TopicOf<E::T>>() as u32)
Alexander Theißen
committed
.ok_or_else(|| "Zero sized topics are not allowed")?;
ctx.charge_gas(RuntimeToken::DepositEvent {
num_topic,
len: data_len,
})?;
if data_len > ctx.ext.max_value_size() {
Alexander Theißen
committed
Err(Error::<E::T>::ValueTooLarge)?;
let mut topics: Vec::<TopicOf<<E as Ext>::T>> = match topics_len {
_ => ctx.read_sandbox_memory_as(topics_ptr, topics_len)?,
// If there are more than `event_topics`, then trap.
if topics.len() > ctx.schedule.limits.event_topics as usize {
Alexander Theißen
committed
Err(Error::<E::T>::TooManyTopics)?;
}
// Check for duplicate topics. If there are any, then trap.
if has_duplicates(&mut topics) {
Alexander Theißen
committed
Err(Error::<E::T>::DuplicateTopics)?;
let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?;
ctx.ext.deposit_event(topics, event_data);
// Set rent allowance of the contract
//
// - value_ptr: a pointer to the buffer with value, how much to allow for rent
// Should be decodable as a `T::Balance`. Traps otherwise.
// - value_len: length of the value buffer.
Alexander Theißen
committed
seal_set_rent_allowance(ctx, value_ptr: u32, value_len: u32) => {
ctx.charge_gas(RuntimeToken::SetRentAllowance)?;
let value: BalanceOf<<E as Ext>::T> =
ctx.read_sandbox_memory_as(value_ptr, value_len)?;
ctx.ext.set_rent_allowance(value);
Ok(())
},
// Stores the rent allowance 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.
Alexander Theißen
committed
seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::RentAllowance)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged
Alexander Theißen
committed
)?)
// Prints utf8 encoded string from the data buffer.
// Only available on `--dev` chains.
// This function may be removed at any time, superseded by a more general contract debugging feature.
Alexander Theißen
committed
seal_println(ctx, str_ptr: u32, str_len: u32) => {
let data = ctx.read_sandbox_memory(str_ptr, str_len)?;
if let Ok(utf8) = core::str::from_utf8(&data) {
}
Ok(())
},
// 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.
Alexander Theißen
committed
seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::BlockNumber)?;
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged
Alexander Theißen
committed
)?)
// 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.
Alexander Theißen
committed
seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashSha256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
},
// 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.
Alexander Theißen
committed
seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
},
// 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.
Alexander Theißen
committed
seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
},
// 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
// directly into this buffer.
Alexander Theißen
committed
seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?)
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
// Call into the chain extension provided by the chain if any.
//
// Handling of the input values is up to the specific chain extension and so is the
// return value. The extension can decide to use the inputs as primitive inputs or as
// in/out arguments by interpreting them as pointers. Any caller of this function
// must therefore coordinate with the chain that it targets.
//
// # Note
//
// If no chain extension exists the contract will trap with the `NoChainExtension`
// module error.
seal_call_chain_extension(
ctx,
func_id: u32,
input_ptr: u32,
input_len: u32,
output_ptr: u32,
output_len_ptr: u32
) -> u32 => {
use crate::chain_extension::{ChainExtension, Environment, RetVal};
if <E::T as Config>::ChainExtension::enabled() == false {
Err(Error::<E::T>::NoChainExtension)?;
}
let env = Environment::new(ctx, input_ptr, input_len, output_ptr, output_len_ptr);
match <E::T as Config>::ChainExtension::call(func_id, env)? {
RetVal::Converging(val) => Ok(val),
RetVal::Diverging{flags, data} => Err(TrapReason::Return(ReturnData {
flags: flags.bits(),
data,
})),
}
},