Function fvm_wasm_instrument::gas_metering::inject

source ·
pub fn inject<R: Rules>(
    raw_wasm: &[u8],
    rules: &R,
    gas_module_name: &str,
) -> Result<Vec<u8>>
Expand description

Transforms a given module into one that charges gas for code to be executed by proxy of an imported gas metering function.

The output module imports a mutable global i64 $GAS_COUNTER_NAME (“gas_couner”) from the specified module. The value specifies the amount of available units of gas. A new function doing gas accounting using this global is added to the module. Having the accounting logic in WASM lets us avoid the overhead of external calls.

The body of each function is divided into metered blocks, and the calls to charge gas are inserted at the beginning of every such block of code. A metered block is defined so that, unless there is a trap, either all of the instructions are executed or none are. These are similar to basic blocks in a control flow graph, except that in some cases multiple basic blocks can be merged into a single metered block. This is the case if any path through the control flow graph containing one basic block also contains another.

Charging gas is at the beginning of each metered block ensures that 1) all instructions executed are already paid for, 2) instructions that will not be executed are not charged for unless execution traps, and 3) the number of calls to “gas” is minimized. The corollary is that modules instrumented with this metering code may charge gas for instructions not executed in the event of a trap.

Additionally, each memory.grow instruction found in the module is instrumented to first make a call to charge gas for the additional pages requested. This cannot be done as part of the block level gas charges as the gas cost is not static and depends on the stack argument to memory.grow.

The above transformations are performed for every function body defined in the module. This function also rewrites all function indices references by code, table elements, etc., since the addition of an imported functions changes the indices of module-defined functions.

This routine runs in time linear in the size of the input module.

The function fails if the module contains any operation forbidden by gas rule set, returning the original module as an Err. Only one imported global is allowed per gas_module_name, the one corresponding to the gas spending measurement