Closed YaronWittenstein closed 1 year ago
Not closing this SMIP because it's not strictly outdated per se, but gas metering within the SVM is so far down the road that it doesn't currently make sense to talk about this.
Closing this now as we're not currently pursuing a Wasm-based VM. Can revisit in the future if we go this route.
Gas Metering
Overview
This document describes what should be done to support Gas-Metering as a pricing mechanism for running Transactions. Since the
Templates
released in the 1st Mainnet will be compliant with the Fixed-Gas, everything described under this piece will be relevant only for future versions.Goals and Motivation
The motivation for the Fixed-Gas Wasm pricing was that
Templates
that abide by specific rules would result in more precise pricing for their transactions.In short, it boils down to whether a
Template
contains potential infinite loops. If we have code that contains no loops, call-cycles, recursions, and dynamic-dispatch on runtime. We can apply static-analysis techniques and compute the gas price for running a piece of code ahead of time.Since many
Templates
fall into that category, we can optimize their pricing. So the decision was that we'd make sure that theTemplates
for Genesis would respect these rules.However, some
Templates
require more flexibility. In such cases, we'll have to introduce another pricing mechanism. This SMIP details how to add theGas Metering
into SVM - theGas Metering
is the most commonly used solution today for pricing running code.The downside is that we can't precisely predict how much
Gas
would suffice for running aTransaction
without hittingOut of Gas
(see the Halting Problem). Current solutions usually simulate a run, and then they add some extra for theGas Limit
set into theTransaction
.Another standard handling is looking at historical
Transactions
and making a sophisticated guess. Most of the time, it'd work fine. Every now and then, the guess won't work, and theTransaction
will reachOut of Gas
and fail to complete.High-level design
Instructions Injection
To implement
Gas Metering
on a Wasm program (i.e., theTemplate
's code), we need to inject new opcodes into the program. The most naive solution would be to inject a host function call (such asinc_gas
) after each instruction. However, that would result in a much slower running time.The solution should probably update the used
Gas
once every couple of Wasm instructions. For example, each new scope should start a new measurement and end the previous one.Here is an example:
Given this Wasm program sketch:
After injecting the
inc_gas
calls (inc_gas
is the name of the host function that tracks the gas usage), the newly transformed code will reflect the changes:important:
Fixed-Gas Wasm
pricing method as well).Template
might be modified differently under different layers having different consensus rules. That's why it's crucial to store the originalTemplate
intact under theGlobal State
.Templates
should take into account the consensus rules used for the Wasm transformation (i.e., byLayer Number
)Wasm Runtime-Agnostic
The critical thing is that the applied solution won't assume anything specific to the underlying Wasm Runtime used.
Today, SVM uses
[Wasmer](https://github.com/wasmerio/wasmer)
solely, but it could have also used[Wasmtime](https://github.com/bytecodealliance/wasmtime)
. Furthermore, it's advised that SVM will support both in the future and that the used Wasm runtime will be configurable. That would strengthen the system as a whole.It's good to know that
Wasmer
has a solution used by some of the Wasm-based Blockchain companies, it's called theMetering Middleware
https://github.com/wasmerio/wasmer/blob/a66226594f5035c6a4816ad338c257f2ce5c5c86/lib/middlewares/src/metering.rs
Due to the described above, it seems that SVM would be better to apply its transformation and not rely on this one. We don't want the injected code having Globals named
wasmer_metering_remaining_points
orwasmer_metering_points_exhausted
. Of course, theinc_gas
stated above could be an importedGlobal Variable
instead of an imported host function.In addition,
Wasmer
's middleware is part of the compilation process. So I'd recommend assuming the least about the Wasm runtime API and just having the transformation execute before compiling the Wasm module. One existing tool for transforming Wasm is[walrus](https://github.com/rustwasm/walrus)
, and maybe there're other similar Rust libraries.Hybrid Mode
Once the
Gas Metering
mechanism is implemented, we could introduce a new one I'm callingHybrid Gas Pricing.
Given aTemplate
with Fixed-Gas Wasm code, we can set theGas Limit
of the Transaction to the value provided by theFixed-Gas Pricing
.That value accounts for the most expensive running path the
Transaction
could end up having. Having theHybrid
mode used will applyGas Metering
and pay for what's been used. Since we've set theGas Limit
to the worst-case scenario - we can know for sure that the Transaction won't fail due toOut of Gas
.Questions/concerns
TBD
Stakeholders and reviewers
@neysofu @avive @moshababo @lrettig @noamnelke