Newer
Older
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.
// If there is no tombstone at the destination address, the hashes don't match or this contract
// instance is already present on the contract call stack, a trap is generated.
//
// Otherwise, 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
//
// - Tombstone hashes do not match
// - Calling cantract is live i.e is already on the call stack.
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)?)
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
},
// 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)?)
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
},
// 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)?)
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
},
// 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)?)
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
// 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,
})),
}
},