pub fn inject<R: Rules, B: Backend>(
    module: Module,
    backend: B,
    rules: &R
) -> Result<Module, Module>
Expand description

Transforms a given module into one that tracks the gas charged during its execution.

The output module uses the gas function to track the gas spent. The function could be either an imported or a local one modifying a mutable global. The argument is the amount of gas required to continue execution. The execution engine is meant to keep track of the total amount of gas used and trap or otherwise halt execution of the runtime if the gas usage exceeds some allowed limit.

The body of each function of the original module 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 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. If the module has a NameSection, added by calling parse_names, the indices will also be updated.

Syncronizing the amount of gas charged with the execution engine can be done in two ways. The first way is by calling the imported gas host function, see host_function for details. The second way is by using a local gas function together with a mutable global, see mutable_global for details.

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.