Коллатор

Коллация

Карта раздела Collator — место коллатора в узле, вход и выход коллации, четыре меры времени и как части раздела опираются друг на друга

Коллатор — компонент узла-валидатора, который производит блоки. Он берёт согласованный вход из DAG-мемпула и сообщения, накопленные во внутренней очереди, исполняет их и собирает из результатов блок.

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

Место коллатора в узле

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

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

Собранный блок коллация тоже не сохраняет сама: адаптер состояния узла кладёт его в карту «шард → номер → блок» и рассылает уведомление. Модуль продвижения по блокам забирает блок оттуда, прогоняет по цепочке своих подписчиков и сохраняет его данные в хранилище блоков.

На этом пути, от входа коллации до сохранённого блока, у неё получается ровно две внешние границы: DAG-мемпул как источник согласованного входа и модуль продвижения по блокам как получатель готового результата. Между ними работают сама коллация и её верификация. Границы домена с хранилищем, сетью и исполнителем транзакций разобраны выше.

Входы и выходы коллации

На входе у коллации три класса данных:

  • внешние сообщения, которые адаптер мемпула вычитывает из закоммиченной истории точек DAG-мемпула, дедуплицирует и упаковывает в якоря (статья «Обратная связь с мемпулом»);
  • внутренние сообщения, накопленные во внутренней очереди с прошлых блоков и разложенные по партициям (статья «Внутренняя очередь сообщений»);
  • предыдущее состояние шарда и данные мастерчейна, которые коллатор получает через адаптер состояния узла (статья «Синхронизация коллации»).

Чтение сообщений набирает из этого входа группы для параллельного исполнения (статья «Чтение сообщений»), а конвейер сборки блока исполняет их и финализирует в кандидат блока (статьи «Сборка блока», «Финализация блока»).

На выходе — кандидат блока, который уходит менеджеру коллации. Дальше события расходятся: блок шарда сразу участвует в выборе следующего шага коллации, а мастер-блок, если он ещё не пришёл из сети, сначала проходит верификацию: сбор подписей подмножества валидаторов мастерчейна (статья «Верификация мастер-блока»).

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

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

Детерминизм

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

Группировка сообщений для параллельного исполнения устроена так, чтобы решение не зависело от того, что конкретный узел успел прочитать из сети: перевод перегруженного аккаунта в низкоприоритетную партицию опирается только на накопленную статистику и данные, зафиксированные в мастер-блоке, а не на локальное состояние узла (статья «Чтение сообщений»). Случайное зерно блока — хеш от шарда, номера блока и времени цепочки, поэтому у любого узла с тем же входом получится то же самое зерно (статья «Сборка блока»). Решение о том, когда импортировать следующий якорь, коллатор шарда тоже принимает не по системным часам, а по детерминированной мере объёма уже проделанной работы (статья «Единицы работы»).

Верификация опирается на тот же принцип с другой стороны: подпись валидатора удостоверяет конкретную битовую сборку блока по его хешам, поэтому кандидат, разошедшийся с версией подмножества валидаторов мастерчейна, просто не наберёт для себя порог суммарного веса (статья «Верификация мастер-блока»). Так расхождение в детерминированной сборке блока обнаруживается уже на этом шаге.

Меры времени в коллации

Детерминизм запрещает коллации принимать решения по системным часам: два узла с одинаковым входом, но разной скоростью, за одно и то же время сделают разный объём работы. Вместо одной меры времени коллация использует четыре, и у каждой своя роль.

Время цепочки — согласованное время, которое несёт каждый якорь DAG-мемпула. Оно продвигается только вместе с новыми якорями, а не непрерывно, и именно от него отсчитываются интервалы выпуска мастер-блока, срок жизни внешних сообщений и время самого блока (статьи «Менеджер коллации», «Чтение сообщений», «Сборка блока»).

Единицы работы — детерминированная мера уже проделанной работы: коллатор считает её по счётчикам блока (число сообщений, аккаунтов, израсходованный газ), а не по длительностям, и накапливает между импортированными якорями. Раз время цепочки продвигается только вместе с якорями, а спрашивать якорь у мемпула по правилу «прошло N миллисекунд» нельзя, накопленные единицы работы и служат коллатору внутренними часами: по достижении порога он идёт за следующим якорем (статья «Единицы работы»).

Логическое время устроено мельче: оно упорядочивает сообщения и транзакции внутри одного блока и между блоками — растёт монотонно на каждом аккаунте и никогда не используется на нём повторно (статья «Сборка блока»).

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

Цена единицы работы в этот список не входит: она, как и почти все остальные времена в модели единиц работы, считается по монотонному таймеру, а не по системным часам. Единственное исключение внутри этой модели — лаг импорта якоря: разность между локальными часами узла в момент запроса якоря и временем цепочки самого якоря. Это единственное место модели единиц работы, где вообще сравниваются локальные часы и время цепочки, и оно осознанно вынесено в диагностику, а не в протокольное решение (статья «Единицы работы»).

Части раздела

Каждая из этих тем становится отдельной статьёй раздела.

  • Менеджер коллации оркестрирует выпуск блоков по событиям от коллаторов, сети и верификации, ведёт кэш блоков-кандидатов и коммитит подтверждённый мастер-блок. Сюда же входит синхронизация узла на уже применённый сетью мастер-блок при отставании (статьи «Менеджер коллации» и «Синхронизация коллации»).
  • Жизненный цикл коллатора — исполнитель одной попытки коллации: рабочее состояние между блоками, кэш якорей мемпула, решение «собирать блок сейчас или сначала импортировать якорь», отмена и прерывание (статья «Жизненный цикл коллатора»).
  • Внутренняя очередь сообщений хранит и коммитит сообщения, порождённые исполнением контрактов, вместе с собственной базой данных (статья «Внутренняя очередь сообщений»).
  • Чтение сообщений набирает из входа группы для параллельного исполнения, помнит место чтения между блоками и переводит перегруженные аккаунты в низкоприоритетную партицию (статья «Чтение сообщений»).
  • Конвейер сборки блока — три фазы, подготовка, исполнение и финализация: исполнение сообщений и специальных транзакций, лимиты блока, меркл-обновление состояния и расписание смены набора валидаторов для ключевых блоков (статьи «Сборка блока» и «Финализация блока»).
  • Единицы работы — детерминированная модель объёма работы коллатора по стадиям, служащая внутренними часами для импорта якорей и основой для последующей подстройки параметров расчёта (статья «Единицы работы»).
  • Обратная связь с мемпулом — единственная точка соприкосновения коллации с DAG-мемпулом: чтение якорей и дедупликация внешних сообщений, уведомления мемпулу о состоянии мастерчейна и о подписанном мастер-блоке (статья «Обратная связь с мемпулом»).
  • Верификация мастер-блока собирает подписи подмножества валидаторов мастерчейна на локально построенный мастер-блок до достижения порога суммарного веса (статья «Верификация мастер-блока»).

Собственная база данных внутренней очереди отдельной статьи не получила: она разобрана внутри статьи «Внутренняя очередь сообщений» (см. буллет выше). Не получил своей статьи и адаптер состояния узла — граница коллации с CoreStorage и модулем продвижения по блокам: он разобран внутри статьи «Синхронизация коллации». Общие типы и конфигурация коллации (секция collator конфигурации узла, данные мастерчейна и кандидат блока как сквозные структуры) тоже остались без отдельной статьи: их поля описаны точечно там, где используются, например в таблицах параметров статей «Синхронизация коллации», «Сборка блока» и «Финализация блока». Все три части при этом входят в граф зависимостей ниже, а их содержание раскрыто в другом месте раздела.

Граф зависимостей

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

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

Остальные зависимости однонаправленные:

  • менеджер коллации опирается на коллатора, верификатора, адаптер состояния узла, адаптер мемпула, внутреннюю очередь и общие типы;
  • коллатор, помимо двух связей выше, опирается на единицы работы, адаптер мемпула, адаптер состояния узла, внутреннюю очередь и общие типы;
  • конвейер сборки блока, помимо связи с коллатором, опирается на чтение сообщений, единицы работы, внутреннюю очередь, общие типы, адаптер состояния узла и конфигурацию блокчейна из раздела Storage. На верификатора он опирается только в одном узком случае — для расписания смены набора валидаторов в ключевом блоке;
  • чтение сообщений, помимо связи с коллатором, опирается на внутреннюю очередь, адаптер мемпула и общие типы;
  • единицы работы опираются на общие типы и на конфигурацию блокчейна;
  • внутренняя очередь опирается на собственную базу данных и на общие типы;
  • база данных внутренней очереди — уже граница с разделом Storage: контекст хранилища, обвязка над RocksDB, интерфейсы сериализации ключей и устойчивые состояния (нужны для холодного импорта, статья «Внутренняя очередь сообщений»);
  • адаптер состояния узла — тоже граница с разделом Storage: он держит внутри CoreStorage и обращается к хранилищу блоков, хранилищу дескрипторов блоков, хранилищу состояний шардов и хранилищу состояния узла, а также опирается на общие типы;
  • адаптер мемпула зависит только от общих типов — сам он и есть граница с DAG-мемпулом;
  • верификатор — граница с разделом Network: сетевой транспорт, базовые сетевые типы, DHT и оверлеи, а также общие типы;
  • общие типы и конфигурация коллации ни от чего внутри раздела не зависят — это фундамент, на который опирается почти каждая из остальных частей.

На уровне всего домена это повторяет ту же картину, что и у остальных крупных частей узла: коллация в целом зависит от хранилища и сети, а не от чего-то ещё.