Expand description
§Ethereum Virtual Machine in Rust
Rust EVM is a flexible Ethereum Virtual Machine interpreter that can be easily customized.
§Basic usage
If you want to simply run EVM against Ethereum mainnet, use the evm-mainnet crate.
The entrypoint of a normal EVM execution is through the transact function. The transact function implements a hybrid (stack-based, and then heap-based) call stack.
To use the transact function, you will need to first implement a
backend. This is anything that implements
interpreter::runtime::RuntimeEnvironment, and
interpreter::runtime::RuntimeBackend traits. You will also need to select
a few other components to construct the invoker
parameter needed for the
function.
- Select an Invoker. The invoker defines all details of the execution environment except the external backend. standard::Invoker is probably want you want if you are not extending EVM.
- For the standard invoker, select a standard::Config, which represents different Ethereum hard forks.
- Select the precompile set. You may want the
StandardPrecompileSet
inevm-precompile
crate. - Select a resolver. This defines how the interpreter machines are resolved given a code address for call or an init code for create. You may want standard::EtableResolver, which accepts a precompile set.
§Debugging
Rust EVM supports two different methods for debugging. You can either single step the execution, or you can trace the opcodes.
§Single stepping
Single stepping allows you to examine the full machine internal state every time the interpreter finishes executing a single opcode. To do this, use the heap-only call stack HeapTransact. Parameters passed to HeapTransact are the same as transact.
§Tracing
The interpreter machine uses information from an interpreter::etable::Etable to decide how each opcode behaves. The default implementation is interpreter::etable::DispatchEtable. interpreter::etable::DispatchEtable is fully customizable and a helper function is also provided interpreter::etable::DispatchEtable::wrap.
If you also want to trace inside gasometers, simply create a wrapper struct of the gasometer you use, and pass that into the invoker.
§Customization
All aspects of the interpreter can be customized individually.
- New opcodes can be added or customized through interpreter::etable::DispatchEtable.
- Gas metering behavior can be customized by wrapping standard::eval_gasometer or creating new ones.
- Code resolution and precompiles can be customized by standard::Resolver. Async precompile is also possible through the evm-future crate.
- Call invocation and transaction behavior can be customized via standard::Invoker.
Re-exports§
pub use evm_interpreter as interpreter;
Modules§
Structs§
- Heap
Transact - Heap-based call stack for a transaction. This is suitable for single stepping or debugging. The hybrid version transact uses a heap-based call stack internally after certain depth.
Enums§
- Invoker
Control - Control for an invoker.
- Merge
Strategy - Merge strategy of a backend substate layer or a call stack gasometer layer.
Traits§
- GasMut
State - Mutable GasState. This simply allows recording an arbitrary gas.
- Invoker
- An invoker, responsible for pushing/poping values in the call stack.
Functions§
- transact
- Initiate a transaction, using a hybrid call stack.