Часть II · Глава 5 из 43

Как узел синхронизируется

Вы устанавливаете новый клиент, а сеть работает уже годы. То, как узел наверстывает упущенное — и пять способов, которыми он мог бы это делать — это аккуратная маленькая деривация: начинаем с самого медленного и параноидального метода, а затем по делу зарабатываем каждое сокращение.

Обновлено 13 сент. 2026 г. · 14 мин
Предполагается
  • как Ethereum хранит состояние
  • финальность

Вы устанавливаете новый узел и нажимаете «Запустить». Сеть работает уже годы; там сотни миллионов аккаунтов и цепочка блоков, уходящая назад до genesis. Ваш узел не знает ничего из этого. Прежде чем он сможет валидировать хотя бы один новый блок или ответить на вопрос «какой баланс у Алисы?», он должен наверстать упущенное — достичь точно того же текущего состояния, что и все остальные, и убедиться самостоятельно, что это состояние верно.

Это можно сделать не одним способом. Их пять, и они не произвольны: каждый — исправление конкретного недостатка предыдущего. Начнём с самого медленного и параноидального метода из возможных, а затем по делу заработаем каждое сокращение. (Это напрямую опирается на trie, которое хранит состояние, и финальность — если они туманны, сначала пробегитесь по ним.)

1 шаг Что должна делать синхронизация

Две вещи и противоречие между ними

«Быть синхронизированным» означает, что ваш узел хранит две вещи: текущее состояние — каждый аккаунт и контракт, то самое, что зафиксировано в stateRoot 32-байтовый корень дерева Меркла-Патриции, который является отпечатком всего мирового состояния. Он есть в каждом заголовке блока; два узла с одинаковым stateRoot хранят идентичное состояние. последнего блока — и достаточно цепочки, чтобы продолжать валидировать новые блоки по мере их поступления.

Вся тема — это одно противоречие. Можно пересчитать всё самостоятельно с самого начала и никому не доверять — медленно, но пуленепробиваемо. Или можно скачать готовое состояние от пира и доверять его правильности — быстро, но легковерно. Каждый режим синхронизации — это разная точка на шкале между доверием и скоростью (и третья ось: сколько диска вы готовы сжечь). Посмотрите, где оказывается каждый.

→ Шаг 2: никому не доверяем. Повторяем всю историю.

2 шаг Полная синхронизация

Повторяем каждый блок начиная с genesis

Дизайн с нулевым доверием: скачиваем каждый блок от genesis до головы и повторно выполняем каждую транзакцию по порядку, применяя каждую к нашей локальной копии состояния — точно так же, как это делали исходные валидаторы. После последнего блока вычисленный нами stateRoot совпадёт с stateRoot блока на голове, и мы будем знать это, потому что прошли каждый шаг сами. Это полная синхронизация (full sync) — точка отсчёта, с которой сравнивают все остальные методы.

генезис голова #1 #2 #3 #4 #5 #6 #7 #8 переисполнение восстановлено 46% переисполняем каждую транзакцию, блок за блоком верно, но медленно: дни работы CPU
Полная синхронизация повторно выполняет каждую транзакцию начиная с genesis, восстанавливая состояние с нуля. Максимально без доверия — и жестоко медленно.

Ничто не заслуживает большего доверия: вы лично верифицировали каждый переход состояния в истории Ethereum. (Если сохранить все промежуточные состояния, получим архивный узел — то, что запускают блок-эксплореры: несколько терабайт на современной path-based раскладке, до ~15–20 ТБ на старой hash-based.)

→ Шаг 3: прекращаем повторную обработку. Просто скачиваем состояние.

3 шаг Быстрая синхронизация

Скачиваем trie вместо того, чтобы его восстанавливать

Вот прыжок. Состояние — это дерево Меркла (Merkle trie), а дерево Меркла самоверифицируется: каждый узел ссылается на дочерние по их хешу, поэтому если скачанный узел хешируется в значение, которое ожидал родитель, — он не может быть поддельным. Выбираем недавний блок pivot, временно принимаем его stateRoot на веру и скачиваем лежащее под ним дерево напрямую от пиров — сначала корень, потом каждый дочерний по его хешу, проверяя каждый узел по мере поступления. Никакого повторного выполнения. Это была быстрая синхронизация (fast sync).

корень узел узел узел листлистлистлистлист качаем trie узел за узлом, каждый сверяем по хешу миллионы мелких запросов; pivot всё время движется
Быстрая синхронизация скачивает trie состояния узел за узлом, проверяя каждый по хешу родителя — без повтора транзакций. Но в trie сотни миллионов разбросанных узлов.

Вы верифицируете только голову, следя за заголовками блоков и консенсусом, а математика Меркла подтверждает скачанное состояние. Дни сжимаются до часов.

→ Шаг 4: забываем о форме дерева. Скачиваем сырые данные оптом.

4 шаг Snap sync

Скачиваем плоские диапазоны, затем лечим

trie — это просто индекс над простыми парами key → value. Так что прекращаем запрашивать его узел за узлом. Вместо этого запрашиваем у пиров непрерывные диапазоны плоских данных аккаунтов — «все аккаунты от 0x00… до 0x20…» — отдаваемые прямо из плоского снимка (snapshot) большими последовательными кусками, каждый с доказательством диапазона (небольшое доказательство Меркла, подтверждающее, что кусок корректен и полон относительно stateRoot). Скачиваем всё состояние несколькими толстыми запросами диапазонов, локально восстанавливаем trie из плоских данных, а затем проходим один финальный heal-проход, чтобы залатать немногие узлы, сместившиеся во время скачивания. Это snap sync — сегодняшний стандарт в geth и reth.

плоское состояние, диапазоны 0x00…0f 0x10…1f 0x20…2f 0x30…3f перестройка перестроено локально корень a…f g…z залечено ✓ несколько больших диапазонов, а не миллион узлов: часы, не дни
Snap sync забирает состояние большими плоскими диапазонами (каждый с доказательством), локально восстанавливает trie и залечивает части, которые сдвинулись. Несколько крупных запросов вместо миллионов мелких.

Та же модель доверия, что у быстрой синхронизации — верифицируем голову, доверяем доказательствам для состояния — но полоса пропускания используется эффективно. Полный узел mainnet синхронизируется за несколько часов.

→ Шаг 5: вообще не храним состояние.

5 шаг Лёгкие клиенты

Храним только заголовки; запрашиваем остальное с доказательством

Отбрасываем состояние полностью. Заголовок блока крошечный — несколько сотен байт — и он несёт stateRoot. Храним только цепочку заголовков. Когда нам что-то нужно — баланс Алисы, слот хранилища — запрашиваем у полного узла вместе с доказательством Меркла: короткую цепочку хешей соседей от листа до stateRoot, который у нас уже есть. Проверяем доказательство сами по доверенному корню. Если сходится — ответ подлинный; полный узел не может солгать, не сломав хеш. Это лёгкий клиент (light client).

root #0root #1root #2root #3root #4root #5 баланс 0xA7? 3a… b1… acct ✓ 12 Ξ хранит только заголовки; спрашивает узел и проверяет Merkle-доказательство проверяет состояние сам, не храня его
Лёгкий клиент хранит только заголовки. Он запрашивает каждый фрагмент состояния по требованию с доказательством Меркла и проверяет его по stateRoot заголовка — доверенные ответы при почти нулевом хранилище.

Вы храните килобайты вместо сотен гигабайт, и каждый ответ по-прежнему криптографически верифицирован — вы обменяли хранение состояния на доказывание каждого фрагмента по требованию.

→ Шаг 6: начинаем с недавней точки, которой можно доверять.

6 шаг Checkpoint sync

Доверяем одному недавнему финализированному блоку и пропускаем остальное

Все методы выше тихо идут вперёд от genesis, доверяя самой тяжёлой цепочке. Но у Proof of Stake есть тонкость: узел, синхронизирующийся от genesis, может быть обманут давно мёртвыми валидаторами, подписывающими альтернативную древнюю историю (атака дальнего диапазона). Исправление одновременно является самым большим ускорением во всей теме. Не начинайте с genesis — начните с недавней финализированной контрольной точки (checkpoint): корня блока возрастом в несколько недель, взятого из доверенного источника (ваш клиент поставляется со списком; вы можете перепроверить по блок-эксплореру или у друга). Поскольку она финализирована, её откат сжёг бы треть всего застейканного ETH — так что это надёжный якорь. Отсюда выполняем snap sync состояния и идём вперёд. Это checkpoint sync (он же weak-subjectivity sync) — именно так реальные узлы и запускаются.

gen голова переигрывает всю историю с генезиса: недели вместо этого: контр. точкафинализир. голова доверенный свежий якорь → snap вперёд → минуты
Вместо повтора истории от genesis, checkpoint sync доверяет одному недавнему финализированному корню и делает snap вперёд оттуда — недели работы превращаются в минуты.

Это единственный режим, меняющий точку начала, а не метод загрузки, и он сочетается с остальными: современные клиенты объединяют слой консенсуса, синхронизированный через checkpoint, со слоем выполнения, синхронизированным через snap, — и узел, бывший офлайн месяцами, может снова выйти в сеть за минуты.

03 Спека и код Вся лестница с первого взгляда

Что вы обменяли — явно

МетодМодель доверияВремя синхронизацииДиск
Полная / архивнаяповторяет всю историю — не доверяет ничемудни–неделисотни ГБ – ТБ
Быстрая (устаревшая)верифицирует голову, доверяет Меркл для состояниячасы+~размер состояния
Snap (стандарт)верифицирует голову, доверяет доказательствам диапазоновнесколько часов~размер состояния
Лёгкий клиентцепочка заголовков + доказательство на каждый запроссекундыКБ–МБ
Checkpointдоверяет одному недавнему финализированному корнюминутыв паре со snap

Столбец, который важен — модель доверия: всё справа — это лишь цена, которую вы платите, а всё слева — то, что вы готовы принять на веру. Snap-от-checkpoint победил, потому что он жертвует почти ничем реальным — финализированный корень настолько же надёжен, насколько вообще что-то может быть надёжным — ради почти всей скорости.

04 Глубже Куда двигаться дальше