EEVM.Config (eevm v0.1.0)

Copy Markdown View Source

Runtime configuration for EEVM execution: the hardfork whose rules apply, the chain id, any custom precompiles, and the simulation switches.

Every entry point takes a config as its :config option, or the shorthand :hardfork (a fork atom) for a mainnet config of that fork.

FieldDescription
hardforkThe fork's rules; config.hardfork.spec_id is the fork atom, such as :prague. Ask enabled?/2 whether a rule applies
chain_idThe chain id, for EIP-155 signatures, EIP-7702 authorizations, and CHAINID
precompilesCustom precompiles by address, added with register_precompile/3
disable_nonce_checkSimulation only: accept any transaction nonce. The sender's nonce is still incremented
disable_balance_checkSimulation only: accept a sender that can't afford the gas and value
disable_base_feeSimulation only: accept a fee cap or gas price below the block's base fee
disable_block_gas_limitSimulation only: accept a transaction gas limit above the block's
disable_eip3607Simulation only: accept a sender that has code (EIP-3607)

Example

iex> config = EEVM.Config.new(:prague, chain_id: 11_155_111)
iex> config.chain_id
11155111
iex> EEVM.Config.enabled?(config, :eip_7702)
true
iex> EEVM.Config.enabled?(config, :eip_7939)
false

Simulation switches

The disable_* fields relax EEVM.transact/4's validity rules for tooling that simulates transactions, such as eth_call-style RPC, gas estimation, and fork tests. They mirror revm's CfgEnv switches of the same names, and all default to false. They are for simulation and must never be set when validating or building real blocks: with any of them on, eevm accepts transactions that no Ethereum node would.

  • disable_nonce_check skips the nonce comparison (and EIP-2681's limit), but still increments the sender's nonce, and a creation's address still comes from the account's nonce.
  • disable_balance_check skips the upfront balance check. The sender's balance is first raised to at least the transaction's value, then charged for gas as far as it can pay while keeping value. Unlike revm, eevm refunds unused gas, and pays the coinbase its tip, only out of what the sender actually paid, so gas settlement never mints ether and the sender never ends with more than it started with. (Raising the balance to value does create that ether, so the transfer can happen.)
  • disable_base_fee accepts a max_fee_per_gas (or legacy gas_price) below the block's base fee. The sender then pays its fee cap per gas, and the coinbase earns no tip.
  • disable_block_gas_limit lets a transaction's gas limit exceed the block's. The EIP-7825 cap from Osaka still applies.
  • disable_eip3607 lets a sender with code, such as a contract or a multisig, send a transaction.

Only single transactions run relaxed: EEVM.Block.validate/3, execute/4, and build/4 return {:error, :simulation_config} for a config with any switch set (see simulation?/1).

Together with an unsigned EEVM.TxEnv, which EEVM.transact/4 accepts in place of a signed transaction, they let a tool run a transaction from any address:

iex> config = EEVM.Config.new(:cancun, disable_nonce_check: true, disable_balance_check: true)
iex> tx = %EEVM.TxEnv{origin: 0xDEAD, nonce: 7, to: 0xB0B, value: 5, gas_limit: 21_000, gas_price: 1}
iex> {:ok, result} = EEVM.transact(tx, EEVM.BlockEnv.new(), EEVM.Database.InMemory.new(), config: config)
iex> {result.status, EEVM.Database.get_balance(result.db, 0xB0B), EEVM.Database.get_nonce(result.db, 0xDEAD)}
{:success, 5, 1}

Summary

Types

An option of new/2.

t()

Functions

Returns whether the rule behind eip_flag (such as :eip_1559 or :eip_7702) is active in config's hardfork.

Returns every supported hardfork, oldest first.

Creates a config for hardfork (default :cancun).

Registers module, which implements EEVM.Precompile, as a precompile at address. It replaces a built-in precompile at the same address.

Returns whether config sets any simulation switch (disable_*).

Types

option()

@type option() ::
  {:chain_id, non_neg_integer()}
  | {:disable_nonce_check, boolean()}
  | {:disable_balance_check, boolean()}
  | {:disable_base_fee, boolean()}
  | {:disable_block_gas_limit, boolean()}
  | {:disable_eip3607, boolean()}

An option of new/2.

t()

@type t() :: %EEVM.Config{
  chain_id: non_neg_integer(),
  disable_balance_check: boolean(),
  disable_base_fee: boolean(),
  disable_block_gas_limit: boolean(),
  disable_eip3607: boolean(),
  disable_nonce_check: boolean(),
  hardfork: EEVM.HardforkConfig.t(),
  precompiles: %{optional(non_neg_integer()) => module()}
}

Functions

enabled?(config, eip_flag)

@spec enabled?(t(), atom()) :: boolean()

Returns whether the rule behind eip_flag (such as :eip_1559 or :eip_7702) is active in config's hardfork.

Unknown flags are inactive.

Examples

iex> config = EEVM.Config.new(:prague)
iex> EEVM.Config.enabled?(config, :eip_7702)
true
iex> EEVM.Config.enabled?(config, :eip_7939)
false
iex> EEVM.Config.enabled?(config, :eip_9999)
false

hardforks()

@spec hardforks() :: [EEVM.HardforkConfig.spec_id()]

Returns every supported hardfork, oldest first.

Example

iex> EEVM.Config.hardforks() |> Enum.take(-3)
[:cancun, :prague, :osaka]

new(hardfork \\ :cancun, opts \\ [])

@spec new(EEVM.HardforkConfig.spec_id(), [option()]) :: t()

Creates a config for hardfork (default :cancun).

Options: :chain_id (default 1, mainnet), used for EIP-155 signatures, EIP-7702 authorizations, and the CHAINID opcode, and the simulation switches :disable_nonce_check, :disable_balance_check, :disable_base_fee, :disable_block_gas_limit, and :disable_eip3607 (each default false; see "Simulation switches" above, and never set them for consensus). Any other option raises ArgumentError.

Examples

iex> config = EEVM.Config.new()
iex> {config.hardfork.spec_id, config.chain_id, config.disable_nonce_check}
{:cancun, 1, false}

iex> config = EEVM.Config.new(:berlin, chain_id: 5, disable_eip3607: true)
iex> {config.hardfork.spec_id, config.chain_id, config.disable_eip3607}
{:berlin, 5, true}

register_precompile(config, address, module)

@spec register_precompile(t(), non_neg_integer(), module()) :: t()

Registers module, which implements EEVM.Precompile, as a precompile at address. It replaces a built-in precompile at the same address.

simulation?(config)

@spec simulation?(t()) :: boolean()

Returns whether config sets any simulation switch (disable_*).

Example

iex> EEVM.Config.simulation?(EEVM.Config.new(:cancun))
false
iex> EEVM.Config.simulation?(EEVM.Config.new(:cancun, disable_base_fee: true))
true