Skip to main content
Зафиксированное состояние должно удовлетворять двум требованиям, которые тянут в разные стороны. Исполнению нужно текущее значение ключа — быстро и миллионы раз. Проверке нужно доказательство того, что на конкретной версии значение было именно таким, как утверждает сеть. Обслуживать оба требования из одной структуры — значит делать плохо и то и другое. Поэтому хранение разделяет задачу между отдельными хранилищами, каждое из которых заточено под свой шаблон доступа.

Три хранилища

Зафиксированный блок
Хранилище реестратранзакции · выходные данные · события · наборы записей · аккумуляторы · метаданные
Воспроизведение и аудит
Хранилище состояниятекущие и исторические значения, шестнадцать шардов, горячее — в своём ярусе
Запросы и исполнение
Хранилище Мерклаверсионированное разреженное дерево Меркла и индексы вытесненных узлов
Проверка — доказательства
Чтение, которому нужно только значение, не платит за обход дерева, а доказательство не собирается заново из хранилища для точечных выборок.
Хранилище реестра держит историю блокчейна: транзакции, их выходные данные и вспомогательные данные, события, наборы записей, метаданные блоков и аккумуляторы. Именно это вы воспроизводите. Хранилище состояния держит значения состояния, адресуемые по ключу и версии. Именно его читают исполнение и запросы. Оно разбито на шестнадцать шардов, поэтому записи одного блока расходятся по шестнадцати независимым экземплярам RocksDB, а не конкурируют за один. Часто используемое состояние дополнительно держится в собственном ярусе, чтобы рабочий набор активного рынка не приходилось искать среди всего, что блокчейн когда-либо сохранил. Хранилище Меркла держит аутентифицирующую структуру: узлы дерева, позволяющие доказать значение, и индексы, отслеживающие, какие узлы были вытеснены. Разделение означает, что чтение, которому нужно только значение, не платит за обход дерева, а доказательство не приходится собирать заново из хранилища, оптимизированного под точечные выборки.

Аутентификация

Две структуры Меркла делают разную работу.
Версионированное разреженное дерево Меркла
Аккумуляторы
Ваш ключ и его значение
хеш-сосед
хеш-сосед
Корень состояния — фиксирует консенсус
Ваша транзакция или событие
Аккумулятор транзакций · аккумулятор событийкаждый фиксирует всё включённое до сих пор, по порядку
Корень реестра — фиксирует консенсус
Дерево доказывает, каким было значение; аккумуляторы — что произошло и в каком порядке. Вместе они позволяют доказать «эта транзакция есть в блокчейне на этой позиции», не имея самого блокчейна.
Версионированное разреженное дерево Меркла аутентифицирует состояние. Позиция каждого ключа определяется его хешем, а каждая версия дерева переиспользует узлы, которые не изменились, — поэтому запись одного ключа в блоке добавляет путь, а не дерево. Доказательство для ключа на конкретной версии — это путь от листа этого ключа до корня, зафиксированного сетью. Аккумуляторы аутентифицируют последовательность. Один накапливает транзакции, другой — события, и каждый выдаёт корень, который фиксирует всё включённое до этого момента, и притом в порядке включения. Именно это позволяет доказать утверждение «эта транзакция находится в блокчейне на этой позиции», не имея самого блокчейна. Вместе: дерево состояния доказывает, каким было значение, аккумуляторы — что произошло и в каком порядке.

Спекулятивное состояние

Результаты блока существуют до того, как их зафиксировали. Незафиксированное состояние не пишут в долговечное дерево с откатом на случай, если блок не зафиксируется, — его держат в разреженном наложении Меркла в памяти поверх последней зафиксированной версии. Исполнение читает сквозь это наложение и видит согласованную картину. Если блок фиксируется, наложение материализуется. Если нет — наложение выбрасывается, и ничего долговечного никто не трогал. Именно это не даёт спекулятивному исполнению оставлять мусор в хранилище.

Кеширование

Узлы дерева кешируются на двух уровнях: кеш, который знает о версиях и держит недавние версии адресуемыми, и под ним — кеш, вытесняющий давно не использованное. Шаблон доступа торгового блокчейна — небольшой набор горячих ключей, затрагиваемых каждый блок, против длинного хвоста, затрагиваемого редко, — ровно то, подо что эти кеши сделаны.

Обрезка истории

Хранить каждую версию вечно — это выбор, а не требование. По трём хранилищам работают три независимых обрезчика, у каждого своя политика хранения: один по реестру, один по значениям состояния, один по узлам Меркла. Обрезчики Меркла и значений состояния управляются индексами устаревания, которые пишутся одновременно с самими данными. Когда версия вытесняет узел или значение, вытесненная запись отмечается устаревшей на этой версии. Тогда обрезка — это сканирование диапазона по индексу, а не поиск мусора: что и когда станет пригодным к удалению, отмечено уже в момент записи.
Глубина хранения — решение оператора с реальными последствиями. Агрессивно обрезанный узел эффективно отдаёт текущее состояние, но не может ни отвечать на исторические запросы, ни обслуживать синхронизацию состояния для узла, который стартует с более ранней точки. Архивный узел хранит всё и платит за это. См. Запуск узла.

Резервное копирование и восстановление

Хранилища можно резервировать и восстанавливать независимо от работающего узла. Именно поэтому узел можно поднять из снимка, а не воспроизводить с генезиса, и сверить состояние восстановленного узла с зафиксированными корнями, а не доверять резервной копии.

Что дальше

Синхронизация состояния

Как узел догоняет блокчейн, не воспроизводя его целиком.

Модель состояния

Что именно хранится и какое представление — источник истины.

Индексатор

Восстановление истории по зафиксированным записям.

Запуск узла

Роли узлов и как запросить возможность управлять узлом.