mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 17:01:09 +00:00
contracts: Fix seal_call weights (#10796)
* Fix call weights * Fix instantiate benchmark * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove stale and superflous comments * `decrement_refcount` should be infallible * Don't hardcode increment_refcount, decrement_refcount * Rename CopyIn/CopyOut * Fix warning in tests Co-authored-by: Parity Bot <admin@parity.io>
This commit is contained in:
committed by
GitHub
parent
47622d6912
commit
b82cfbac4d
@@ -136,6 +136,10 @@ pub enum RuntimeCosts {
|
||||
/// Charge the gas meter with the cost of a metering block. The charged costs are
|
||||
/// the supplied cost of the block plus the overhead of the metering itself.
|
||||
MeteringBlock(u32),
|
||||
/// Weight charged for copying data from the sandbox.
|
||||
CopyFromContract(u32),
|
||||
/// Weight charged for copying data to the sandbox.
|
||||
CopyToContract(u32),
|
||||
/// Weight of calling `seal_caller`.
|
||||
Caller,
|
||||
/// Weight of calling `seal_is_contract`.
|
||||
@@ -162,8 +166,6 @@ pub enum RuntimeCosts {
|
||||
WeightToFee,
|
||||
/// Weight of calling `seal_input` without the weight of copying the input.
|
||||
InputBase,
|
||||
/// Weight of copying the input data for the given size.
|
||||
InputCopyOut(u32),
|
||||
/// Weight of calling `seal_return` for the given output size.
|
||||
Return(u32),
|
||||
/// Weight of calling `seal_terminate`.
|
||||
@@ -188,21 +190,19 @@ pub enum RuntimeCosts {
|
||||
TakeStorage(u32),
|
||||
/// Weight of calling `seal_transfer`.
|
||||
Transfer,
|
||||
/// Weight of calling `seal_call` for the given input size.
|
||||
CallBase(u32),
|
||||
/// Base weight of calling `seal_call`.
|
||||
CallBase,
|
||||
/// Weight of calling `seal_delegate_call` for the given input size.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
DelegateCallBase(u32),
|
||||
DelegateCallBase,
|
||||
/// Weight of the transfer performed during a call.
|
||||
CallSurchargeTransfer,
|
||||
/// Weight of output received through `seal_call` for the given size.
|
||||
CallCopyOut(u32),
|
||||
/// Weight of calling `seal_instantiate` for the given input and salt without output weight.
|
||||
/// This includes the transfer as an instantiate without a value will always be below
|
||||
/// the existential deposit and is disregarded as corner case.
|
||||
/// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag.
|
||||
CallInputCloned(u32),
|
||||
/// Weight of calling `seal_instantiate` for the given input length and salt.
|
||||
InstantiateBase { input_data_len: u32, salt_len: u32 },
|
||||
/// Weight of output received through `seal_instantiate` for the given size.
|
||||
InstantiateCopyOut(u32),
|
||||
/// Weight of the transfer performed during an instantiate.
|
||||
InstantiateSurchargeTransfer,
|
||||
/// Weight of calling `seal_hash_sha_256` for the given input size.
|
||||
HashSha256(u32),
|
||||
/// Weight of calling `seal_hash_keccak_256` for the given input size.
|
||||
@@ -216,9 +216,6 @@ pub enum RuntimeCosts {
|
||||
EcdsaRecovery,
|
||||
/// Weight charged by a chain extension through `seal_call_chain_extension`.
|
||||
ChainExtension(u64),
|
||||
/// Weight charged for copying data from the sandbox.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CopyIn(u32),
|
||||
/// Weight charged for calling into the runtime.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntime(Weight),
|
||||
@@ -236,6 +233,8 @@ impl RuntimeCosts {
|
||||
use self::RuntimeCosts::*;
|
||||
let weight = match *self {
|
||||
MeteringBlock(amount) => s.gas.saturating_add(amount.into()),
|
||||
CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()),
|
||||
CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()),
|
||||
Caller => s.caller,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
IsContract => s.is_contract,
|
||||
@@ -250,7 +249,6 @@ impl RuntimeCosts {
|
||||
Now => s.now,
|
||||
WeightToFee => s.weight_to_fee,
|
||||
InputBase => s.input,
|
||||
InputCopyOut(len) => s.input_per_byte.saturating_mul(len.into()),
|
||||
Return(len) => s.r#return.saturating_add(s.return_per_byte.saturating_mul(len.into())),
|
||||
Terminate => s.terminate,
|
||||
Random => s.random,
|
||||
@@ -277,18 +275,16 @@ impl RuntimeCosts {
|
||||
.take_storage
|
||||
.saturating_add(s.take_storage_per_byte.saturating_mul(len.into())),
|
||||
Transfer => s.transfer,
|
||||
CallBase(len) =>
|
||||
s.call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())),
|
||||
CallSurchargeTransfer => s.call_transfer_surcharge,
|
||||
CallCopyOut(len) => s.call_per_output_byte.saturating_mul(len.into()),
|
||||
CallBase => s.call,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
DelegateCallBase(len) =>
|
||||
s.delegate_call.saturating_add(s.call_per_input_byte.saturating_mul(len.into())),
|
||||
DelegateCallBase => s.delegate_call,
|
||||
CallSurchargeTransfer => s.call_transfer_surcharge,
|
||||
CallInputCloned(len) => s.call_per_cloned_byte.saturating_mul(len.into()),
|
||||
InstantiateBase { input_data_len, salt_len } => s
|
||||
.instantiate
|
||||
.saturating_add(s.instantiate_per_input_byte.saturating_mul(input_data_len.into()))
|
||||
.saturating_add(s.return_per_byte.saturating_mul(input_data_len.into()))
|
||||
.saturating_add(s.instantiate_per_salt_byte.saturating_mul(salt_len.into())),
|
||||
InstantiateCopyOut(len) => s.instantiate_per_output_byte.saturating_mul(len.into()),
|
||||
InstantiateSurchargeTransfer => s.instantiate_transfer_surcharge,
|
||||
HashSha256(len) => s
|
||||
.hash_sha2_256
|
||||
.saturating_add(s.hash_sha2_256_per_byte.saturating_mul(len.into())),
|
||||
@@ -304,8 +300,7 @@ impl RuntimeCosts {
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
EcdsaRecovery => s.ecdsa_recover,
|
||||
ChainExtension(amount) => amount,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CopyIn(len) => s.return_per_byte.saturating_mul(len.into()),
|
||||
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntime(weight) => weight,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
@@ -319,6 +314,17 @@ impl RuntimeCosts {
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`Runtime::charge_gas`].
|
||||
///
|
||||
/// We need this access as a macro because sometimes hiding the lifetimes behind
|
||||
/// a function won't work out.
|
||||
macro_rules! charge_gas {
|
||||
($runtime:expr, $costs:expr) => {{
|
||||
let token = $costs.token(&$runtime.ext.schedule().host_fn_weights);
|
||||
$runtime.ext.gas_meter().charge(token)
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Copy, Clone)]
|
||||
struct RuntimeToken {
|
||||
@@ -339,7 +345,7 @@ where
|
||||
|
||||
bitflags! {
|
||||
/// Flags used to change the behaviour of `seal_call` and `seal_delegate_call`.
|
||||
struct CallFlags: u32 {
|
||||
pub struct CallFlags: u32 {
|
||||
/// Forward the input of current function to the callee.
|
||||
///
|
||||
/// Supplied input pointers are ignored when set.
|
||||
@@ -393,11 +399,11 @@ enum CallType {
|
||||
}
|
||||
|
||||
impl CallType {
|
||||
fn cost(&self, input_data_len: u32) -> RuntimeCosts {
|
||||
fn cost(&self) -> RuntimeCosts {
|
||||
match self {
|
||||
CallType::Call { .. } => RuntimeCosts::CallBase(input_data_len),
|
||||
CallType::Call { .. } => RuntimeCosts::CallBase,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase(input_data_len),
|
||||
CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -493,8 +499,7 @@ where
|
||||
///
|
||||
/// Returns `Err(HostError)` if there is not enough gas.
|
||||
pub fn charge_gas(&mut self, costs: RuntimeCosts) -> Result<ChargedAmount, DispatchError> {
|
||||
let token = costs.token(&self.ext.schedule().host_fn_weights);
|
||||
self.ext.gas_meter().charge(token)
|
||||
charge_gas!(self, costs)
|
||||
}
|
||||
|
||||
/// Adjust a previously charged amount down to its actual amount.
|
||||
@@ -734,12 +739,15 @@ where
|
||||
output_ptr: u32,
|
||||
output_len_ptr: u32,
|
||||
) -> Result<ReturnCode, TrapReason> {
|
||||
self.charge_gas(call_type.cost(input_data_len))?;
|
||||
self.charge_gas(call_type.cost())?;
|
||||
let input_data = if flags.contains(CallFlags::CLONE_INPUT) {
|
||||
self.input_data.as_ref().ok_or_else(|| Error::<E::T>::InputForwarded)?.clone()
|
||||
let input = self.input_data.as_ref().ok_or_else(|| Error::<E::T>::InputForwarded)?;
|
||||
charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?;
|
||||
input.clone()
|
||||
} else if flags.contains(CallFlags::FORWARD_INPUT) {
|
||||
self.input_data.take().ok_or_else(|| Error::<E::T>::InputForwarded)?
|
||||
} else {
|
||||
self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?;
|
||||
self.read_sandbox_memory(input_data_ptr, input_data_len)?
|
||||
};
|
||||
|
||||
@@ -782,7 +790,7 @@ where
|
||||
|
||||
if let Ok(output) = &call_outcome {
|
||||
self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| {
|
||||
Some(RuntimeCosts::CallCopyOut(len))
|
||||
Some(RuntimeCosts::CopyToContract(len))
|
||||
})?;
|
||||
}
|
||||
Ok(Runtime::<E>::exec_into_return_code(call_outcome)?)
|
||||
@@ -803,8 +811,11 @@ where
|
||||
salt_len: u32,
|
||||
) -> Result<ReturnCode, TrapReason> {
|
||||
self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?;
|
||||
let code_hash: CodeHash<<E as Ext>::T> = self.read_sandbox_memory_as(code_hash_ptr)?;
|
||||
let value: BalanceOf<<E as Ext>::T> = self.read_sandbox_memory_as(value_ptr)?;
|
||||
if value > 0u32.into() {
|
||||
self.charge_gas(RuntimeCosts::InstantiateSurchargeTransfer)?;
|
||||
}
|
||||
let code_hash: CodeHash<<E as Ext>::T> = self.read_sandbox_memory_as(code_hash_ptr)?;
|
||||
let input_data = self.read_sandbox_memory(input_data_ptr, input_data_len)?;
|
||||
let salt = self.read_sandbox_memory(salt_ptr, salt_len)?;
|
||||
let instantiate_outcome = self.ext.instantiate(gas, code_hash, value, input_data, &salt);
|
||||
@@ -819,7 +830,7 @@ where
|
||||
)?;
|
||||
}
|
||||
self.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| {
|
||||
Some(RuntimeCosts::InstantiateCopyOut(len))
|
||||
Some(RuntimeCosts::CopyToContract(len))
|
||||
})?;
|
||||
}
|
||||
Ok(Runtime::<E>::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?)
|
||||
@@ -1302,7 +1313,7 @@ define_env!(Env, <E: Ext>,
|
||||
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::InputCopyOut(len))
|
||||
Some(RuntimeCosts::CopyToContract(len))
|
||||
})?;
|
||||
ctx.input_data = Some(input);
|
||||
Ok(())
|
||||
@@ -1911,7 +1922,7 @@ define_env!(Env, <E: Ext>,
|
||||
// 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::CopyIn(call_len))?;
|
||||
ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?;
|
||||
let call: <E::T as Config>::Call = ctx.read_sandbox_memory_as_unbounded(
|
||||
call_ptr, call_len
|
||||
)?;
|
||||
|
||||
Reference in New Issue
Block a user