Expose block number in seal_random (#8329)

* Allow contract callable functions to specify the module

* Add new version of `seal_random`

* Fix overlong lines

* Fix benchmarking code

* Update README.md

* Replace Module by Pallet
This commit is contained in:
Alexander Theißen
2021-03-23 14:48:36 +01:00
committed by GitHub
parent f9b6c869a3
commit 1f911ddb61
7 changed files with 213 additions and 95 deletions
+74 -33
View File
@@ -629,7 +629,7 @@ define_env!(Env, <E: Ext>,
// This call is supposed to be called only by instrumentation injected code.
//
// - amount: How much gas is used.
gas(ctx, amount: u32) => {
[seal0] gas(ctx, amount: u32) => {
ctx.charge_gas(RuntimeToken::MeteringBlock(amount))?;
Ok(())
},
@@ -649,7 +649,7 @@ define_env!(Env, <E: Ext>,
//
// - If value length exceeds the configured maximum value length of a storage entry.
// - Upon trying to set an empty storage entry (value length is 0).
seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => {
[seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => {
ctx.charge_gas(RuntimeToken::SetStorage(value_len))?;
if value_len > ctx.ext.max_value_size() {
Err(Error::<E::T>::ValueTooLarge)?;
@@ -665,7 +665,7 @@ define_env!(Env, <E: Ext>,
// # Parameters
//
// - `key_ptr`: pointer into the linear memory where the location to clear the value is placed.
seal_clear_storage(ctx, key_ptr: u32) => {
[seal0] seal_clear_storage(ctx, key_ptr: u32) => {
ctx.charge_gas(RuntimeToken::ClearStorage)?;
let mut key: StorageKey = [0; 32];
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
@@ -684,7 +684,7 @@ define_env!(Env, <E: Ext>,
// # Errors
//
// `ReturnCode::KeyNotFound`
seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
[seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
ctx.charge_gas(RuntimeToken::GetStorageBase)?;
let mut key: StorageKey = [0; 32];
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
@@ -713,7 +713,7 @@ define_env!(Env, <E: Ext>,
//
// `ReturnCode::BelowSubsistenceThreshold`
// `ReturnCode::TransferFailed`
seal_transfer(
[seal0] seal_transfer(
ctx,
account_ptr: u32,
account_len: u32,
@@ -767,7 +767,7 @@ define_env!(Env, <E: Ext>,
// `ReturnCode::BelowSubsistenceThreshold`
// `ReturnCode::TransferFailed`
// `ReturnCode::NotCallable`
seal_call(
[seal0] seal_call(
ctx,
callee_ptr: u32,
callee_len: u32,
@@ -868,7 +868,7 @@ define_env!(Env, <E: Ext>,
// `ReturnCode::TransferFailed`
// `ReturnCode::NewContractNotFunded`
// `ReturnCode::CodeNotFound`
seal_instantiate(
[seal0] seal_instantiate(
ctx,
code_hash_ptr: u32,
code_hash_len: u32,
@@ -950,7 +950,7 @@ define_env!(Env, <E: Ext>,
// - 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.
seal_terminate(
[seal0] seal_terminate(
ctx,
beneficiary_ptr: u32,
beneficiary_len: u32
@@ -981,7 +981,7 @@ define_env!(Env, <E: Ext>,
// # Note
//
// This function can only be called once. Calling it multiple times will trigger a trap.
seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::InputBase)?;
if let Some(input) = ctx.input_data.take() {
ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| {
@@ -1010,7 +1010,7 @@ define_env!(Env, <E: Ext>,
// --- msb ---
//
// Using a reserved bit triggers a trap.
seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
[seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
ctx.charge_gas(RuntimeToken::Return(data_len))?;
Err(TrapReason::Return(ReturnData {
flags,
@@ -1028,7 +1028,7 @@ define_env!(Env, <E: Ext>,
// 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.
seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Caller)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged
@@ -1041,7 +1041,7 @@ define_env!(Env, <E: Ext>,
// `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.
seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Address)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged
@@ -1061,7 +1061,7 @@ define_env!(Env, <E: Ext>,
//
// It is recommended to avoid specifying very small values for `gas` as the prices for a single
// gas can be smaller than one.
seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::WeightToFee)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged
@@ -1076,7 +1076,7 @@ define_env!(Env, <E: Ext>,
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as Gas.
seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::GasLeft)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged
@@ -1091,7 +1091,7 @@ define_env!(Env, <E: Ext>,
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as T::Balance.
seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Balance)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged
@@ -1106,7 +1106,7 @@ define_env!(Env, <E: Ext>,
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as T::Balance.
seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::ValueTransferred)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged
@@ -1121,7 +1121,43 @@ define_env!(Env, <E: Ext>,
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as T::Hash.
seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
//
// # Deprecation
//
// This function is deprecated. Users should migrate to the version in the "seal1" module.
[seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Random)?;
if subject_len > ctx.ext.schedule().limits.subject_len {
Err(Error::<E::T>::RandomSubjectTooLong)?;
}
let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).0.encode(), false, already_charged
)?)
},
// Stores a random number for the current block and the given subject into the supplied buffer.
//
// The value is stored to linear memory at the address pointed to by `out_ptr`.
// `out_len_ptr` must point to a u32 value that describes the available space at
// `out_ptr`. This call overwrites it with the size of the value. If the available
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as (T::Hash, T::BlockNumber).
//
// # Changes from v0
//
// In addition to the seed it returns the block number since which it was determinable
// by chain observers.
//
// # Note
//
// The returned seed should only be used to distinguish commitments made before
// the returned block number. If the block number is too early (i.e. commitments were
// made afterwards), then ensure no further commitments may be made and repeatedly
// call this on later blocks until the block number returned is later than the latest
// commitment.
[seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Random)?;
if subject_len > ctx.ext.schedule().limits.subject_len {
Err(Error::<E::T>::RandomSubjectTooLong)?;
@@ -1138,7 +1174,7 @@ define_env!(Env, <E: Ext>,
// `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.
seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::Now)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged
@@ -1148,7 +1184,7 @@ define_env!(Env, <E: Ext>,
// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer.
//
// The data is encoded as T::Balance.
seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::MinimumBalance)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged
@@ -1170,7 +1206,7 @@ define_env!(Env, <E: Ext>,
// 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.
seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::TombstoneDeposit)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged
@@ -1208,7 +1244,7 @@ define_env!(Env, <E: Ext>,
// - Tombstone hashes do not match.
// - The calling contract is already present on the call stack.
// - The supplied code_hash does not exist on-chain.
seal_restore_to(
[seal0] seal_restore_to(
ctx,
dest_ptr: u32,
dest_len: u32,
@@ -1279,8 +1315,13 @@ define_env!(Env, <E: Ext>,
// - 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.
seal_deposit_event(ctx, topics_ptr: u32, topics_len: u32, data_ptr: u32, data_len: u32) => {
[seal0] seal_deposit_event(
ctx,
topics_ptr: u32,
topics_len: u32,
data_ptr: u32,
data_len: u32
) => {
fn has_duplicates<T: Ord>(items: &mut Vec<T>) -> bool {
// # Warning
//
@@ -1336,7 +1377,7 @@ define_env!(Env, <E: Ext>,
// - 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.
seal_set_rent_allowance(ctx, value_ptr: u32, value_len: u32) => {
[seal0] 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)?;
@@ -1353,7 +1394,7 @@ define_env!(Env, <E: Ext>,
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as T::Balance.
seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::RentAllowance)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged
@@ -1363,7 +1404,7 @@ define_env!(Env, <E: Ext>,
// 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.
seal_println(ctx, str_ptr: u32, str_len: u32) => {
[seal0] 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) {
log::info!(target: "runtime::contracts", "seal_println: {}", utf8);
@@ -1377,7 +1418,7 @@ define_env!(Env, <E: Ext>,
// `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.
seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::BlockNumber)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged
@@ -1404,7 +1445,7 @@ define_env!(Env, <E: Ext>,
// - `output_ptr`: the pointer into the linear memory where the output
// data is placed. The function will write the result
// directly into this buffer.
seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
[seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashSha256(input_len))?;
Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
},
@@ -1429,7 +1470,7 @@ define_env!(Env, <E: Ext>,
// - `output_ptr`: the pointer into the linear memory where the output
// data is placed. The function will write the result
// directly into this buffer.
seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
[seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?;
Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
},
@@ -1454,7 +1495,7 @@ define_env!(Env, <E: Ext>,
// - `output_ptr`: the pointer into the linear memory where the output
// data is placed. The function will write the result
// directly into this buffer.
seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
[seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?;
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
},
@@ -1479,7 +1520,7 @@ define_env!(Env, <E: Ext>,
// - `output_ptr`: the pointer into the linear memory where the output
// data is placed. The function will write the result
// directly into this buffer.
seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
[seal0] seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?;
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?)
},
@@ -1495,7 +1536,7 @@ define_env!(Env, <E: Ext>,
//
// If no chain extension exists the contract will trap with the `NoChainExtension`
// module error.
seal_call_chain_extension(
[seal0] seal_call_chain_extension(
ctx,
func_id: u32,
input_ptr: u32,
@@ -1531,7 +1572,7 @@ define_env!(Env, <E: Ext>,
// The returned information was collected and cached when the current contract call
// started execution. Any change to those values that happens due to actions of the
// current call or contracts that are called by this contract are not considered.
seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => {
[seal0] seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::RentParams)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.rent_params().encode(), false, already_charged