# `EEVM.Database`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/database.ex#L1)

World state: a read-only backend plus eevm's own write overlay.

It inspects as its backend and a count of pending writes, such as
`#EEVM.Database<EEVM.Database.InMemory, pending writes to 2 accounts and 1 storage slot>`;
read state with this module's functions, list the writes with
`changes/1`, or pass `structs: false` to `inspect/2` to see every field.

A backend implements this behaviour's read callbacks, `c:account/2`,
`c:code/2`, `c:storage/3`, and `c:block_hash/2`. eevm never writes to it
during execution: every balance, nonce, code, and storage write lands in
the overlay this struct carries. Because a `%EEVM.Database{}` is an
immutable value, reverting a call frame is just dropping its copy.

When a transaction or block finishes, `changes/1` returns the overlay as an
`EEVM.StateChanges`. `EEVM.transact/4` and `EEVM.Block.execute/4` hand it
to the backend's `c:commit/2` and return the committed database. When
`commit/2` returns `{:error, :unsupported}`, the result keeps the overlay
and the caller applies `result.changes` itself. `EEVM.run/2` never commits.

`EEVM.StateRoot` also needs to enumerate the backend, through
`c:accounts/1` and `c:storage_slots/2`. A backend that can't, such as one
over JSON-RPC, returns `{:error, :unsupported}` from them and still
executes transactions; the EIP-7610 check that a CREATE target has no
storage then sees only the overlay.

Every callback is required, so what a backend can do is stated in its
code: eevm never asks the code server which functions a module exports.
`use EEVM.Database` declares the behaviour and defines `c:commit/2`,
`c:accounts/1`, and `c:storage_slots/2` to return `{:error, :unsupported}`
until the module overrides them, so a read-only backend implements only
the four reads.

`EEVM.Database.InMemory` implements every callback. This read-only
backend serves a fixed map of accounts, so a call's writes stay in the
overlay and `commit/1` reports that the backend can't commit:

    iex> defmodule MyApp.FixedDatabase do
    ...>   use EEVM.Database
    ...>   @impl true
    ...>   def account(accounts, address), do: {:ok, Map.get(accounts, address)}
    ...>   @impl true
    ...>   def code(_accounts, _code_hash), do: {:ok, <<>>}
    ...>   @impl true
    ...>   def storage(_accounts, _address, _slot), do: {:ok, 0}
    ...>   @impl true
    ...>   def block_hash(_accounts, _number), do: {:ok, nil}
    ...> end
    iex> db = EEVM.Database.new(MyApp.FixedDatabase, %{0xA11CE => %{balance: 100, nonce: 0, code: <<>>}})
    iex> {:ok, result} = EEVM.call(db, 0xB0B, <<>>, caller: 0xA11CE, value: 40)
    iex> {EEVM.Database.get_balance(result.db, 0xA11CE), EEVM.Database.get_balance(result.db, 0xB0B)}
    {60, 40}
    iex> EEVM.Database.commit(result.db)
    {:error, :commit_not_supported}

## Read errors

A callback that returns `{:error, reason}` aborts execution: the entry
point (`EEVM.run/2`, `EEVM.transact/4`, `EEVM.Block.execute/4`, or
`EEVM.Block.build/4`) returns `{:error, {:database, reason}}`. Called
directly, the functions in this module raise `EEVM.Database.ReadError`.

## Deprecated backends

These still work for one minor version:

- A backend that leaves out `c:commit/2`, `c:accounts/1`, or
  `c:storage_slots/2` (optional before #204) is treated as returning
  `{:error, :unsupported}`, and a bare enumerable from `c:accounts/1` or
  `c:storage_slots/2` is accepted.
- A `c:commit/2`, `c:accounts/1`, or `c:storage_slots/2` that returns
  `{:error, :not_supported}`, the atom earlier docs used, is treated as
  returning `{:error, :unsupported}`.
- A module that implements only the pre-1.0 write and query callbacks
  (`get_account/2`, `set_balance/3`, `storage_store/4`, and so on) is
  wrapped in `EEVM.Database.Legacy` by `new/2`.

# `account`

```elixir
@type account() :: %{
  optional(:balance) =&gt; non_neg_integer(),
  optional(:nonce) =&gt; non_neg_integer(),
  optional(:code) =&gt; binary()
}
```

An account record: balance, nonce, and code.

# `address`

```elixir
@type address() :: non_neg_integer()
```

An address: a 160-bit integer.

# `backend_account`

```elixir
@type backend_account() :: %{
  :balance =&gt; non_neg_integer(),
  :nonce =&gt; non_neg_integer(),
  optional(:code_hash) =&gt; &lt;&lt;_::256&gt;&gt;,
  optional(:code) =&gt; binary()
}
```

An account as a backend returns it. `code` may be included to save a
`c:code/2` call; when it is, `code_hash` may be left out.

# `t`

```elixir
@type t() :: %EEVM.Database{
  accounts: %{required(address()) =&gt; overlay_account() | nil},
  destroyed: MapSet.t(address()),
  impl: module(),
  state: term(),
  storage: %{
    required(address()) =&gt; %{required(non_neg_integer()) =&gt; non_neg_integer()}
  },
  tries: EEVM.StateRoot.tries() | nil
}
```

# `account`

```elixir
@callback account(state :: term(), address()) ::
  {:ok, backend_account() | nil} | {:error, term()}
```

Returns the account at `address`, or `nil` when it doesn't exist.

# `accounts`

```elixir
@callback accounts(state :: term()) ::
  {:ok, Enumerable.t()} | {:error, :unsupported | term()}
```

Enumerates every address with an account or storage, or returns
`{:error, :unsupported}`. Only state roots need it.

# `block_hash`

```elixir
@callback block_hash(state :: term(), number :: non_neg_integer()) ::
  {:ok, &lt;&lt;_::256&gt;&gt; | nil} | {:error, term()}
```

Returns the hash of block `number`, or `nil` when unknown. BLOCKHASH asks
only for blocks the `EEVM.BlockEnv` doesn't already carry.

# `code`

```elixir
@callback code(state :: term(), code_hash :: &lt;&lt;_::256&gt;&gt;) ::
  {:ok, binary()} | {:error, term()}
```

Returns the code whose keccak256 hash is `code_hash`.

# `commit`

```elixir
@callback commit(state :: term(), EEVM.StateChanges.t()) ::
  {:ok, term()} | {:error, :unsupported | term()}
```

Applies a finished set of changes and returns the new backend state.
A read-only backend returns `{:error, :unsupported}`.

# `storage`

```elixir
@callback storage(state :: term(), address(), slot :: non_neg_integer()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Returns the storage word at `slot` of `address` (0 when unset).

# `storage_slots`

```elixir
@callback storage_slots(state :: term(), address()) ::
  {:ok, Enumerable.t()} | {:error, :unsupported | term()}
```

Enumerates `{slot, value}` for every set slot of `address`, or returns
`{:error, :unsupported}`. Only state roots and the EIP-7610 CREATE check need it.

# `__using__`
*macro* 

Declares the `EEVM.Database` behaviour and defines `c:commit/2`,
`c:accounts/1`, and `c:storage_slots/2` to return `{:error, :unsupported}`.

A module that `use`s it implements only the read callbacks, `c:account/2`,
`c:code/2`, `c:storage/3`, and `c:block_hash/2`, and overrides a default
by defining the callback itself:

    defmodule MyApp.RpcDatabase do
      use EEVM.Database

      @impl true
      def account(state, address), do: ...
      # code/2, storage/3, and block_hash/2 likewise; no commit/2,
      # accounts/1, or storage_slots/2.
    end

The defaults are ordinary compiled functions, so the module still states
what it supports in code. `@behaviour EEVM.Database` with all seven
callbacks keeps working unchanged. The `EEVM.Database` module docs run a
complete read-only adapter.

# `account_addresses`

```elixir
@spec account_addresses(t()) :: [address()]
```

Returns every address with an account or storage, overlay included.
Needs the backend's `c:accounts/1`.

# `account_empty?`

```elixir
@spec account_empty?(t(), address()) :: boolean()
```

Returns whether `address` is empty: zero balance and nonce, and no code (EIP-161).

# `account_exists?`

```elixir
@spec account_exists?(t(), address()) :: boolean()
```

Returns whether an account exists at `address`.

# `block_hash`

```elixir
@spec block_hash(t(), non_neg_integer()) :: &lt;&lt;_::256&gt;&gt; | nil
```

Returns the hash of block `number` from the backend, or `nil` when unknown.

# `changes`

```elixir
@spec changes(t()) :: EEVM.StateChanges.t()
```

Returns the overlay's writes as an `EEVM.StateChanges`.

## Example

    iex> db = EEVM.Database.InMemory.new() |> EEVM.Database.set_balance(1, 5)
    iex> %{1 => change} = EEVM.Database.changes(db).accounts
    iex> {change.balance, change.nonce, change.destroyed?}
    {5, 0, false}

# `commit`

```elixir
@spec commit(t()) :: {:ok, t()} | {:error, term()}
```

Commits the overlay to the backend with its `c:commit/2` and returns the
database with an empty overlay. Returns `{:error, :commit_not_supported}`
when the backend's `commit/2` returns `{:error, :unsupported}`.

# `delete_account`

```elixir
@spec delete_account(t(), address()) :: t()
```

Deletes the account at `address` and all its storage.

# `get_account`

```elixir
@spec get_account(t(), address()) :: account() | nil
```

Returns `%{balance, nonce, code}` for `address`, or `nil` if it has no account.

# `get_balance`

```elixir
@spec get_balance(t(), address()) :: non_neg_integer()
```

Returns the balance of `address` in wei (0 if it has no account).

# `get_code`

```elixir
@spec get_code(t(), address()) :: binary()
```

Returns the code at `address`, or `<<>>`.

# `get_code_hash`

```elixir
@spec get_code_hash(t(), address()) :: &lt;&lt;_::256&gt;&gt; | nil
```

Returns the keccak256 hash of the code at `address`; `nil` if it has no account.

# `get_nonce`

```elixir
@spec get_nonce(t(), address()) :: non_neg_integer()
```

Returns the nonce of `address` (0 if it has no account).

# `increment_nonce`

```elixir
@spec increment_nonce(t(), address()) :: t()
```

Increments the nonce of `address`.

# `new`

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

Wraps a backend module and its state, with an empty overlay.

A module that implements only the deprecated pre-1.0 callbacks is wrapped
in `EEVM.Database.Legacy`.

## Example

    iex> db = EEVM.Database.new(EEVM.Database.InMemory, EEVM.Database.InMemory.init())
    iex> EEVM.Database.get_balance(db, 0x1234)
    0

# `put_account`

```elixir
@spec put_account(t(), address(), account()) :: t()
```

Replaces the account record at `address`; missing fields default to zero and no code.

# `put_code`

```elixir
@spec put_code(t(), address(), binary()) :: t()
```

Sets the code at `address`.

# `set_balance`

```elixir
@spec set_balance(t(), address(), non_neg_integer()) :: t()
```

Sets the balance of `address`.

# `set_nonce`

```elixir
@spec set_nonce(t(), address(), non_neg_integer()) :: t()
```

Sets the nonce of `address`.

# `storage_addresses`

> This function is deprecated. Use EEVM.Database.account_addresses/1.

```elixir
@spec storage_addresses(t()) :: [address()]
```

Returns the addresses with storage. Deprecated: use `account_addresses/1`.

# `storage_load`

```elixir
@spec storage_load(t(), address(), non_neg_integer()) :: non_neg_integer()
```

Returns the storage word at `key` of `address` (0 when unset).

# `storage_slots`

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

Returns `{slot, value}` for every set storage slot of `address`, overlay
included. Needs the backend's `c:storage_slots/2`.

# `storage_store`

```elixir
@spec storage_store(t(), address(), non_neg_integer(), non_neg_integer()) :: t()
```

Stores a 256-bit word at `key` of `address`.

# `transfer`

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

Moves `amount` wei from `from` to `to`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
