Storage trie — повторно используются ли узлы trie для двух экземпляров контракта с одним и тем же содержимым хранилища?

Читая код geth и различные сообщения здесь, я думаю, что теперь хорошо понимаю, как данные хранятся в Ethereum (пожалуйста, поправьте меня, если я ошибаюсь в какой-то момент).

На самом низком уровне у нас есть база данных ключ-значение

На следующем уровне у нас есть общая структура данных, называемая trie.

А на уровне блокчейна Ethereum у нас есть что-то вроде (названы только соответствующие части):

block -> state trie -> account* -> storage trie

[Q1] : Для проверки состояния пути представляют адреса учетных записей. Каковы пути в хранилище? Индексы хранения?

[Q2] : Если у нас есть простой контракт в форме:

contract C {
    uint256 public x = 100;
}

Когда мы создаем два экземпляра этого контракта. Будет ли у них одинаковый корневой хэш хранилища? Если да, будут ли они совместно использовать одну и ту же пару ключ/значение в базе данных (на самом низком уровне) и, соответственно, один и тот же узел дерева в дереве хранилища?

Ответы (2)

Для проверки состояния пути представляют адреса учетных записей. Каковы пути в хранилище? Индексы хранения?

Это правильно, за исключением того, что адреса и индексы хэшируются перед сохранением в дереве. Это сделано для защиты от DoS: почему ключи хешируются в Merkle Patricia Trie?

Когда мы создаем два экземпляра этого контракта. Будет ли у них одинаковый корневой хэш хранилища?

Да.

будут ли они совместно использовать одну и ту же пару ключ/значение в базе данных (на самом низком уровне), соответственно один и тот же узел дерева в дереве хранилища?

Да, поскольку корень trie одинаков для обоих контрактов, они совместно используют ключ/значение в базовой базе данных. Поначалу кажется нелогичным или небезопасным, что 2 контракта «разделяют одно и то же хранилище», однако, поскольку структура дерева неизменяема, всякий раз, когда в дерево добавляется новая запись, создается модифицированный экземпляр с собственным корнем. Старое немодифицированное дерево все еще существует в базовой базе данных, и другие контракты все еще могут указывать на него.

Вы можете попробовать создать 2 контракта с одним и тем же хранилищем, а затем прочитать их корни и содержимое хранилища, используя этот код nodejs https://ethereum.stackexchange.com/a/40280/18932 .

Спасибо за отличный ответ! Я спрашивал об этом, потому что я думаю, что было бы здорово иметь возможность создать новый контракт с содержанием старого контракта. Если я все правильно понимаю, на уровне evm это будет только вопрос установки того же корня хранилища для нового контракта, вместо того, чтобы начинать с пустого хранилища. Это было бы довольно круто с точки зрения возможности обновления контрактов. Я знаю, что мы можем использовать делегатский вызов для возможности обновления, но самый прямой способ, ИМХО, — это быстрое копирование хранилища.
Я думаю, что технически это возможно. Сложная часть будет заключаться в том, чтобы убедиться, что новые переменные контракта указывают на те же слоты, что и старые переменные контракта, например, если у вас было 2 поля в старом контракте, а затем добавьте еще 1 между этими 2 в новом контракте, слот сместится на 3-й поле. Может быть, это можно как-то решить в Solidity, введя аннотации.
Да, конечно... та же проблема, что и с делегатом.

Контракты на самом деле имеют корневой хэш хранилища и корневой хэш кода (который является не столько корневым хэшем, сколько обычным хэшем, поскольку код представляет собой один большой двоичный объект). Если два контракта имеют один и тот же код и, следовательно, один и тот же хэш кода, то большой двоичный объект, который соответствует этому хешу, должен быть сохранен в базе данных узлом только один раз, но я не могу сказать, действительно ли они это делают. который.

То же самое и с корневым хэшем состояния контракта, но, поскольку он может меняться от блока к блоку, в базе данных это может быть немного сложнее. Я предполагаю, что он не дублируется, поскольку БД в основном является хранилищем ключей и значений, но я не могу быть уверен.