Запуск верификатора
Верификатор (verifier) — это read-only узел, который воспроизводит каждый блок, полученный от производителя, на собственной локальной копии состояния. Если корень состояния (state root) или хеш блока (block hash) не совпадают, блок отклоняется, и узел прекращает обслуживание запросов. Standalone verifier обслуживает read-only RPC. Кошельки отправляют подписанные транзакции через публичный write RPC POA; verifier mode не пересылает запись.
В этой статье рассматривается практическая сторона вопроса: конфигурация, процесс запуска, выполняемые проверки и поведение при сбоях. Криптографические детали state roots и block hash подробно описаны в разделе State roots.
Конфигурация
Заголовок раздела «Конфигурация»Для работы верификатора требуются два изменения в конфигурации по сравнению с производителем:
config :chain, mode: :verifier,Параметр mode: :verifier изменяет набор компонентов, которые запускаются при старте узла:
| Компонент | Производитель (Producer) | Верификатор (Verifier) |
|---|---|---|
| Инициализация генезиса | Да | Нет (получает от upstream) |
| Производитель блоков | Да | Нет |
| Пул транзакций | Да | Нет |
| Синхронизатор верификатора | Нет | Да |
| RPC (eth_, /wallet/) | Внутренний | Публичный |
| BlockFeed (история блоков) | Да | Да |
| BlockStage (live broadcast) | Да | Да |
Верификатору требуется собственная база данных. Общего хранилища с производителем не существует.
Порядок запуска
Заголовок раздела «Порядок запуска»При первом запуске с пустой базой данных процесс выглядит следующим образом:
- Синхронизатор (syncer) подключается к upstream-узлу через Erlang distribution.
- Он запрашивает у upstream-узла текущий указатель (tip), затем скачивает блоки пакетами, начиная со своего последнего известного блока, и проверяет каждый из них (выполняет catch-up).
- Как только синхронизация завершена, верификатор подписывается на live-поток блоков (block feed).
- Для каждого последующего live-блока верификатор воспроизводит все транзакции, пересчитывает state root и block hash, и фиксирует блок только при совпадении обоих значений.
- Блоки, которые уже были зафиксированы на этапе catch-up, пропускаются по номеру.
Если upstream-узел недоступен при запуске, синхронизатор повторяет попытку подключения каждые 5 секунд.
Что проверяет верификатор
Заголовок раздела «Что проверяет верификатор»Для каждого блока (включая генезис) верификатор независимо проверяет следующие параметры:
| Проверка | Что предотвращает |
|---|---|
| state_root | Производитель записал состояние, которое не соответствует результатам выполнения транзакций. Охватывает балансы, HTLC-свопы, регистрации precompile-контрактов и bridge_mints. |
| transactions_root | Производитель подменил, добавил или удалил транзакции из блока. |
| block_hash | Любое поле в заголовке блока было изменено после его формирования. |
| parent_hash | Блок некорректно ссылается на предыдущий. Это позволяет обнаруживать форки (разветвления цепи). |
| block_number | Наличие пропусков в последовательности (пропущенные блоки). |
| timestamp блока | Блок, помеченный временем раньше своего родителя. Timestamp-метки монотонны: производитель подтягивает их вперёд при обратном скачке часов, поэтому регрессия timestamp означает расходящийся или скомпрометированный upstream. |
| chain_id | Cross-chain replay (транзакция была подписана для другой сети). |
| Восстановление отправителя | Для Ethereum-транзакций адрес отправителя заново вычисляется из подписи. Для Tron-транзакций подпись перепроверяется на соответствие заявленному отправителю. |
| Инварианты генезиса | Timestamp и transactions root генезис-блока должны совпадать с каноническими константами. Это предотвращает подделку генезиса. |
| Cross-chain проверка моста | Каждая строка bridge_mints независимо проверяется по финализированному состоянию Ethereum через JSON-RPC. Для строк bridge_lock адрес receiverOn2D из Ethereum-события Locked сравнивается с получателем HTLC в 2D. Полный список проверок приведен в статье Мост. |
Расхождение в state_root, transactions_root или block_hash означает нарушение консенсуса. В этом случае верификатор останавливается и прекращает обслуживание запросов. Операционные ошибки (например, временная недоступность upstream-узла или пропуск блоков) инициируют повторный процесс catch-up.
Режим верификатора и RPC
Заголовок раздела «Режим верификатора и RPC»Верификатор отклоняет RPC-вызовы, которые пытаются изменить состояние:
eth_sendRawTransactionвозвращает код ошибки-32601./wallet/broadcasttransactionвозвращает Tron-ошибкуOTHER_ERROR(код 20).
Все read-only методы работают в штатном режиме: eth_getBalance, eth_getTransactionReceipt, eth_getBlockByNumber, /wallet/getaccount и другие. Кошельки и обозреватели блоков (explorers) могут подключаться к верификатору без каких-либо изменений.
Цепочки верификаторов
Заголовок раздела «Цепочки верификаторов»Каждый верификатор ретранслирует проверенные блоки через свой собственный block feed. Второй верификатор может подписаться на этот поток вместо потока производителя:
# Верификатор B подключается к Верификатору A, а не к производителюconfig :chain, mode: :verifier,Каждый верификатор воспроизводит каждый блок самостоятельно, независимо от источника его получения. Модель безопасности остается неизменной: сначала проверь, потом обслуживай.
Producer ──▶ Верификатор A ──▶ Верификатор C ▶ Верификатор B ──▶ Верификатор DСетевые требования
Заголовок раздела «Сетевые требования»Производитель и верификатор взаимодействуют через Erlang distribution. Используются два порта, оба должны быть защищены файрволом:
- EPMD (по умолчанию порт 4369): Erlang Port Mapper Daemon.
- Distribution port (настраивается через
inet_dist_listen_minиinet_dist_listen_maxвvm.argsили конфигурации ядра): канал передачи данных, защищенный шифрованием TLS. Переменная окруженияRELEASE_DISTRIBUTIONуправляет режимом дистрибуции (name/sname/none), а не портом.
Публичный edge направляет подписанные записи в producer write API. Standalone verifier обслуживает чтение; Erlang distribution и admin API остаются закрытыми. Настройте маршруты по роли ноды.
Сценарии отказов
Заголовок раздела «Сценарии отказов»| Сценарий | Поведение верификатора |
|---|---|
| Upstream недоступен при запуске | Повторная попытка catch-up каждые 5 секунд. |
| Upstream-узел отключился в процессе работы | Live-события прекращают поступать; reconnect и catch-up при восстановлении связи. |
| Пропуск блоков (gap) | Автоматический catch-up через BlockFeed upstream-узла. |
Расхождение state_root | Остановка. В логи записывается критическое предупреждение. RPC перестает отвечать. |
Расхождение block_hash | Остановка. В логи записывается критическое предупреждение. RPC перестает отвечать. |
| Отсутствие (nil) сырых данных транзакции в блоке | Транзакция записывается как неуспешная (status 0), без падения узла. |
Остановленный верификатор требует ручного вмешательства и анализа. Расхождение означает, что либо производитель скомпрометирован, либо в executor присутствует баг детерминизма. В обоих случаях необходимо участие инженера.