Состояние Ethereum: account-based модель, state root и Merkle Patricia Trie

Состояние Ethereum (Ethereum state) — это снимок всех аккаунтов и их хранилища в текущий момент: балансы, nonce, код смарт-контрактов и значения в их storage–слотах. Каждый новый блок обновляет это состояние, а в заголовок блока попадает один хеш — state root, который служит компактным «отпечатком» всей системы.

Ethereum использует account-based модель, Merkle Patricia Trie и дерево storage для каждого контракта. Всё это вместе делает состояние проверяемым и воспроизводимым для любого узла сети.

Состояние Ethereum: account-based модель, state root и Merkle Patricia Trie

Account-based модель: какие бывают аккаунты

В Ethereum есть два типа аккаунтов (см. Ethereum и EVM):

  • EOA (Externally Owned Account)

Обычный пользовательский аккаунт:

  1. управляется приватным ключом;
  2. не содержит кода;
  3. может отправлять транзакции и владеть ETH/токенами.
  • Контрактный аккаунт (contract account)

Адрес, за которым:

  1. закреплён байткод смарт-контракта;
  2. хранится собственное хранилище (storage);
  3. код выполняется при входящих вызовах.

Логически у любого аккаунта есть одно и то же базовое представление, включающее:

  • nonce — счётчик транзакций/созданных контрактов;
  • balance — баланс в wei;
  • storageRoot — корень дерева хранилища для контракта;
  • codeHash — хеш кода (пустой для EOA).

Что такое состояние Ethereum на уровне узла

Для полного узла состояние — это:

  • дерево аккаунтов (account trie), включающее все адреса и их данные;
  • для каждого контрактного аккаунта — собственное дерево хранилища (storage trie);
  • дополнительная информация, связанная с блоками и логами (но именно account trie определяет глобальное «state» сети).

После применения всех транзакций блока клиент:

  • выполняет код через EVM;
  • обновляет балансы, nonce, storage-слоты;
  • пересчитывает корень дерева аккаунтов;
  • записывает полученный state root в заголовок блока.

Этот хеш — единственный элемент в заголовке, который «подписывает» всё состояние сети на данный момент.

Merkle Patricia Trie для аккаунтов

Для компактного и проверяемого хранения состояния в Ethereum используется Merkle Patricia Trie (см. также Merkle Patricia Trie).

Идея:

  • все аккаунты (по адресам) организованы в дерево, ключом служит 20-байтовый адрес;
  • в узлах хранятся RLP-кодированные данные аккаунта (balance, nonce, storageRoot, codeHash);
  • на каждом уровне вычисляются хеши, пока сверху не получится один корень — state root.

Свойства Merkle Patricia Trie:

  • узел может доказать, что конкретный аккаунт с определёнными данными действительно входит в состояние, предъявив Merkle-доказательство;
  • лёгкие клиенты и сторонние сервисы могут проверять данные без хранения полного состояния, ориентируясь на state root из заголовков блоков.

Хранилище контрактов и storage-слоты

У каждого контрактного аккаунта есть отдельное дерево хранилища:

  • storage trie строится по тем же принципам Merkle Patricia Trie;
  • ключом выступает индекс слота (256-битное значение);
  • значение — данные слота (256-битное слово).

На уровне EVM storage — это отображение slot → 32 байта. То, как именно значения переменных попадают в слоты, определяется компилятором языка (см. Storage layout в Solidity и шпаргалка по storage layout).

Для смарт-контрактов это означает:

  • каждая запись sstore(slot, value) меняет локальное дерево storage;
  • хеш корня этого дерева (storageRoot) хранится в аккаунте контракта;
  • при изменении хотя бы одного слота меняется и storageRoot, а затем и общий state root.

State root в заголовке блока

В заголовке каждого блока есть поле stateRoot:

  • это Merkle-корень дерева аккаунтов после применения всех транзакций блока;
  • любой узел, имея:
    1. предыдущее состояние,
    2. список транзакций,
    3. правила EVM,

может вычислить новое состояние и убедиться, что его корень совпадает с заявленным stateRoot.

Зачем это нужно:

  • детерминируемость — все честные узлы приходят к одному и тому же state root при одинаковых входных данных;
  • проверяемость — можно строить Merkle-доказательства существования аккаунта или значения в storage без полного состояния;
  • базис для L2 и мостов — rollup’ы и кросс-чейн протоколы часто ссылаются на state root (или его аналог) как на источник истины (см. обзор L2-роллапов и решения data availability).

Как транзакции изменяют состояние

Каждая транзакция в Ethereum:

  • считывает текущее состояние:
    1. баланс отправителя;
    2. код и storage целевых контрактов;
  • выполняется в EVM:
    1. обновляются балансы (переводы, комиссии);
    2. изменяются storage-слоты смарт-контрактов;
    3. пишутся события (events) в лог;
  • в конце узел фиксирует новое состояние и пересчитывает state root.

Если транзакция невалидна (out-of-gas, revert), состояние откатывается к прежнему состоянию, и state root не меняется.

Роль состояния для L2, клиентов и аналитики

Понимание структуры состояния важно не только для валидаторов:

  • Лёгкие клиенты

Могут синхронизироваться по заголовкам и получать доказательства по отдельным аккаунтам, не храня весь state.

  • L2-решения и мосты

При дизайне rollup’ов, мостов и протоколов с cross-chain логикой нужно учитывать:

  1. модель состояния на L1;
  2. способы получения и проверки state root и отдельных веток Merkle-дерева.
  • Аналитика и индексаторы

Сервисы типа block-explorer’ов и аналитических панелей читают состояние напрямую из storage-слотов и деревьев, строя свои индексы поверх Merkle-структур.

  • Account abstraction и кошельки нового поколения

Новые модели аккаунтов (см. account abstraction) по-прежнему строятся на той же базе — состояние сети описывается набором аккаунтов и их storage.

См. также

Task Runner