Коллация
Коллатор (Collator) - компонент валидатора Tycho, который детерминированно забирает входящие сообщения из модуля консенсуса, исполняет их и формирует блоки.
Назначение коллатора
Коллатор отвечает за:
- получение дедуплицированного и упорядоченного потока внешних сообщений из DAG-мемпула;
- чтение внутренних сообщений из внутренних очередей;
- детерминированную группировку сообщений для параллельного исполнения;
- запуск исполнения сообщений и накопление результатов: транзакции, изменения состояния, новые внутренние сообщения;
- завершение процесса создания блока по лимитам и формирование блока;
- передачу блока дальше в компонент верификации.
При этом коллатор не требует сетевого взаимодействия с другими валидаторами для согласования результата своей работы: в процессе сборки блока он не "договаривается" с сетью, а выполняет локальный детерминированный расчет на уже согласованном входе. Тем самым коллатор может создавать новые блоки сразу без согласования предыдущего блока с другими валидационными нодами.
Практическое следствие: все валидаторы, имея один и тот же согласованный вход, одновременно создают одинаковые блоки на одной и той же высоте. Это уменьшает задержки на согласование содержимого блока между валидаторами и, как результат, существенно снижает время достижения финальности для пользователей и внешних систем.
Дедупликация входящих данных
Дубликаты внешних сообщений возможны из-за "раннего" распространения этих сообщений между валидаторами до того, как они попадут в DAG, и из-за этого одно и то же сообщение может оказаться в нескольких точках DAG.
Удаление дублей делается перед коллатором: внешние сообщения, извлеченные из упорядоченных точек, проходят дедупликацию, в результате которой коллатор получает вход без дублей, что позитивно сказывается на производительности.
Важно: дедупликация не используется как защита от повторного проигрывания сообщений (replay protection), так как эта защита реализована на уровне смарт-контрактов. Дедупликация внешних сообщений служит в первую очередь как оптимизация работы протокола.
Входные данные коллации
Для сборки блока коллатор использует три класса входных данных:
- внешние сообщения из DAG-мемпула: коллатор получает детерминированно упорядоченную (по якорям) и предварительно дедуплицированную последовательность внешних сообщений, согласованную сетью на стадии DAG-мемпула;
- внутренние сообщения из очередей: сообщения, порожденные контрактами, накапливаются во внутренних очередях и затем подаются на коллацию. Допускается детерминированная разбивка аккаунтов (а значит и их входящих сообщений) на независимые партиции, которые можно обрабатывать параллельно;
- контекст состояния и конфигурации: предыдущее состояние шарда и актуальные данные мастерчейна и конфигурации сети.
Группировка сообщений для параллельного исполнения
Коллатор исполняет входящие сообщения не "сплошным потоком", а порциями - группами сообщений. Группа сообщений - это детерминированно сформированный набор сообщений, который коллатор передает на один шаг исполнения и обработки результатов.
Смысл такой группировки:
- повысить параллелизм: группа собирается так, чтобы в ней было много независимых аккаунтов, которые можно исполнять одновременно на разных ядрах;
- снизить конфликты и упростить параллельное исполнение: сообщения группируются по аккаунтам назначения, и один аккаунт представлен в группе сообщений только один раз (со своей очередью сообщений), что исключает конкуренцию за одно и то же состояние;
- ограничить "взрыв" работы: группы формируются с лимитами на размер порции и на "емкость" отдельных частей порции, чтобы один аккаунт/очередь не мог непропорционально занять весь шаг исполнения;
- обеспечить предсказуемость и детерминизм: правила отбора сообщений в группу должны быть полностью детерминированными, чтобы при одинаковом входе все валидаторы сформировали одинаковые группы и получили одинаковый результат.
Свойства группировки группами сообщений:
- детерминированность: при одинаковом входе валидаторы формируют одинаковые группы и одинаково распределяют аккаунты по слотам;
- параллелизм: разные аккаунты внутри одной группы можно исполнять параллельно без гонок за одно и то же состояние;
- отсутствие дубликатов аккаунта в группе: один аккаунт присутствует в группе только один раз, со своей последовательностью сообщений;
- ограничение перекоса нагрузки: распределение по слотам и партициям должно предотвращать ситуацию, когда один высоконагруженный аккаунт блокирует обработку остальных;
- ограниченность порции работы: группа имеет верхнюю границу по объему, что делает шаг исполнения предсказуемым по ресурсам и времени.
Выполнение сообщений
Коллатор выступает оркестратором исполнения сообщений на смарт-контрактах: он подбирает детерминированный набор сообщений для обработки, подготавливает контекст состояния и правил исполнения, запускает выполнение в VM через Executor и собирает результаты.
Executor удобно рассматривать как "чистую функцию" над состоянием и входными сообщениями: при фиксированном входе он детерминированно вычисляет результаты исполнения и новое состояние. Внутри этого процесса TVM исполняет байткод контрактов в sandbox-модели.
Сообщения, направленные в один и тот же аккаунт, исполняются последовательно. Это позволяет не хранить в блоке промежуточные состояния аккаунта: промежуточные результаты между сообщениями удерживаются внутри шага исполнения, а в блок фиксируется итоговый набор транзакций и итоговое обновление состояния.
Детерминизм
Коллатор не может опираться на локальную, недетерминированную информацию (системное время, порядок прихода сетевых пакетов, текущую загрузку CPU/диска). Если такие данные влияют на выбор сообщений, группировку или точки синхронизации, разные валидаторы при одинаковом входе соберут разные блоки. Поэтому коллация построена на строгих правилах, которые дают один и тот же результат независимо от производительности сервера.
Детерминизм обеспечивается двумя аспектами:
- одинаковым порядком исполнения сообщений;
- одинаковыми решениями о том, когда получать следующую группу внешних сообщений из DAG-мемпула.
Порядок исполнения фиксируется правилами логического времени:
- последовательные сообщения одного аккаунта исполняются в строгом порядке по логическому времени;
- между блоками сохраняется монотонность (сообщения более позднего блока считаются логически позже сообщений более раннего блока);
- при отборе сообщений для очередного шага исполнения применяется детерминированная сортировка и детерминированные правила для взаимозависимых вызовов.
Синхронизация с DAG-мемпулом также не может строиться на "прошло N секунд". Вместо этого коллатор измеряет затраты на выпуск блоков в детерминированных единицах работы (Work Unit). Эти единицы считаются по фиксированным формулам фаз prepare, execute и finalize, а затем накапливаются в счетчике между якорями. Накопив достаточно Work Unit, коллатор импортирует следующие якоря и все честные валидаторы делают это после одного и того же номера блока, даже если их реальная скорость выполнения отличается.
Порог импорта задается on-chain параметром wu_used_to_import_next_anchor в CollationConfig. При высоком накопленном значении коллатор может импортировать несколько якорей подряд в одном цикле, последовательно уменьшая накопленный счетчик на один порог за каждый импорт.
Подробный разбор формул и правил импорта приведен в Work Unit в Collator.
Создание блоков
Коллатор создает блок, повторяя детерминированный цикл: читает доступные внешние и внутренние сообщения, формирует группы сообщений, исполняет их, накапливает результаты и обновления состояния, после чего финализирует блок. На каждом шаге считаются Work Unit фаз prepare, execute и finalize, а их сумма попадает в счетчик между якорями. Если в системе есть невыполненные сообщения, коллатор выпускает блоки непрерывно, без простоя. Если входящей нагрузки нет (нет ни внешних, ни внутренних сообщений), пустые блоки создаются редко - в основном затем, чтобы внешние клиенты видели, что сеть не "стоит" и продолжает продвигать высоту/время.
Tycho создает блоки для двух цепочек: шардовой цепочки (где происходит основная пользовательская активность) и мастер-цепочки, которая носит служебный характер и используется в основном для сервисных целей протокола. Блок включает результаты исполнения (транзакции), обновления состояния, ссылки на предыдущие блоки и необходимые данные об изменениях очередей сообщений и связях между мастер- и шардовой частями.
Важный практический момент: в рамках коллации готовые блоки не передаются по сети валидаторам как "большие объекты". Тем не менее размер блока полезно ограничивать, чтобы не перегружать клиентов, которым нужно скачивать, индексировать и хранить данные. На практике такие ограничения формулируются как ограничение вычислительной работы в блоке, например через максимальный суммарно потраченный газ или максимальное число операций/шагов исполнения.
Верификация
Верификация в Tycho используется для:
- Механизм самопроверки: валидатор сравнивает локально полученный результат коллации с тем, что подтверждают остальные участники. Это позволяет своевременно обнаружить устаревшую версию ноды.
- Механизм сбора подписей для клиентов: подписи валидаторов позволяют лайт-нодам принимать блок без полной валидации "тяжелой" части (проверок консенсусного входа и повторного выполнения сообщений), что экономит их CPU/память/трафик и позволяет быстро индексировать транзакции в сети.
- Логически отделенный этап: верификация опциональна относительно самого процесса консенсуса и коллации и может идти асинхронно, пока коллатор продолжает работу над следующими блоками.
Важно, что для верификации по сети не передают сам блок: узлы обмениваются только подписями на хеш по идентификатору блока.