Newer
Older
// Should be decodable as a `T::Balance`. Traps otherwise.
// - value_len: length of the value buffer.
// `ReturnCode::TransferFailed`
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)
}
}
// 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.
[seal0] seal_call(
ctx,
callee_ptr: u32,
gas: u64,
value_ptr: u32,
input_data_ptr: u32,
input_data_len: u32,
output_ptr: u32,
output_len_ptr: u32
) -> ReturnCode => {
ctx.call(
CallFlags::ALLOW_REENTRY,
Yarik Bratashchuk
committed
CallType::Call{callee_ptr, value_ptr, gas},
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
},
// 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`.
//
// - 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`
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
) -> ReturnCode => {
ctx.call(
CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
Yarik Bratashchuk
committed
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
CallType::Call{callee_ptr, value_ptr, gas},
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
},
// 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`
[seal0] seal_delegate_call(
Yarik Bratashchuk
committed
ctx,
flags: u32,
code_hash_ptr: u32,
input_data_ptr: u32,
input_data_len: u32,
output_ptr: u32,
output_len_ptr: u32
) -> ReturnCode => {
ctx.call(
CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
Yarik Bratashchuk
committed
CallType::DelegateCall{code_hash_ptr},
input_data_ptr,
input_data_len,
output_ptr,
output_len_ptr,
)
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
// 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.
[seal0] seal_instantiate(
ctx,
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
) -> ReturnCode => {
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,
)
},
// 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
Alexander Theißen
committed
// 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.
// - 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.
// 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`
[seal1] seal_instantiate(
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
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
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.
[seal0] seal_terminate(ctx, beneficiary_ptr: u32, _beneficiary_len: u32) => {
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.
[seal1] seal_terminate(ctx, beneficiary_ptr: u32) => {
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`.
[seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
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:
// ```
Alexander Theißen
committed
// 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.
[seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
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.
[seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
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
)?)
},
Sasha Gryaznov
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
[seal0] seal_is_contract(ctx, account_ptr: u32) -> u32 => {
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)
},
// 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
[seal0] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
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
[seal0] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => {
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)?)
},
Sasha Gryaznov
committed
// 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
[seal0] seal_caller_is_origin(ctx) -> u32 => {
Sasha Gryaznov
committed
ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
Ok(ctx.ext.caller_is_origin() as u32)
},
// 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.
[seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
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.
[seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
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.
[seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::GasLeft)?;
let gas_left = &ctx.ext.gas_meter().gas_left().encode();
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, gas_left, false, already_charged,
Alexander Theißen
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.
//
// The data is encoded as T::Balance.
[seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
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.
[seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
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.
[seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::Random)?;
if subject_len > ctx.ext.schedule().limits.subject_len {
return Err(Error::<E::T>::RandomSubjectTooLong.into());
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
}
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(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.
[seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
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.
[seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
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.
// There is no longer a tombstone deposit. This function always returns 0.
[seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
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
[seal0] seal_restore_to(
ctx,
_rent_allowance_len: u32,
_delta_ptr: u32,
_delta_count: u32
ctx.charge_gas(RuntimeCosts::DebugMessage)?;
Ok(())
// Was used to restore the given destination contract sacrificing the caller.
// The state rent functionality was removed. This is stub only exists for
// backwards compatiblity
[seal1] seal_restore_to(
_dest_ptr: u32,
_code_hash_ptr: u32,
_rent_allowance_ptr: u32,
_delta_ptr: u32,
_delta_count: u32
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.
[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
//
// 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 {
_ => ctx.read_sandbox_memory_as_unbounded(topics_ptr, topics_len)?,
// If there are more than `event_topics`, then trap.
if topics.len() > ctx.ext.schedule().limits.event_topics as usize {
return Err(Error::<E::T>::TooManyTopics.into());
}
// Check for duplicate topics. If there are any, then trap.
// Complexity O(n * log(n)) and no additional allocations.
// This also sorts the topics.
if has_duplicates(&mut topics) {
return Err(Error::<E::T>::DuplicateTopics.into());
let event_data = ctx.read_sandbox_memory(data_ptr, data_len)?;
ctx.ext.deposit_event(topics, event_data);
// Was used to set rent allowance of the contract.
//
// # Note
//
// The state rent functionality was removed. This is stub only exists for
// backwards compatiblity.
[seal0] seal_set_rent_allowance(ctx, _value_ptr: u32, _value_len: u32) => {
ctx.charge_gas(RuntimeCosts::DebugMessage)?;
// Was used to set rent allowance of the contract.
// # Note
//
// The state rent functionality was removed. This is stub only exists for
// backwards compatiblity.
[seal1] seal_set_rent_allowance(ctx, _value_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::DebugMessage)?;
// Was used to store the rent allowance into the supplied buffer.
// The state rent functionality was removed. This is stub only exists for
// backwards compatiblity.
[seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::Balance)?;
let rent_allowance = <BalanceOf<E::T>>::max_value().encode();
Alexander Theißen
committed
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &rent_allowance, false, already_charged
Alexander Theißen
committed
)?)
// 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.
[seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::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.
[seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
},
// 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.
[seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
},
// 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.
[seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
},
// 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.
[seal0] seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?;
Alexander Theißen
committed
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?)
// 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.
[seal0] 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() {
return Err(Error::<E::T>::NoChainExtension.into());
}
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,
})),
}
},
// Emit a custom debug message.
//
// No newlines are added to the supplied message.
// Specifying invalid UTF-8 triggers a trap.
//
// This is a no-op if debug message recording is disabled which is always the case
// when the code is executing on-chain. The message is interpreted as UTF-8 and
// appended to the debug buffer which is then supplied to the calling RPC client.
//
// # Note
//
// Even though no action is taken when debug message recording is disabled there is still
// a non trivial overhead (and weight cost) associated with calling this function. Contract
// languages should remove calls to this function (either at runtime or compile time) when
// not being executed as an RPC. For example, they could allow users to disable logging
// through compile time flags (cargo features) for on-chain deployment. Additionally, the
// return value of this function can be cached in order to prevent further calls at runtime.
[seal0] seal_debug_message(ctx, str_ptr: u32, str_len: u32) -> ReturnCode => {
ctx.charge_gas(RuntimeCosts::DebugMessage)?;
if ctx.ext.append_debug_buffer("") {
let data = ctx.read_sandbox_memory(str_ptr, str_len)?;
let msg = core::str::from_utf8(&data)
.map_err(|_| <Error<E::T>>::DebugMessageInvalidUTF8)?;
ctx.ext.append_debug_buffer(msg);
return Ok(ReturnCode::Success);
}
Ok(ReturnCode::LoggingDisabled)
},
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
// Call some dispatchable of the runtime.
//
// This function decodes the passed in data as the overarching `Call` type of the
// runtime and dispatches it. The weight as specified in the runtime is charged
// from the gas meter. Any weight refunds made by the dispatchable are considered.
//
// The filter specified by `Config::CallFilter` is attached to the origin of
// the dispatched call.
//
// # 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.
//
// # Return Value
//
// Returns `ReturnCode::Success` when the dispatchable was succesfully executed and
// returned `Ok`. When the dispatchable was exeuted but returned an error
// `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not
// provided because it is not guaranteed to be stable.
//
// # Comparison with `ChainExtension`
//
// Just as a chain extension this API allows the runtime to extend the functionality
// of contracts. While making use of this function is generelly easier it cannot be
// used in call cases. Consider writing a chain extension if you need to do perform
// one of the following tasks:
//
// - Return data.
// - Provide functionality **exclusively** to contracts.
// - Provide custom weights.
// - Avoid the need to keep the `Call` data structure stable.
//
// # Unstable
//
// This function is unstable and subject to change (or removal) in the future. Do not
// deploy a contract using it to a production chain.
[__unstable__] seal_call_runtime(ctx, call_ptr: u32, call_len: u32) -> ReturnCode => {
use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight};
ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?;
let call: <E::T as Config>::Call = ctx.read_sandbox_memory_as_unbounded(
call_ptr, call_len
)?;
let dispatch_info = call.get_dispatch_info();
let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?;
let result = ctx.ext.call_runtime(call);
let actual_weight = extract_actual_weight(&result, &dispatch_info);
ctx.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight));
match result {
Ok(_) => Ok(ReturnCode::Success),
Err(_) => Ok(ReturnCode::CallRuntimeReturnedError),
}
},
// Recovers the ECDSA public key from the given message hash and signature.
//
// Writes the public key into the given output buffer.
// Assumes the secp256k1 curve.
//
// # Parameters
//
// - `signature_ptr`: the pointer into the linear memory where the signature
Sasha Gryaznov
committed
// is placed. Should be decodable as a 65 bytes. Traps otherwise.
// - `message_hash_ptr`: the pointer into the linear memory where the message
// hash is placed. Should be decodable as a 32 bytes. Traps otherwise.
// - `output_ptr`: the pointer into the linear memory where the output
Sasha Gryaznov
committed
// data is placed. The buffer should be 33 bytes. The function
// will write the result directly into this buffer.
//
// # Errors
//
// `ReturnCode::EcdsaRecoverFailed`
[__unstable__] seal_ecdsa_recover(ctx, signature_ptr: u32, message_hash_ptr: u32, output_ptr: u32) -> ReturnCode => {
ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?;