EEVM.Database behaviour (eevm v0.1.0)

Copy Markdown View Source

Behaviour defining the external state interface for the EVM — account state (balances, nonces, code) plus per-contract storage — abstracted behind a single interface so different backends (in-memory, Merkle-backed, disk) can be plugged in without changing opcode implementations.

A database value is a %EEVM.Database{} struct containing:

  • impl — the module implementing @behaviour EEVM.Database
  • state — the implementation-specific state (opaque to callers)

All public functions in this module dispatch to the impl module, passing and receiving the opaque state. The default implementation is EEVM.Database.InMemory.

Summary

Callbacks

Return all known account addresses in the backend state.

Return whether account at address is EIP-161 empty.

Check whether an account exists at the given address.

Remove an account entirely (used by SELFDESTRUCT under EIP-6780).

Fetch the full account record, or nil if the address has no state.

Return the balance in wei for address (0 if non-existent).

Return the bytecode deployed at address (empty binary if none).

Return the nonce for address (0 if non-existent).

Increment the nonce at address by 1.

Replace the entire account record at address.

Set the bytecode at address.

Set the balance at address.

Set the nonce at address.

Return addresses that currently have tracked storage entries.

Load a 256-bit storage slot for the given contract address.

Return all storage slots currently tracked for an address.

Store a 256-bit value into a storage slot for the given contract address.

Transfer amount wei from one address to another.

Types

account()

@type account() :: %{
  optional(:balance) => non_neg_integer(),
  optional(:nonce) => non_neg_integer(),
  optional(:code) => binary(),
  optional(:storage) => EEVM.Storage.t()
}

t()

@type t() :: %EEVM.Database{impl: module(), state: term()}

Callbacks

account_addresses(state)

@callback account_addresses(state :: term()) :: [non_neg_integer()]

Return all known account addresses in the backend state.

account_empty?(state, address)

@callback account_empty?(state :: term(), address :: non_neg_integer()) :: boolean()

Return whether account at address is EIP-161 empty.

account_exists?(state, address)

@callback account_exists?(state :: term(), address :: non_neg_integer()) :: boolean()

Check whether an account exists at the given address.

delete_account(state, address)

@callback delete_account(state :: term(), address :: non_neg_integer()) :: term()

Remove an account entirely (used by SELFDESTRUCT under EIP-6780).

get_account(state, address)

@callback get_account(state :: term(), address :: non_neg_integer()) :: account() | nil

Fetch the full account record, or nil if the address has no state.

get_balance(state, address)

@callback get_balance(state :: term(), address :: non_neg_integer()) :: non_neg_integer()

Return the balance in wei for address (0 if non-existent).

get_code(state, address)

@callback get_code(state :: term(), address :: non_neg_integer()) :: binary()

Return the bytecode deployed at address (empty binary if none).

get_nonce(state, address)

@callback get_nonce(state :: term(), address :: non_neg_integer()) :: non_neg_integer()

Return the nonce for address (0 if non-existent).

increment_nonce(state, address)

@callback increment_nonce(state :: term(), address :: non_neg_integer()) :: term()

Increment the nonce at address by 1.

put_account(state, address, account)

@callback put_account(state :: term(), address :: non_neg_integer(), account :: account()) ::
  term()

Replace the entire account record at address.

put_code(state, address, code)

@callback put_code(state :: term(), address :: non_neg_integer(), code :: binary()) ::
  term()

Set the bytecode at address.

set_balance(state, address, balance)

@callback set_balance(
  state :: term(),
  address :: non_neg_integer(),
  balance :: non_neg_integer()
) :: term()

Set the balance at address.

set_nonce(state, address, nonce)

@callback set_nonce(
  state :: term(),
  address :: non_neg_integer(),
  nonce :: non_neg_integer()
) :: term()

Set the nonce at address.

storage_addresses(state)

@callback storage_addresses(state :: term()) :: [non_neg_integer()]

Return addresses that currently have tracked storage entries.

storage_load(state, address, key)

@callback storage_load(
  state :: term(),
  address :: non_neg_integer(),
  key :: non_neg_integer()
) :: non_neg_integer()

Load a 256-bit storage slot for the given contract address.

storage_slots(state, address)

@callback storage_slots(state :: term(), address :: non_neg_integer()) :: [
  {non_neg_integer(), non_neg_integer()}
]

Return all storage slots currently tracked for an address.

storage_store(state, address, key, value)

@callback storage_store(
  state :: term(),
  address :: non_neg_integer(),
  key :: non_neg_integer(),
  value :: non_neg_integer()
) :: term()

Store a 256-bit value into a storage slot for the given contract address.

transfer(state, from, to, amount)

@callback transfer(
  state :: term(),
  from :: non_neg_integer(),
  to :: non_neg_integer(),
  amount :: non_neg_integer()
) :: {:ok, term()} | {:error, :insufficient_balance}

Transfer amount wei from one address to another.

Functions

account_addresses(database)

@spec account_addresses(t()) :: [non_neg_integer()]

account_empty?(database, address)

@spec account_empty?(t(), non_neg_integer()) :: boolean()

account_exists?(database, address)

@spec account_exists?(t(), non_neg_integer()) :: boolean()

delete_account(db, address)

@spec delete_account(t(), non_neg_integer()) :: t()

get_account(database, address)

@spec get_account(t(), non_neg_integer()) :: account() | nil

get_balance(database, address)

@spec get_balance(t(), non_neg_integer()) :: non_neg_integer()

get_code(database, address)

@spec get_code(t(), non_neg_integer()) :: binary()

get_nonce(database, address)

@spec get_nonce(t(), non_neg_integer()) :: non_neg_integer()

increment_nonce(db, address)

@spec increment_nonce(t(), non_neg_integer()) :: t()

new(impl, state)

@spec new(module(), term()) :: t()

Wraps an implementation module and its initial state into a %Database{}.

Example

db = Database.new(Database.InMemory, Database.InMemory.init())

put_account(db, address, account)

@spec put_account(t(), non_neg_integer(), account()) :: t()

put_code(db, address, code)

@spec put_code(t(), non_neg_integer(), binary()) :: t()

set_balance(db, address, balance)

@spec set_balance(t(), non_neg_integer(), non_neg_integer()) :: t()

set_nonce(db, address, nonce)

@spec set_nonce(t(), non_neg_integer(), non_neg_integer()) :: t()

storage_addresses(database)

@spec storage_addresses(t()) :: [non_neg_integer()]

storage_load(database, address, key)

@spec storage_load(t(), non_neg_integer(), non_neg_integer()) :: non_neg_integer()

storage_slots(database, address)

@spec storage_slots(t(), non_neg_integer()) :: [
  {non_neg_integer(), non_neg_integer()}
]

storage_store(db, address, key, value)

@spec storage_store(t(), non_neg_integer(), non_neg_integer(), non_neg_integer()) ::
  t()

transfer(db, from, to, amount)

@spec transfer(t(), non_neg_integer(), non_neg_integer(), non_neg_integer()) ::
  {:ok, t()} | {:error, :insufficient_balance}