bytecodealliance / wasmtime

A fast and secure runtime for WebAssembly
https://wasmtime.dev/
Apache License 2.0
14.87k stars 1.24k forks source link

More control over fuel consumption #5109

Open coolreader18 opened 1 year ago

coolreader18 commented 1 year ago

Feature

A set of new APIs that provide more control over fuel consumption:

impl Config {
    fn fuel_cost(&mut self, f: impl Fn(WasmOpcode) -> u64 + Send + Sync + 'static) -> &mut Self;
}
enum WasmOpcode {
    Unreachable,
    Nop,
    Block,
    Loop,
    // ...
}
impl Store {
    fn fuel_remaining(&self) -> Option<u64>;
    /// Returns an error if the store is not configured for fuel consumption
    fn set_fuel(&mut self, value: u64) -> Result<()>;
}
#[non_exhaustive]
struct OutOfFuelError;

Benefit

Allows more direct control over fuel consumption and filling, letting users set custom fuel costs for each operand if they deem some to be more costly/intensive in their environment, as well letting them set precisely how much fuel they might allow a single function call or set of function calls. OutOfFuelError being made public allows users to check when a Trap was caused by fuel running out.

Implementation

I have an implementation for the custom fuel cost configuration, and the methods on Store should be fairly trivial.

Alternatives

fuel_remaining and set_fuel can be approximated by consume_fuel(0) and if new_fuel > fuel_remaining() { add_fuel(delta) } else { consume_fuel(delta) } respectively. fuel_cost cannot be emulated, so the alternative is to just accept wasmtime's default cost function. As an alternative in designing the API, the fuel_cost closure could take a &wasmparser::Operator<'_> as it did in the original version of this issue. However, that would require exposing wasmparser in wasmtime's public api, which is undesirable.

coolreader18 commented 1 year ago

Oh, looks like wasmtime-fuzzing has a shim for set_fuel the same as I described:

https://github.com/bytecodealliance/wasmtime/blob/main/crates/fuzzing/src/oracles.rs#L790-L802

howjmay commented 1 year ago

Hi I am curious why #5220 can help us set customized fuel for each opcode?

RReverser commented 9 months ago

Looks like #7240 only adds reset_fuel, I don't think it should've auto-closed this issue?

In particular,

fn fuel_cost(&mut self, f: impl Fn(WasmOpcode) -> u64 + Send + Sync + 'static) -> &mut Self;

this would be still desirable.

rockwotj commented 9 months ago

Apologies for this getting closed. I was picking up #5220 which also would have closed this issue. Maybe @coolreader18 could update this issue to have it be more about a custom cost function for fuel APIs?

Also if you have opinions on store fuel related APIs would love to hear there here https://github.com/bytecodealliance/wasmtime/issues/7255