mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 02:51:08 +00:00
contracts: switch to wasmi gas metering (#14084)
* upgrade to wasmi 0.29 * prepare cleanup * sync ref_time w engine from the stack frame * proc_macro: sync gas in host funcs save: compiles, only gas pushing left to macro WIP proc macro proc macro: done * clean benchmarks & schedule: w_base = w_i64const * scale gas values btw engine and gas meter * (re)instrumentation & code_cache removed * remove gas() host fn, continue clean-up save * address review comments * move from CodeStorage&PrefabWasmModule to PristineCode&WasmBlob * refactor: no reftime_limit&schedule passes, no CodeStorage * bugs fixing * fix tests: expected deposit amount * fix prepare::tests * update tests and fix bugs tests::run_out_of_gas_engine, need 2 more save: 2 bugs with gas syncs: 1 of 2 tests done gas_syncs_no_overcharge bug fixed, test passes! cleaned out debug prints second bug is not a bug disabled_chain_extension test fix (err msg) tests run_out_of_fuel_host, chain_extension pass all tests pass * update docs * bump wasmi 0.30.0 * benchmarks updated, tests pass * refactoring * s/OwnerInfo/CodeInfo/g; * migration: draft, compiles * migration: draft, runs * migration: draft, runs (fixing) * deposits repaid non pro rata * deposits repaid pro rata * better try-runtime output * even better try-runtime output * benchmark migration * fix merge leftover * add forgotten fixtures, fix docs * address review comments * ci fixes * cleanup * benchmarks::prepare to return DispatchError * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * store memory limits to CodeInfo * ci: roll back weights * ".git/.scripts/commands/bench-vm/bench-vm.sh" pallet dev pallet_contracts * drive-by: update Readme and pallet rustdoc * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * use wasmi 0.29 * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * use wasmi 0.30 again * query memory limits from wasmi * better migration types * ci: pull weights from master * refactoring * ".git/.scripts/commands/bench-vm/bench-vm.sh" pallet dev pallet_contracts * addressing review comments * refactor * address review comments * optimize migration * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * another review round comments addressed * ci fix one * clippy fix * ci fix two --------- Co-authored-by: command-bot <>
This commit is contained in:
@@ -67,7 +67,6 @@ pub trait Environment<HostState> {
|
||||
}
|
||||
|
||||
/// Type of a storage key.
|
||||
#[allow(dead_code)]
|
||||
enum KeyType {
|
||||
/// Legacy fix sized key `[u8;32]`.
|
||||
Fix,
|
||||
@@ -174,9 +173,6 @@ impl HostError for TrapReason {}
|
||||
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Copy, Clone)]
|
||||
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(u64),
|
||||
/// Weight charged for copying data from the sandbox.
|
||||
CopyFromContract(u32),
|
||||
/// Weight charged for copying data to the sandbox.
|
||||
@@ -277,7 +273,6 @@ impl RuntimeCosts {
|
||||
fn token<T: Config>(&self, s: &HostFnWeights<T>) -> RuntimeToken {
|
||||
use self::RuntimeCosts::*;
|
||||
let weight = match *self {
|
||||
MeteringBlock(amount) => s.gas.saturating_add(Weight::from_parts(amount, 0)),
|
||||
CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()),
|
||||
CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()),
|
||||
Caller => s.caller,
|
||||
@@ -369,7 +364,7 @@ impl RuntimeCosts {
|
||||
macro_rules! charge_gas {
|
||||
($runtime:expr, $costs:expr) => {{
|
||||
let token = $costs.token(&$runtime.ext.schedule().host_fn_weights);
|
||||
$runtime.ext.gas_meter().charge(token)
|
||||
$runtime.ext.gas_meter_mut().charge(token)
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -485,25 +480,40 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> {
|
||||
|
||||
/// Converts the sandbox result and the runtime state into the execution outcome.
|
||||
pub fn to_execution_result(self, sandbox_result: Result<(), wasmi::Error>) -> ExecResult {
|
||||
use wasmi::core::TrapCode::OutOfFuel;
|
||||
use TrapReason::*;
|
||||
|
||||
match sandbox_result {
|
||||
// Contract returned from main function -> no data was returned.
|
||||
Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }),
|
||||
// `OutOfGas` when host asks engine to consume more than left in the _store_.
|
||||
// We should never get this case, as gas meter is being charged (and hence raises error)
|
||||
// first.
|
||||
Err(wasmi::Error::Store(_)) => Err(Error::<E::T>::OutOfGas.into()),
|
||||
// Contract either trapped or some host function aborted the execution.
|
||||
Err(wasmi::Error::Trap(trap)) => {
|
||||
// If we encoded a reason then it is some abort generated by a host function.
|
||||
// Otherwise the trap came from the contract.
|
||||
let reason: TrapReason = trap.downcast().ok_or(Error::<E::T>::ContractTrapped)?;
|
||||
match reason {
|
||||
Return(ReturnData { flags, data }) => {
|
||||
let flags =
|
||||
ReturnFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?;
|
||||
Ok(ExecReturnValue { flags, data })
|
||||
},
|
||||
Termination =>
|
||||
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }),
|
||||
SupervisorError(error) => return Err(error.into()),
|
||||
if let Some(OutOfFuel) = trap.trap_code() {
|
||||
// `OutOfGas` during engine execution.
|
||||
return Err(Error::<E::T>::OutOfGas.into())
|
||||
}
|
||||
// If we encoded a reason then it is some abort generated by a host function.
|
||||
if let Some(reason) = &trap.downcast_ref::<TrapReason>() {
|
||||
match &reason {
|
||||
Return(ReturnData { flags, data }) => {
|
||||
let flags = ReturnFlags::from_bits(*flags)
|
||||
.ok_or(Error::<E::T>::InvalidCallFlags)?;
|
||||
return Ok(ExecReturnValue { flags, data: data.to_vec() })
|
||||
},
|
||||
Termination =>
|
||||
return Ok(ExecReturnValue {
|
||||
flags: ReturnFlags::empty(),
|
||||
data: Vec::new(),
|
||||
}),
|
||||
SupervisorError(error) => return Err((*error).into()),
|
||||
}
|
||||
}
|
||||
// Otherwise the trap came from the contract itself.
|
||||
Err(Error::<E::T>::ContractTrapped.into())
|
||||
},
|
||||
// Any other error is returned only if instantiation or linking failed (i.e.
|
||||
// wasm binary tried to import a function that is not provided by the host).
|
||||
@@ -536,7 +546,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> {
|
||||
/// refunded to match the actual amount.
|
||||
pub fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) {
|
||||
let token = actual_costs.token(&self.ext.schedule().host_fn_weights);
|
||||
self.ext.gas_meter().adjust_gas(charged, token);
|
||||
self.ext.gas_meter_mut().adjust_gas(charged, token);
|
||||
}
|
||||
|
||||
/// Read designated chunk from the sandbox memory.
|
||||
@@ -1004,18 +1014,6 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> {
|
||||
// for every function.
|
||||
#[define_env(doc)]
|
||||
pub mod env {
|
||||
/// Account for used gas. Traps if gas used is greater than gas limit.
|
||||
///
|
||||
/// NOTE: This is a implementation defined call and is NOT a part of the public API.
|
||||
/// This call is supposed to be called only by instrumentation injected code.
|
||||
/// It deals only with the *ref_time* Weight.
|
||||
///
|
||||
/// - `amount`: How much gas is used.
|
||||
fn gas(ctx: _, _memory: _, amount: u64) -> Result<(), TrapReason> {
|
||||
ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the value at the given key in the contract storage.
|
||||
///
|
||||
/// Equivalent to the newer [`seal1`][`super::api_doc::Version1::set_storage`] version with the
|
||||
|
||||
Reference in New Issue
Block a user