Предложение Finalization protocol (host-initiated, collectors, commit certificate)
Оригинал: Finalization protocol proposal (host-initiated, collectors, commit certificate)

Резюме
Это предложение определяет полный протокол финализации, в котором любой хост может начать финализацию (не только пользователь/программист) с явными доказательствами срабатывания, детерминированным выбором сборщика, безопасностью на этапе фиксации и требованиями проверки основной сети.
Он предназначен для:
сохранить безопасность при византийском поведении,
разрешить ход финализации, когда пользователь не в сети или мошенничает,
уменьшить поток сообщений с помощью детерминированного набора сборщиков,
- заставить основную сеть принимать финализацию только тогда, когда фаза фиксации доказуемо завершена.
Похожие предложения:
- Протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340) — один из дополнительных способов получения маяка случайности коллектора (см. Маяк случайности коллектора).
- Детерминированная случайность в стиле Педерсена (еще один источник сигналов). ЗАДАЧА: описать
Важно учитывать
- Никаких сплетен как ворота доработки. В соответствии с моделью, на которую нацелено это предложение, мы не полагаемся на принцип «сначала сплетни, а затем доработка». Какая бы среда выполнения ни существовала сегодня для разветвления nonce во время нормального выполнения, здесь не указано как способ выравнивания хостов непосредственно перед финализацией.
Никаких сплетен как ворота доработки. В соответствии с моделью, на которую нацелено это предложение, мы не полагаемся на принцип «сначала сплетни, а затем доработка». Какая бы среда выполнения ни существовала сегодня для разветвления nonce во время нормального выполнения, здесь не указано как способ выравнивания хостов непосредственно перед финализацией.
- Nonce ↔ расписание исполнителя (гипотеза). Со строгой привязкой между nonce и хостом-исполнителем (например. N хостов в фиксированном порядке): если хост A выполнил nonce NoID , то хост A снова запланирован на nonce NoID + N и так далее. После полного цикла N последовательных одноразовых номеров каждый хост выполнил один шаг. Открытое предположение: это означает, что каждый другой хост знает об одной и той же линейной истории (или может получить ее) без дополнительного обмена сообщениями. Прежде чем строить на этом аргументы в пользу безопасности, это должно быть подтверждено точными правилами планирования, транспортировки и хранения.
Nonce ↔ расписание исполнителя (гипотеза). Со строгой привязкой между nonce и хостом-исполнителем (например. N хостов в фиксированном порядке): если хост A выполнил nonce NoID , то хост A снова запланирован на nonce NoID + N и так далее. После полного цикла N последовательных одноразовых номеров каждый хост выполнил один шаг. Открытое предположение: это означает, что каждый другой хост знает об одной и той же линейной истории (или может получить ее) без дополнительного обмена сообщениями. Прежде чем строить на этом аргументы в пользу безопасности, это должно быть подтверждено точными правилами планирования, транспортировки и хранения.
- Совместное использование состояний осуществляется отдельно. Для финализации необходим явный протокол совместного использования состояния (что обменивать, кто что доказывает, как обнаружить задержку или форк). Это принадлежит другому документу предложения (не этому файлу). Это предложение описывает голосование/фиксацию/основную сеть только после успешного разделения состояния.
Совместное использование состояний осуществляется отдельно. Для финализации необходим явный протокол совместного использования состояния (что обменивать, кто что доказывает, как обнаружить задержку или форк). Это принадлежит другому документу предложения (не этому файлу). Это предложение описывает голосование/фиксацию/основную сеть только после успешного разделения состояния.
- Случайность коллектора не связана с разделением состояний. Перед этапами 2–4 участники должны договориться о маяке случайности сборщиков — общедоступных материалах, смешанных с начальным числом отбора коллекционеров, чтобы ни один инициатор не мог выбрать подходящие агрегаторы. Синхронизация по высоте не является обязательным условием финализации. Когда используется протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340), его роль здесь заключается только в создании этого маяка (обычно выровненная высота основной сети после проверенных LightBlock s). Другие схемы детерминированной случайности в равной степени действительны, если они соответствуют требованиям маяка случайности коллектора (например, открытые значения из обязательств Педерсена, собранные во время сеанса).
Случайность коллектора не связана с разделением состояний. Перед этапами 2–4 участники должны договориться о маяке случайности сборщиков — общедоступных материалах, смешанных с начальным числом отбора коллекционеров, чтобы ни один инициатор не мог выбрать подходящие агрегаторы. Синхронизация по высоте не является обязательным условием финализации. Когда используется протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340), его роль здесь заключается только в создании этого маяка (обычно выровненная высота основной сети после проверенных LightBlock s). Другие схемы детерминированной случайности в равной степени действительны, если они соответствуют требованиям маяка случайности коллектора (например, открытые значения из обязательств Педерсена, собранные во время сеанса).
- Порядок этапов доработки. Сквозная финализация заключается в следующем: Совместное использование состояния — запуск выделенного протокола до тех пор, пока все необходимые стороны не разделят общее представление о состоянии терминала (или не прекратят работу). Соглашение о случайности — получите и проверьте маяк случайности коллектора для этой попытки завершения (зависит от источника; может совпадать с синхронизацией высоты, раскрытием Педерсена или другой определенной церемонией). Маяк передается в FinalizeInit как randomness_source +collector_randomness_beacon. Обязательство по предложению — трансляция/блокировка FinalizeInit с помощью Finalization_hash, полей маяка и свидетельства триггера. Голосование — FinalizeVote и агрегация в VoteQC (QC = Сертификат кворума: доказательство того, что достаточно хостов проголосовали за один и тот же Finalization_hash). Голосование за обязательство — FinalizeCommit и агрегирование в CommitQC (этап фиксации согласованного предложения), затем FinalizeSubmit в основную сеть.
Порядок этапов доработки. Сквозная доработка – это:
- Совместное использование состояния — запускайте выделенный протокол до тех пор, пока все необходимые стороны не разделят общее представление о состоянии терминала (или не прекратят работу).
- Соглашение о случайности — получите и проверьте маяк случайности коллектора для этой попытки завершения (зависит от источника; может совпадать с синхронизацией высоты, раскрытием Педерсена или другой определенной церемонией). Маяк передается в FinalizeInit как randomness_source +collector_randomness_beacon.
- Обязательство по предложению — трансляция/блокировка FinalizeInit с помощью Finalization_hash, полей маяка и свидетельства триггера.
- Голосование — FinalizeVote и агрегация в VoteQC (QC = Сертификат кворума: доказательство того, что достаточно хостов проголосовали за один и тот же Finalization_hash).
- Голосование за обязательство — FinalizeCommit и агрегирование в CommitQC (этап фиксации согласованного предложения), затем FinalizeSubmit в основную сеть.
Фазы 1–2 могут проходить как одна объединенная церемония или как отдельные этапы; Схемы сообщений ниже соответствуют этапам 3–5. Фаза 1 здесь выходит за рамки в ожидании спецификации совместного использования состояния.
Цели
- Завершение может быть инициировано любым хостом с одной из разрешенных причин запуска.
- Причина срабатывания должна быть подкреплена криптографическими доказательствами, которые могут проверить все хосты.
- Результат финализации должен быть уникальным/безопасным (сертификат фиксации, а не только голосование).
- Основная сеть должна проверить завершение фиксации перед применением урегулирования.
- Сетевые коммуникации должны быть ограничены; по возможности избегайте тотального наводнения.
- Набор сборщиков должен быть детерминированным для всех верификаторов, но при этом непредсказуемым/непредвзятым только для инициатора (через согласованный маяк случайности).
Причины и необходимые доказательства
FinalizationTriggerReason:
ПОЛЬЗОВАТЕЛЬ_CHEATING
EPOCH_CHANGE_IMMINENT
USER_TIMEOUT
Свидетельство триггера не зависит от маяка случайности коллектора, за исключением случаев, когда один и тот же механизм синхронизации по высоте обеспечивает оба (см. USER_TIMEOUT ).
1) ПОЛЬЗОВАТЕЛЬ_CHEATING
Требуемые доказательства:
- одно или несколько сообщений, подписанных пользователем, подтверждающих нарушение протокола, например: конфликтующие подписанные фрагменты в одном и том же одноразовом номере (форк/эквивокация), неверный переход последовательности с подписью пользователя, неправильно сформированный подписанный пользовательский запрос, который не может быть исправлен с помощью более поздних различий.
конфликтующие подписанные фрагменты одновременно (форк/двусмысленность),
неверный переход последовательности с подписью пользователя,
- неправильно сформированный подписанный пользовательский запрос, который не может быть исправлен с помощью более поздних различий.
Каждый предмет доказательств должен включать в себя:
необработанные подписанные байты полезной нагрузки,
подпись пользователя,
nonce/высота/контекст темы,
- хеш предыдущего фрагмента (если есть).
2) EPOCH_CHANGE_IMMINENT
Требуемые доказательства:
- подписанный заголовок блока основной сети (или доказательство легкого клиента), подтверждающий следующую эпоху перехода блоков.
- epoch_current, epoch_next, height_proven.
При этом для триггера используются доказательства заголовка основной сети, а не маяк случайности сборщика.
3) ПОЛЬЗОВАТЕЛЬ_ТАЙМ-АУТ
Требуемые доказательства:
- последний пользователь HeightSyncSection (раздел 1 конверта пользователь-хост), наблюдаемый при обмене данными, с действительным CometBFT LightBlock и подписью отправителя,
- наибольшая наблюдаемая высота ответа/запроса для каждого хоста для одного и того же сеанса (из проверенного раздела 1 в обоих направлениях),
- окно тайм-аута в блоках.
Тайм-аут рассчитывается по:
- max(user_height_seen, host_response_height_seen) и текущий совет основной сети.
Формат конверта, доказательства и подписи определены в: Протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340) (структурированное тело HTTP: раздел высоты + раздел сообщения).
Примечание. Синхронизация по высоте здесь доказывает отсутствие активности пользователя для триггера. Само по себе это не оправдывает обработку выровненной высоты основной сети как глобальных часов финализации, если только это же значение не будет также принято как Collector_randomness_beacon в случайном_источнике = HEIGHT_SYNC_ALIGNED_HEIGHT.
Депонирование, привязанное к эпохе: валидаторы L1 от участников эпохи
Если срок службы подсети ограничен одной эпохой основной сети и подсеть завершается при переключении эпохи (в соответствии с политикой перехода EPOCH_CHANGE_IMMINENT/эпохи), запуск условного депонирования не обязательно должен включать набор валидаторов L1. Валидаторы CometBFT, которые могут подписывать блоки в течение этой эпохи, определяются участниками эпохи основной сети (каноническое состояние в цепочке; точный модуль/запрос подлежит уточнению). Каждый хост загружает этот список участников один раз за эпоху, преобразует записи в адреса консенсусных валидаторов Cosmos/CometBFT (тот же вывод, что и в блоках), кэширует их и использует результат для вычисления ожидаемого validators_hash на высоте H при проверке LightBlock (например, в доказательствах USER_TIMEOUT или когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT) на шаге 3b в протоколе синхронизации высоты. (https://github.com/gonka-ai/gonka/discussions/1340), поэтому одноранговые LightBlock не могут использовать изготовленный набор валидаторов.
Создание условного депонирования по-прежнему может определять, какая эпоха применяется (например, с помощью высоты создания или дополнительного поля epoch_id) без дублирования ключей валидатора в стартовом сообщении.
Обязательство состояния и хеш завершения
Чтобы избежать двусмысленности и обеспечить детерминированный выбор коллектора, определите:
NonceLeaf_i = H(nonce_i || state_hash_i || tx_digest_i)
NonceMerkleRoot = MerkleRoot(NonceLeaf_1..NonceLeaf_N) (упорядочено по nonce)
Затем дайджест кандидата на доработку:
FinalizationHash = H(escrow_id || round || триггер_причина || триггер_evidence_hash || nonce_merkle_root || терминал_nonce || Settlement_payload_hash)
Trigger_evidence_hash — это корень Merkle для всех элементов триггерных доказательств.
Маяк случайности коллектора не является частью этого дайджеста. Он переносится в FinalizeInit (и отображается в FinalizeSubmit) и смешивается только с начальным числом выбора сборщика (см. Детерминированные сборщики). Отсутствие случайности в FinalizationHash позволяет одному и тому же предложению состояния терминала использовать разные источники или раунды маяков, при этом привязывая голоса/фиксации к одной полезной нагрузке расчета.
Обоснование:
- Корень Меркла меньше по размеру, и его легче проверить постепенно, чем объединение всех хешей nonce.
- доказательства для отдельных одноразовых номеров/доказательств компактны.
Незавершенная работа на стадии доработки
Когда начинается финализация (состояние завершения раунда фиксировано), протокол применяет детерминированные значения по умолчанию, поэтому расчет всегда закрывается:
- Незавершенные выводы — любой вывод, не находящийся в состоянии окончательного успеха (Ожидание, Начато, текущее выполнение и т. д.), рассматривается как успешно завершенный для расчета: зачисляется исполнителю по зарезервированной или согласованной стоимости, включенной в nonce_merkle_root и Settlement_payload, так же, как и обычный завершенный результат.
- Незавершенные проверки — любая проверка, которая не была завершена до начала финализации, не запускается. Открытые окна проверки закрываются без дальнейших проверок; частичная или отсутствующая работа по проверке не блокирует финализацию и не меняет автоматически завершенный результат вывода, указанный выше.
Эти правила применяются во время совместного использования состояния при построении представления терминала, которое передает FinalizationHash. Все хосты должны применять одни и те же значения по умолчанию, чтобы поля nonce_merkle_root и payout совпадали. Споры о правильности расчетов (если таковые имеются) выходят за рамки настоящего протокола голосования/фиксации.
Коллекторный маяк случайности
Детерминистическим сборщикам нужен общий источник псевдослучайности, который:
- Каждый честный хост получает одно и то же значение перед отправкой FinalizeVote (с учетом принятого FinalizeInit ).
- Инициатор не может в одностороннем порядке выбрать исходный материал, благоприятный для сборщика, после того, как станет известно конечное состояние (в противном случае он может измельчить комбинации FinalizationHash + beacon).
- Основная сеть может проверить правильность создания маяка для объявленного источника randomness_source.
- Независим от FinalizationHash, поэтому содержимое расчетов и начальное значение перемешивания являются отдельными обязательствами (см. выше).
Синхронизация высоты удовлетворяет условиям (1)–(3) при использовании только в качестве источника случайности: стороны запускают правила конвергенции синхронизации высоты из протокола синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340) и принимают полученную выровненную высоту основной сети в качестве материала маяка. Эта высота не требуется для финализации, поскольку хосты должны «согласовать подсказку L1» в целом — она требуется только в той мере, в какой выбранная схема случайности использует ее.
Поддерживаемые источники (расширяемое перечисление)
Реализации выбирают один источник для каждого условного депонирования или каждого параметра цепочки. FinalizeInit должен объявить источник, чтобы верификаторы не предполагали синхронизацию высоты при использовании другой церемонии.
Почему бы не использовать только FinalizationHash?
FinalizationHash фиксируется по предложению инициатора. Без внешней случайности начальное значение = H(FinalizationHash || «коллекторы») полностью предсказуемо для инициатора, который может пробовать альтернативные представления доказательств/состояний до тех пор, пока сборщики не отдадут предпочтение своему слоту. Маяк разрушает эту шлифовку.
Детерминированные коллекторы
Коллекторы выбираются из активных слотов с помощью FinalizationHash, randomness_source и Collector_randomness_beacon из FinalizeInit (одна и та же тройка, которую каждый хост и основная сеть должны использовать в раунде).
Параметры:
Collector_count = c (например, c=3 или c=5, параметр цепочки)
- randness_source: перечисление, выбирающее правила проверки (см. Маяк случайности сборщика).
- Collector_randomness_beacon: непрозрачные байты, кодировка которых зависит от randomness_source.
семя выбора: семя = H(FinalizationHash || случайный_источник || коллектор_рандомность_маяк || "коллекторы")
семя = H(FinalizationHash || источник_рандомизма || коллектор_рандомность_маяк || "коллекторы")
Хэш H — это та же функция, которая используется в других местах этого предложения (например, Хеш финализации). Детерминированное «случайное» перемешивание: начальное число фиксирует псевдослучайную перестановку слотов; все верификаторы получают один и тот же набор сборщиков без дополнительных сообщений.
Эталонное кодирование для синхронизации по высоте: когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT, Collector_randomness_beacon ДОЛЖЕН быть 8-байтовым выравниванием_mainnet_height с прямым порядком байтов из протокола синхронизации по высоте (https://github.com/gonka-ai/gonka/discussions/1340).
Алгоритм:
- Проверьте Collector_randomness_beacon для случайного_источника.
- Создайте детерминированный список активных слотов (отсортированные идентификаторы слотов).
- Используйте детерминированное перетасовывание, управляемое начальным числом.
- Возьмите сначала уникальные слоты в качестве коллекционеров.
Обязанности коллекторов:
агрегировать голоса и строить VoteQC,
собирать аттестации коммитов и строить CommitQC,
- после существования CommitQC отправьте один подписанный FinalizeSubmit в основную сеть (без более раннего трафика основной сети для голосования/фиксации).
Резервный вариант:
- если тайм-аут сборщика истекает, любой хост может принять отправку с теми же сертификатами.
Точный протокол (инициатор, заказ, транспорт)
В этом разделе указывается, кто запускает, в каком порядке передаются сообщения и по какому пути проходит каждое сообщение. Предполагается, что разделение состояния (этап 1) прошло успешно, участники совместно используют состояние терминала и имеют проверенный маяк случайности коллектора для попытки (этап 2).
Инициатор
- Кто: Любой хост в наборе активных участников может инициировать попытку финализации условного депонирования при условии, что он прикрепит действительные доказательства триггера для одного из FinalizationTriggerReason (см. Причины триггера и необходимые доказательства).
- Что они отправляют первым: подписанный FinalizeInit — это первое сообщение раунда. В этом проекте нет отдельного «избранного лидера»: первый действительный FinalizeInit, который принимают хосты для (escrow_id, round) в соответствии с правилами дедупликации/блокировки/разблокировки, открывает этот раунд. (Политика может позже добавить ротацию предлагающих; эта спецификация делает инициацию неразрешенной для честных хостов.)
- Раунд 1: FinalizeInit с round = 1 и отсутствием unlock_timeout_certificate (первая попытка завершения процесса условного депонирования).
- Раунд > 1: FinalizeInit должен включать действительный unlock_timeout_certificate, подтверждающий, что предыдущая попытка раунда (или раунд, указанный в сертификате) исчерпана без расчета — см. unlock_timeout_certificate в разделе FinalizeInit. Организаторы отклоняют более высокий раунд без соответствующего доказательства, если они все еще заблокированы из предыдущего раунда (см. Блокировка голосования и несколько раундов).
Порядок сообщений (один раунд, счастливый путь)
Для фиксированного (escrow_id, round):
- FinalizeInit — одно логическое предложение за раунд (может дублироваться слухами; дедупликация верификаторов осуществляется с помощью message_hash ).
- FinalizeVote — каждый участвующий хост отправляет не более одного голоса за (escrow_id, раунд) после проверки FinalizeInit (включая проверку маяка).
- VoteQC — производится только сборщиками после 2f+1 сопоставления AGREE с тем же Finalization_hash ; коллекторы передают компактный QC всем хостам (такой же транспорт, как и другие разветвления коллекторов).
- FinalizeCommit — каждый хост, который принимает VoteQC, отправляет не более одного коммита на каждый (escrow_id, раунд), ссылаясь на этот VoteQC (например, voice_qc_hash), только сборщикам (никаких слухов о фиксации между хостами; см. Транспорт).
- CommitQC — сборщики агрегированных коммитов, транслирующие компактный CommitQC.
- FinalizeSubmit — одна подписанная транзакция в mainnet, отправленная сборщиком (или резервным отправителем после таймаута сборщика), содержащая поля VoteQC, CommitQC и расчет.
Несчастливый путь: если шаг 3 никогда не дает результата VoteQC (недостаточно AGREE , все REJECT или тайм-аут) или шаг 5 никогда не дает CommitQC , в этом раунде не происходит отправки в основную сеть. Хосты ждут unlock_timeout_certificate (или участия локального таймаута в его формировании), затем новый FinalizeInit с round := round + 1 может начать следующую попытку.
Транспорт
Минимизация трафика коммитов: достаточно, чтобы FinalizeCommit отправлялся только сборщикам; это ограничивает разветвление фиксации до O(hosts ×collector_count) вместо лавинной рассылки между хостами. Никакого отдельного пути фиксации «все ко всем» не требуется.
Полезные данные доказательств: большие триггер_evidence_items ДОЛЖНЫ использовать хэш + выборку после первого объявления; FinalizeInit содержит корни и дополнительные ссылки, соответствующие минимизации связи.
Протокольные сообщения
Эти сообщения реализуют этапы 3–5 раздела «Важно учитывать» (после соглашения о совместном использовании состояний и случайности). Они не определяют разделение штатов или церемонии вручения маяков.
Все сообщения должны содержать:
escrow_id
круглый (монотонный uint64)
отправитель_слот
sender_sig
тип_сообщения
message_hash
Финализеинит
Поля:
escrow_id
круглый
- randomness_source (enum): объявляет, как проверить коллектор_randomness_beacon (см. «Маяк случайности коллектора»).
- Collector_randomness_beacon (байты): материал, специфичный для источника, смешанный с начальным числом коллектора. Хосты отклоняют FinalizeInit, если проверка объявленного источника не удалась или если значение маяка отличается от локально проверенного значения для этой попытки депонирования (если политика не допускает определенного допуска). Коллекторы для раунда получаются из FinalizationHash, этого поля и randomness_source (Детерминированные коллекторы).
- randomness_evidence (необязательно): доказательства, специфичные для источника (например, LightBlock с синхронизацией по высоте, вступительные расшифровки Педерсена), если их нельзя вывести из состояния кэшированного сеанса.
триггер_причина
триггер_evidence_root
триггер_evidence_items (или получить ссылки)
nonce_merkle_root
терминал_нонсе
Settlement_payload_hash
Finalization_hash
- unlock_timeout_certificate: Пропустить round = 1. В раунде > 1 требуется (см. Точный протокол — Инициатор): подписанное кворумом (или определенное политикой) доказательство того, что предыдущий раунд завершился без успешного расчета, чтобы можно было начать этот раунд. Должно охватывать как минимум: (a) раунд r не получил CommitQC и/или (b) раунд r не получил действительный VoteQC к крайнему сроку (этап голосования не пройден). Точная кодировка подлежит уточнению; функционально сертификат «раунда исчерпан».
Продвижение раундов: чтобы открыть round = r_new > 1, инициатор включает unlock_timeout_certificate для предыдущей попытки (обычно r_new - 1), если политика цепочки не определяет другое сопоставление. Хосты проверяют сертификат перед принятием нового FinalizeInit, если они удерживают блокировку из предыдущего раунда.
Псевдоним синхронизации высоты: когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT, Collector_randomness_beacon равен uint64_be(aligned_mainnet_height) из протокола синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340). В более старых черновиках это поле в сообщении называлось Align_mainnet_height; байты маяка представляют собой каноническую кодировку.
Завершить голосование
Поля:
escrow_id
круглый
Finalization_hash
голосовать ( СОГЛАСЕН / ОТКЛОНЕН )
код_отклонения (необязательно)
ignore_evidence_hash (необязательно)
ГолосоватьQC
Произведено коллекционерами после 2f+1 совпадения голосов AGREE. Распространен на все хосты после агрегации. Включено в FinalizeSubmit в основную сеть.
Поля:
escrow_id
круглый
Finalization_hash
voice_signers_bitmap
агрегированный_vote_signature (или список явных подписей)
voice_count
Завершить фиксацию
Отправляется хостами сборщикам только после проверки VoteQC (не передается между хостами; см. Точный протокол — Транспорт).
Поля:
escrow_id
круглый
Finalization_hash
voice_qc_hash
зафиксировать (СОВЕРШИТЬ)
CommitQC
Создается сборщиками после достижения порога фиксации.
Поля:
escrow_id
круглый
Finalization_hash
voice_qc_hash
commit_signers_bitmap
агрегированный_commit_signature (или список явных подписей)
commit_count
FinalizeSubmit (в основную сеть)
Поля:
escrow_id
круглый
случайный_источник
- Collector_randomness_beacon: должен соответствовать принятому FinalizeInit для этого (escrow_id, round), чтобы хранитель (и аудиторы) могли повторно получить набор сборщиков с помощью FinalizationHash.
- randomness_evidence (необязательно): та же роль, что и FinalizeInit, если основная сеть не может полагаться на кеш предыдущего сеанса.
триггер_причина
триггер_evidence_root
nonce_merkle_root
терминал_нонсе
Settlement_payload
Finalization_hash
voice_qc
commit_qc
Блокировка голосования и несколько туров
Правило:
- Хост, отправивший FinalizeVote AGREE в раунде r для Finalization_hash H, заблокирован (r, H) .
- Хост не должен отправлять второй конфликтующий FinalizeVote для одного и того же (escrow_id, r) .
- Хост может принять FinalizeInit для r_new > r и проголосовать снова, только если unlock_timeout_certificate (и любая более строгая политика цепочки) показывает, что раунд r исчерпан без урегулирования - поэтому продвижение раунда оправдано, а не произвольное переворачивание представления.
Изменение Finalization_hash в более позднем раунде: Реализации ДОЛЖНЫ требовать unlock_timeout_certificate перед принятием FinalizeInit с другим Finalization_hash, отличным от хеша, за который хост ранее проголосовал AGREE, поэтому нечестный инициатор не может перенаправлять честных избирателей между конфликтующими предложениями без истечения времени ожидания или неудачного предыдущего раунда.
Практическое состояние каждого хоста:
- lock_round , lock_hash после голосования СОГЛАСИЕ до разблокировки или успешного расчета в основной сети для условного депонирования.
- В FinalizeInit(r_new) : если r_new > lock_round , требуется действительный unlock_timeout_certificate, охватывающий остановленные раунды для каждой политики; затем обновите блокировку при голосовании в r_new.
Повторить попытку без повторного раунда (необязательная оптимизация): если VoteQC существует, но CommitQC никогда не формируется, реализация МОЖЕТ повторно передать VoteQC и запустить еще одну волну FinalizeCommit в том же раунде вместо увеличения round . По умолчанию в этом документе используется круглая монотонность + новый FinalizeInit с unlock_timeout_certificate, поэтому каждая повторная попытка явно открывается.
Нет двойной финализации (идемпотентность)
Сплетни в подсети могут доставлять один и тот же материал FinalizeSubmit много раз, и нескольким сборщикам разрешено транслировать/отправлять его. Расчет по-прежнему должен происходить не более одного раза за каждое условное депонирование в основной сети.
Гарантии исходят из правил уровня приложения в keeper , а не только из протокола голосования/фиксации:
- Состояние терминала условного депонирования: цепочка хранит каждый escrow_id в жизненном цикле (например, АКТИВ → УСТАНОВЛЕНО / ЗАКРЫТО). Обработчик отклоняет любое сообщение завершения, если это условное депонирование уже оплачено (или уже прервано по определенному пути спора). Это основные ворота «никогда дважды».
Состояние условного депонирования терминала: цепочка хранит каждый escrow_id в жизненном цикле (например, АКТИВ → УСТАНОВЛЕНО / ЗАКРЫТО). Обработчик отклоняет любое сообщение завершения, если это условное депонирование уже оплачено (или уже прервано по определенному пути спора). Это основные ворота «никогда дважды».
- Необязательная привязка дайджеста: хранитель МОЖЕТ записать Last_finalization_hash (или Settled_terminal_nonce + обязательство по полезной нагрузке) для условного депонирования и отклонить вторую отправку, которая отличается (конфликтующая повторная попытка). Байт-идентичное воспроизведение одной и той же действительной отправки должно быть отклонено как дубликат или рассматриваться как недействующее (идемпотентный успех), чтобы сборщики, участвующие в гонках с одними и теми же сертификатами, не применяли эффекты дважды.
Необязательная привязка дайджеста: хранитель МОЖЕТ записать Last_finalization_hash (или Settled_terminal_nonce + обязательство по полезной нагрузке) для условного депонирования и отклонить вторую отправку, которая отличается (конфликтующая повторная попытка). Байт-идентичное воспроизведение одной и той же действительной отправки должно быть отклонено как дубликат или рассматриваться как недействующее (идемпотентный успех), чтобы сборщики, участвующие в гонках с одними и теми же сертификатами, не применяли эффекты дважды.
- Те же сертификаты, один эффект: VoteQC и CommitQC связывают отправку с одним Finalization_hash. Честные хозяева подписывают только один гарантированный результат за успешный раунд; для двух разных результатов потребуются разные хеши, и они не смогут пройти оба, если цепочка не разрешит второй раунд, который все равно должен соблюдать (1).
Те же сертификаты, один эффект: VoteQC и CommitQC связывают отправку с одним Finalization_hash. Честные хозяева подписывают только один гарантированный результат за успешный раунд; для двух разных результатов потребуются разные хеши, и они не смогут пройти оба, если цепочка не разрешит второй раунд, который все равно должен соблюдать (1).
- Дедупликация на уровне передачи: дедупликация последовательности/пула памяти Cosmos SDK предотвращает двукратное выполнение одной и той же подписанной передачи; отдельные транзакции, повторяющие один и тот же расчет, все равно должны завершиться неудачей в (1)–(2).
Дедупликация на уровне передачи: дедупликация последовательности/пула памяти Cosmos SDK предотвращает двукратное выполнение одной и той же подписанной передачи; отдельные транзакции, повторяющие один и тот же расчет, все равно должны завершиться неудачей в (1)–(2).
Фаза фиксации предотвращает подписание кворумом конфликтующих финалов без нового раунда и правил разблокировки; Идемпотентность основной сети предотвращает повторное применение расчетов для одного и того же условного депонирования.
Взаимодействие с основной сетью: одиночный проход туда и обратно
Фазы голосования и фиксации выполняются только на уровне devshard-local. FinalizeInit и контроль качества, созданные сборщиком, используют слухи о подсети; FinalizeCommit управляется только сборщиком (см. Транспорт). Во время выполнения этих этапов в основную сеть не поступает никаких сообщений — нет «отчета о голосовании по контролю качества» или «отчета о подтверждении контроля качества» как отдельных транзакций цепочки.
Одно цепное взаимодействие: когда подсеть завершена, сборщик (или резервный отправитель) передает одну подписанную транзакцию FinalizeSubmit, которая включает в себя полезную нагрузку расчета, поля случайности, VoteQC, CommitQC и все поля, необходимые для повторного вычисления Finalization_hash. Узел возвращает успешную передачу (расчет применен) или неудачу (ошибка проверки → отклонено).
Почему бы не увеличить количество шагов в основной сети: промежуточные события «голосование подтверждено» / «проверено подтверждение» будут подразумевать дополнительный трафик devshard↔ в основной сети и не повышать безопасность, если хранитель применяет состояние только к окончательному принятому сообщению. Проверка VoteQC и CommitQC происходит внутри этого одного обработчика.
События (для хостов devshard, а не дополнительные круговые обходы): хранитель должен генерировать события Cosmos по результатам, чтобы каждый хост devshard мог узнать результат, наблюдая за цепочкой, даже если отправляющий сборщик выйдет из строя, прежде чем сообщить об успехе:
- Finalization_settled — включает escrow_id, Finalization_hash и любые поля индекса, необходимые для кошельков/индексаторов.
- Finalization_rejected — включает escrow_id, Finalization_hash (если анализируемый) и код причины/класс ошибки.
Необязательно: один общий Finalization_outcome с перечислением SETLED | REJECTED вместо двух типов событий. Не создавайте отдельные события цепочки, которые отражают внутренние проверки голосования и фиксации, если только потребность продукта не требует аудита (который может оставаться в журналах, а не через p2p в основную сеть).
Изменения проверки в основной сети
Обработчик основной сети должен отклонять отправки финализации, если:
- Finalization_hash пересчитывает точно на основе полезных данных и доказательств.
- присутствуют случайный_источник и коллектор_рандомность_маяк; маяк проверяет заявленный источник; необязательная строгая проверка того, что подписывающие лица в VoteQC/CommitQC являются именно набором сборщиков из H(FinalizationHash || randomness_source || Collector_randomness_beacon || "collectors"), если цепочка проверяет членство сборщика.
- Триггерные доказательства действительны по заявленной причине (независимые проверки — например, Разделы синхронизации высоты USER_TIMEOUT, подтверждение заголовка EPOCH_CHANGE_IMMINENT).
- Голосование действительно и соответствует порогу 2f+1.
- CommitQC действителен, ссылается на VoteQC и соответствует порогу 2f+1 (или настроенному порогу фиксации).
- Проверки раундов и повторов проходят (escrow_id, монотонность раунда, отсутствие дублирующего хеша финализации).
- Идемпотентность: условное депонирование еще не урегулировано в соответствии с отсутствием двойной финализации, указанной выше; применяются повторяющиеся или противоречивые правила повторной отправки.
Пункты 4–5 — это проверки в памяти внутри одного tx, а не отдельных сообщений основной сети.
Минимизация связи
- Хосты отправляют FinalizeVote коллекторам (направленная ретрансляция или ретрансляция с адресом коллектора); FinalizeCommit предназначен только для сборщиков — никаких слухов о коммитах между хостами (достаточно для ограничения трафика коммитов).
- Коллекторы агрегируют и транслируют только компактные VoteQC/CommitQC.
- Большие двоичные объекты доказательств передаются по ссылке (хэш+выборка) после первого распространения.
- Дедупликация (escrow_id, round, message_hash).
Открытые вопросы
сообщить о совместном использовании до того, как будет принято окончательное предложение,
- Церемония обязательства Педерсена: точная фаза публикации, агрегация, правила открытия и проверка основной сети для randomness_source = PEDERSEN_COMMITMENT ,
- источник случайности по умолчанию для каждого параметра условного депонирования/цепочки (синхронизация по высоте против Педерсена против гибрида),
агрегированные BLS,
продолжительность хранения доказательств и гарантии сокращения,
- должен ли путь REJECT также создавать сертификаты фиксации для детерминированного урегулирования по умолчанию.

Summary
This proposal defines a complete finalization protocol where any host can start finalization (not only the user/sequencer), with explicit trigger proofs, deterministic collector selection, commit-phase safety, and mainnet verification requirements.
It is designed to:
preserve safety under Byzantine behavior,
allow finalization progress when the user is offline or cheating,
reduce message flood via deterministic collector set,
- make mainnet accept finalization only when commit phase is provably complete.
Related proposals:
- Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) — one optional way to obtain the collector randomness beacon (see Collector randomness beacon ).
- Pedersen-style deterministic randomness (another beacon source). TODO: describe
Important to consider
- No gossip as the finalization gate. Under the model this proposal targets, we do not rely on “gossip first, then finalize.” Whatever runtime exists today for nonce fan-out during normal execution is not specified here as the way hosts align immediately before finalization.
No gossip as the finalization gate. Under the model this proposal targets, we do not rely on “gossip first, then finalize.” Whatever runtime exists today for nonce fan-out during normal execution is not specified here as the way hosts align immediately before finalization.
- Nonce ↔ executor schedule (hypothesis). With a strict binding between nonce and executor host (e.g. N hosts in fixed order): if host A executed nonce NoID , then host A is scheduled again at nonce NoID + N , and so on. After a full round of N consecutive nonces, each host has executed one step. Open assumption: that implies every other host is then aware of the same linear history (or can derive it) without extra messaging. This must be proved under the exact scheduling, transport, and storage rules before building safety arguments on it.
Nonce ↔ executor schedule (hypothesis). With a strict binding between nonce and executor host (e.g. N hosts in fixed order): if host A executed nonce NoID , then host A is scheduled again at nonce NoID + N , and so on. After a full round of N consecutive nonces, each host has executed one step. Open assumption: that implies every other host is then aware of the same linear history (or can derive it) without extra messaging. This must be proved under the exact scheduling, transport, and storage rules before building safety arguments on it.
- State sharing is separate. Finalization needs an explicit state sharing protocol (what to exchange, who proves what, how to detect lag or fork). That belongs in another proposal document (not this file). This proposal describes vote / commit / mainnet only after state sharing has succeeded.
State sharing is separate. Finalization needs an explicit state sharing protocol (what to exchange, who proves what, how to detect lag or fork). That belongs in another proposal document (not this file). This proposal describes vote / commit / mainnet only after state sharing has succeeded.
- Collector randomness is separate from state sharing. Before phases 2–4, participants must agree on a collector randomness beacon — public material mixed into the collector-selection seed so no single initiator can pick favorable aggregators. Height sync is not a general finalization prerequisite. When Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) is used, its role here is only to produce that beacon (typically the aligned mainnet height after verified LightBlock s). Other deterministic randomness schemes are equally valid if they meet the requirements in Collector randomness beacon (e.g. opened values from Pedersen commitments collected during the session).
Collector randomness is separate from state sharing. Before phases 2–4, participants must agree on a collector randomness beacon — public material mixed into the collector-selection seed so no single initiator can pick favorable aggregators. Height sync is not a general finalization prerequisite. When Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) is used, its role here is only to produce that beacon (typically the aligned mainnet height after verified LightBlock s). Other deterministic randomness schemes are equally valid if they meet the requirements in Collector randomness beacon (e.g. opened values from Pedersen commitments collected during the session).
- Phase order for finalization. End-to-end finalization is: State sharing — run the dedicated protocol until all required parties share a common view of terminal state (or abort). Randomness agreement — obtain and verify the collector randomness beacon for this finalization attempt (source-specific; may coincide with height sync, Pedersen reveal, or another defined ceremony). The beacon is carried on FinalizeInit as randomness_source + collector_randomness_beacon . Proposal commitment — broadcast / lock FinalizeInit with finalization_hash , beacon fields, and trigger evidence. Voting — FinalizeVote and aggregation into VoteQC ( QC = Quorum Certificate : proof enough hosts voted for the same finalization_hash ). Vote commitment — FinalizeCommit and aggregation into CommitQC (commit phase on the agreed proposal), then FinalizeSubmit to mainnet.
Phase order for finalization. End-to-end finalization is:
- State sharing — run the dedicated protocol until all required parties share a common view of terminal state (or abort).
- Randomness agreement — obtain and verify the collector randomness beacon for this finalization attempt (source-specific; may coincide with height sync, Pedersen reveal, or another defined ceremony). The beacon is carried on FinalizeInit as randomness_source + collector_randomness_beacon .
- Proposal commitment — broadcast / lock FinalizeInit with finalization_hash , beacon fields, and trigger evidence.
- Voting — FinalizeVote and aggregation into VoteQC ( QC = Quorum Certificate : proof enough hosts voted for the same finalization_hash ).
- Vote commitment — FinalizeCommit and aggregation into CommitQC (commit phase on the agreed proposal), then FinalizeSubmit to mainnet.
Phases 1–2 may run in one combined ceremony or as distinct steps; message schemas below map to phases 3–5 . Phase 1 is out of scope here pending the state-sharing spec.
Goals
- Finalization can be initiated by any host with one of the allowed trigger reasons.
- Trigger reason must be backed by cryptographic evidence all hosts can verify.
- Finalization result must be unique/safe (commit certificate, not vote-only).
- Mainnet must verify commit completion before applying settlement.
- Network communications should be bounded; avoid all-to-all flooding where possible.
- Collector set must be deterministic for all verifiers yet unpredictable / unbiasable by the initiator alone (via agreed randomness beacon).
Trigger reasons and required evidence
FinalizationTriggerReason :
USER_CHEATING
EPOCH_CHANGE_IMMINENT
USER_TIMEOUT
Trigger evidence is independent of the collector randomness beacon except where the same height-sync machinery happens to supply both (see USER_TIMEOUT ).
1) USER_CHEATING
Required evidence:
- one or more user-signed messages proving protocol violation, for example: conflicting signed fragments at same nonce (fork/equivocation), invalid sequence transition with user signature, malformed signed user request that cannot be repaired by later diffs.
conflicting signed fragments at same nonce (fork/equivocation),
invalid sequence transition with user signature,
- malformed signed user request that cannot be repaired by later diffs.
Each evidence item must include:
raw signed payload bytes,
user signature,
nonce/height/topic context,
- hash of previous fragment (if available).
2) EPOCH_CHANGE_IMMINENT
Required evidence:
- signed mainnet block header (or light-client proof) proving next block transitions epoch.
- epoch_current , epoch_next , height_proven .
This uses mainnet header proofs for the trigger , not the collector randomness beacon.
3) USER_TIMEOUT
Required evidence:
- latest user HeightSyncSection (section 1 of the user–host envelope) observed in communication, with valid CometBFT LightBlock and sender signature,
per-host highest observed response/request height for the same session (from validated section 1 on both directions),
- timeout window in blocks.
Timeout is computed against:
- max(user_height_seen, host_response_height_seen) and current mainnet tip.
Envelope format, proofs, and signatures are defined in: Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) (structured HTTP body: height section + message section).
Note: Height sync here proves user liveness failure for the trigger. It does not by itself justify treating aligned mainnet height as a global finalization clock unless that same value is also adopted as collector_randomness_beacon under randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT .
Epoch-bound escrow: L1 validators from epoch participants
When subnet life is limited to one mainnet epoch and the subnet is finalized on epoch switch (aligned with EPOCH_CHANGE_IMMINENT / epoch transition policy), escrow start need not include the L1 validator set. The CometBFT validators that may sign blocks during that epoch are defined by mainnet epoch participants (canonical on-chain state; exact module/query TBD). Each host loads that participant list once per epoch , converts entries to Cosmos / CometBFT consensus validator addresses (same derivation as in blocks), caches them, and uses the result to compute the expected validators_hash at height H when verifying LightBlock s (e.g. in USER_TIMEOUT evidence or when randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT ) per Step 3b in Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) , so peer LightBlock s cannot use a fabricated validator set.
Escrow creation may still fix which epoch applies (e.g. via creation height or an optional epoch_id field) without duplicating validator keys on the start message.
State commitment and finalization hash
To avoid ambiguity and enable deterministic collector choice, define:
NonceLeaf_i = H(nonce_i || state_hash_i || tx_digest_i)
NonceMerkleRoot = MerkleRoot(NonceLeaf_1..NonceLeaf_N) (ordered by nonce)
Then finalization candidate digest:
FinalizationHash = H(escrow_id || round || trigger_reason || trigger_evidence_hash || nonce_merkle_root || terminal_nonce || settlement_payload_hash)
trigger_evidence_hash is Merkle root of all trigger evidence items.
The collector randomness beacon is not part of this digest. It is carried on FinalizeInit (and echoed on FinalizeSubmit ) and mixed into the collector selection seed only (see Deterministic collectors ). Keeping randomness out of FinalizationHash lets the same terminal state proposal use different beacon sources or rounds while still binding votes/commits to one settlement payload.
Rationale:
- Merkle root is smaller and easier to verify incrementally than concatenating all nonce hashes.
- proofs for individual nonces/evidence are compact.
Unfinished work at finalization
When finalization starts (terminal state is fixed for the round), the protocol applies deterministic defaults so settlement always closes:
- Unfinished inferences — any inference not in a terminal success state ( Pending , Started , in-flight execution, etc.) is treated as successfully finished for settlement: credited to the executor at the reserved or agreed cost, included in nonce_merkle_root and settlement_payload , same as a normal Finished outcome.
- Unfinished validations — any validation that had not completed before finalization started is not run . Open validation windows close without further checks; partial or missing validation work does not block finalization and does not change the auto-finished inference outcome above.
These rules apply during state sharing when building the terminal view that feeds FinalizationHash . All hosts must apply the same defaults so nonce_merkle_root and payout fields match. Post-settlement correctness disputes (if any) are out of scope for this vote/commit protocol.
Collector randomness beacon
Deterministic collectors need a shared source of pseudorandomness that:
- Every honest host derives the same value before sending FinalizeVote (given the accepted FinalizeInit ).
- The initiator cannot unilaterally choose collector-favorable seed material after the terminal state is known (otherwise they could grind FinalizationHash + beacon combinations).
- Mainnet can verify the beacon was produced correctly for the declared randomness_source .
- Is independent of FinalizationHash so settlement content and shuffle seed are separate commitments (see above).
Height sync satisfies (1)–(3) when used only as a randomness source : parties run the height-sync convergence rules from Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) and take the resulting aligned mainnet height as beacon material. That height is not required for finalization because hosts must “agree on L1 tip” in general — it is required only insofar as the chosen randomness scheme uses it.
Supported sources (extensible enum)
Implementations pick one source per escrow or per chain param. FinalizeInit must declare the source so verifiers do not assume height sync when another ceremony was used.
Why not FinalizationHash alone?
FinalizationHash is fixed by the initiator’s proposal. Without external randomness, seed = H(FinalizationHash || "collectors") is fully predictable to the initiator, who could try alternate evidence/state presentations until collectors favor their slot. The beacon breaks that grind.
Deterministic collectors
Collectors are selected from active slots using FinalizationHash , randomness_source , and collector_randomness_beacon from FinalizeInit (same triple every host and mainnet must use for the round).
Parameters:
collector_count = c (for example c=3 or c=5 , chain param)
- randomness_source : enum selecting verification rules (see Collector randomness beacon ).
- collector_randomness_beacon : opaque bytes whose encoding depends on randomness_source .
- selection seed: seed = H(FinalizationHash || randomness_source || collector_randomness_beacon || "collectors")
seed = H(FinalizationHash || randomness_source || collector_randomness_beacon || "collectors")
The hash H is the same function used elsewhere in this proposal (e.g. FinalizationHash ). Deterministic “random” shuffle: the seed fixes a pseudorandom permutation of slots; all verifiers derive the same collector set without extra messaging.
Reference encoding for height sync: when randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT , collector_randomness_beacon MUST be the 8-byte big-endian aligned_mainnet_height from Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) .
Algorithm:
- Verify collector_randomness_beacon for randomness_source .
- Build deterministic active-slot list (sorted slot ids).
- Use seed -driven deterministic shuffle.
- Take first c unique slots as collectors.
Collectors responsibilities:
aggregate votes and build VoteQC ,
collect commit attestations and build CommitQC ,
- after CommitQC exists, submit one signed FinalizeSubmit to mainnet (no earlier mainnet traffic for vote/commit).
Fallback:
- if collector timeout expires, any host may take over submission with the same certificates.
Exact protocol (initiator, order, transport)
This section fixes who starts , in what order messages flow , and which path each message takes. It assumes state sharing (phase 1) has succeeded, participants share terminal state, and they hold a verified collector randomness beacon for the attempt (phase 2).
Initiator
- Who: Any host in the active participant set may initiate a finalization attempt for an escrow, provided it attaches valid trigger evidence for one of FinalizationTriggerReason (see Trigger reasons and required evidence ).
- What they send first: A signed FinalizeInit is the first message of a round . There is no separate “elected leader” in this draft: the first valid FinalizeInit that hosts accept for (escrow_id, round) under dedup / lock / unlock rules opens that round. (Policy may later add proposer rotation; this spec keeps initiation permissionless among honest hosts.)
- Round 1 : FinalizeInit with round = 1 and no unlock_timeout_certificate (first attempt for the escrow’s finalization flow).
- Round > 1 : FinalizeInit must include a valid unlock_timeout_certificate proving the immediately prior attempted round (or the round named in the certificate) exhausted without settlement — see unlock_timeout_certificate under FinalizeInit . Hosts reject a higher round without that proof if they are still locked from an earlier round (see Voting lock and multiple rounds ).
Message order (single round, happy path)
For a fixed (escrow_id, round) :
- FinalizeInit — one logical proposal per round (may be gossip-duplicated; verifiers dedup by message_hash ).
- FinalizeVote — each participating host sends at most one vote per (escrow_id, round) after validating FinalizeInit (including beacon verification).
- VoteQC — produced only by collectors after 2f+1 matching AGREE on the same finalization_hash ; collectors broadcast the compact QC to all hosts (same transport as other collector fan-out).
- FinalizeCommit — each host that accepts VoteQC sends at most one commit per (escrow_id, round) referencing that VoteQC (e.g. vote_qc_hash ), to the collectors only (no host-to-host commit gossip; see Transport ).
- CommitQC — collectors aggregate commits, broadcast compact CommitQC .
- FinalizeSubmit — one signed transaction to mainnet , sent by a collector (or fallback submitter after collector timeout) carrying VoteQC , CommitQC , and settlement fields.
Unhappy path: If step 3 never yields VoteQC (insufficient AGREE , all REJECT , or timeout), or step 5 never yields CommitQC , no mainnet submit occurs for that round. Hosts wait for unlock_timeout_certificate (or local timeout participation in forming it), then a new FinalizeInit with round := round + 1 may begin the next attempt.
Transport
Minimizing commit traffic: It is enough that FinalizeCommit goes only to collectors; that bounds commit fan-out to O(hosts × collector_count) instead of host-to-host flooding. No separate all-to-all commit path is required.
Evidence payloads: Large trigger_evidence_items SHOULD use hash + fetch after first advertisement; FinalizeInit carries roots and optional references consistent with Communication minimization .
Protocol messages
These messages implement phases 3–5 in Important to consider (after state sharing and randomness agreement ). They do not define state sharing or beacon ceremonies.
All messages must include:
escrow_id
round (monotonic uint64)
sender_slot
sender_sig
message_type
message_hash
FinalizeInit
Fields:
escrow_id
round
- randomness_source (enum): declares how to verify collector_randomness_beacon (see Collector randomness beacon ).
- collector_randomness_beacon (bytes): source-specific material mixed into the collector seed. Hosts reject FinalizeInit if verification fails for the declared source or if the beacon diverges from their locally verified value for this escrow attempt (unless policy allows a defined tolerance). Collectors for the round are derived from FinalizationHash , this field, and randomness_source ( Deterministic collectors ).
- randomness_evidence (optional): source-specific proofs (e.g. height-sync LightBlock s, Pedersen opening transcripts) when not inferable from cached session state.
trigger_reason
trigger_evidence_root
trigger_evidence_items (or fetch references)
nonce_merkle_root
terminal_nonce
settlement_payload_hash
finalization_hash
- unlock_timeout_certificate : Omit on round = 1 . On round > 1 , required (see Exact protocol — Initiator ): quorum-signed (or policy-defined) proof that a prior round closed without successful settlement so this round may start. Must cover at least: (a) round r did not obtain CommitQC , and/or (b) round r did not obtain a valid VoteQC by deadline (vote phase failed). Exact encoding TBD; functionally a “round r exhausted” certificate.
Advancing rounds: To open round = r_new > 1 , the initiator includes unlock_timeout_certificate for the prior attempt (typically r_new - 1 ) unless chain policy defines a different mapping. Hosts verify the certificate before accepting the new FinalizeInit if they hold a lock from an earlier round.
Height sync alias: when randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT , collector_randomness_beacon is uint64_be(aligned_mainnet_height) from Height sync protocol (https://github.com/gonka-ai/gonka/discussions/1340) . Older drafts named this field aligned_mainnet_height on the message; the beacon bytes are the canonical encoding.
FinalizeVote
Fields:
escrow_id
round
finalization_hash
vote ( AGREE / REJECT )
reject_code (optional)
reject_evidence_hash (optional)
VoteQC
Produced by collectors after 2f+1 matching AGREE votes. Gossiped to all hosts after aggregation. Included in FinalizeSubmit to mainnet.
Fields:
escrow_id
round
finalization_hash
vote_signers_bitmap
aggregated_vote_signature (or explicit sig list)
vote_count
FinalizeCommit
Sent by hosts to collectors only after validating VoteQC (not gossiped host-to-host; see Exact protocol — Transport ).
Fields:
escrow_id
round
finalization_hash
vote_qc_hash
commit ( COMMIT )
CommitQC
Produced by collectors after commit threshold.
Fields:
escrow_id
round
finalization_hash
vote_qc_hash
commit_signers_bitmap
aggregated_commit_signature (or explicit sig list)
commit_count
FinalizeSubmit (to mainnet)
Fields:
escrow_id
round
randomness_source
- collector_randomness_beacon : must match the accepted FinalizeInit for this (escrow_id, round) so the keeper (and auditors) can re-derive the collector set with FinalizationHash .
- randomness_evidence (optional): same role as on FinalizeInit if mainnet cannot rely on prior session cache.
trigger_reason
trigger_evidence_root
nonce_merkle_root
terminal_nonce
settlement_payload
finalization_hash
vote_qc
commit_qc
Voting lock and multiple rounds
Rule:
- A host that sent FinalizeVote AGREE in round r for finalization_hash H is locked on (r, H) .
- Host must not send a second conflicting FinalizeVote for the same (escrow_id, r) .
- Host may accept FinalizeInit for r_new > r and vote again only if unlock_timeout_certificate (and any stricter chain policy) shows round r exhausted without settlement — so advancing the round is justified , not an arbitrary view flip.
Changing finalization_hash in a later round: Implementations SHOULD require unlock_timeout_certificate before accepting FinalizeInit with a different finalization_hash than the hash the host previously voted AGREE for, so a dishonest initiator cannot bounce honest voters between conflicting proposals without a timed-out or failed prior round.
Practical per-host state:
- locked_round , locked_hash after an AGREE vote until unlock or successful mainnet settlement for the escrow.
- On FinalizeInit(r_new) : if r_new > locked_round , require valid unlock_timeout_certificate covering the stalled round(s) per policy; then update lock when voting in r_new .
Retry without bumping round (optional optimization): If VoteQC exists but CommitQC never forms, an implementation MAY re-gossip VoteQC and run another FinalizeCommit wave at the same round instead of incrementing round . This doc’s default is round monotonicity + new FinalizeInit with unlock_timeout_certificate so every retry is explicitly opened.
No double finalization (idempotency)
Subnet gossip may deliver the same FinalizeSubmit material many times, and several collectors are allowed to broadcast/submit. Settlement must still happen at most once per escrow on mainnet.
Guarantees come from application-level rules in the keeper , not from the vote/commit protocol alone:
- Terminal escrow state: The chain stores each escrow_id in a lifecycle (e.g. ACTIVE → SETTLED / CLOSED ). The handler rejects any finalize message if that escrow is already settled (or already aborted under a defined dispute path). This is the primary “never twice” gate.
Terminal escrow state: The chain stores each escrow_id in a lifecycle (e.g. ACTIVE → SETTLED / CLOSED ). The handler rejects any finalize message if that escrow is already settled (or already aborted under a defined dispute path). This is the primary “never twice” gate.
- Optional digest bind: The keeper MAY record last_finalization_hash (or settled_terminal_nonce + payload commitment) for the escrow and reject a second submission that differs (conflicting retry). A byte-identical replay of the same valid submission should be rejected as duplicate or treated as no-op (idempotent success), so collectors racing on the same certificates do not double-apply effects.
Optional digest bind: The keeper MAY record last_finalization_hash (or settled_terminal_nonce + payload commitment) for the escrow and reject a second submission that differs (conflicting retry). A byte-identical replay of the same valid submission should be rejected as duplicate or treated as no-op (idempotent success), so collectors racing on the same certificates do not double-apply effects.
- Same certificates, one effect: VoteQC and CommitQC tie submission to a single finalization_hash . Honest hosts only sign one committed outcome per successful round; two different outcomes would need different hashes and could not both pass unless the chain allowed a second round — which must still respect (1).
Same certificates, one effect: VoteQC and CommitQC tie submission to a single finalization_hash . Honest hosts only sign one committed outcome per successful round; two different outcomes would need different hashes and could not both pass unless the chain allowed a second round — which must still respect (1).
- Tx-level dedup: Cosmos SDK sequence / mempool dedup prevents the same signed tx from executing twice; distinct txs repeating the same settlement must still fail at (1)–(2).
Tx-level dedup: Cosmos SDK sequence / mempool dedup prevents the same signed tx from executing twice; distinct txs repeating the same settlement must still fail at (1)–(2).
The commit phase prevents conflicting finals from being signed by a quorum without a new round and unlock rules; mainnet idempotency prevents repeated application of settlement for the same escrow.
Mainnet interaction: single round-trip
Vote and commit phases are devshard-local only. FinalizeInit and collector-originated QCs use subnet gossip; FinalizeCommit is collector-directed only (see Transport ). There is no message to mainnet while those phases run — no “report vote QC” or “report commit QC” as separate chain transactions.
One chain interaction: when the subnet is done, a collector (or fallback submitter) broadcasts a single signed FinalizeSubmit transaction that includes settlement payload, randomness fields, VoteQC , CommitQC , and all fields needed to recompute finalization_hash . The node returns tx success (settlement applied) or failure (validation error → rejected).
Why not more mainnet steps: Intermediate “vote verified” / “commit verified” events would imply extra devshard↔mainnet traffic and do not add safety if the keeper only applies state on the final accepted message. Verification of VoteQC and CommitQC happens inside that one handler.
Events (for devshard hosts, not extra round-trips): The keeper should emit Cosmos events on outcome so every devshard host can learn the result by watching the chain , even if the submitting collector crashes before gossiping success back:
- finalization_settled — include escrow_id , finalization_hash , and any index fields needed for wallets/indexers.
- finalization_rejected — include escrow_id , finalization_hash (if parseable), and reason code / error class.
Optional: one generic finalization_outcome with an enum SETTLED | REJECTED instead of two event types. Do not emit separate chain events that mirror internal vote vs commit checks unless a product need requires auditing (that can stay in logs, not p2p to mainnet).
Mainnet verification changes
Mainnet handler must reject finalize submissions unless:
- finalization_hash recomputes exactly from payload and evidence.
- randomness_source and collector_randomness_beacon are present; beacon verifies under the declared source; optional strict check that signers in VoteQC / CommitQC are exactly the collector set from H(FinalizationHash || randomness_source || collector_randomness_beacon || "collectors") if the chain verifies collector membership.
- Trigger evidence is valid for the declared reason (independent checks — e.g. USER_TIMEOUT height-sync sections, EPOCH_CHANGE_IMMINENT header proof).
- VoteQC is valid and meets threshold 2f+1 .
- CommitQC is valid, references VoteQC , and meets threshold 2f+1 (or configured commit threshold).
- Round and replay checks pass ( escrow_id , round monotonicity, no duplicate finalization hash).
- Idempotency: escrow not already settled per No double finalization above; duplicate or conflicting resubmission rules enforced.
Items 4–5 are in-memory checks inside this single tx , not separate mainnet messages.
Communication minimization
- Hosts send FinalizeVote to collectors (directed or collector-addressed relay); FinalizeCommit is collectors only — no host-to-host commit gossip (sufficient to cap commit traffic).
- Collectors aggregate and broadcast only compact VoteQC / CommitQC .
- Evidence blobs transferred by reference (hash+fetch) after first propagation.
- Dedup by (escrow_id, round, message_hash) .
Open questions
state sharing before finalization proposal is committed,
- Pedersen commitment ceremony: exact posting phase, aggregation, opening rules, and mainnet verification for randomness_source = PEDERSEN_COMMITMENT ,
default randomness source per escrow / chain param (height sync vs Pedersen vs hybrid),
aggregated BLS,
evidence retention duration and pruning guarantees,
- whether REJECT path should also produce commit certificates for deterministic default settlement.
Резюме
Это предложение определяет полный протокол финализации, в котором любой хост может начать финализацию (не только пользователь/программист) с явными доказательствами срабатывания, детерминированным выбором сборщика, безопасностью на этапе фиксации и требованиями проверки основной сети.
Он предназначен для:
сохранить безопасность при византийском поведении,
разрешить ход финализации, когда пользователь не в сети или мошенничает,
уменьшить поток сообщений с помощью детерминированного набора сборщиков,
Похожие предложения:
Важно учитывать
Никаких сплетен как ворота доработки. В соответствии с моделью, на которую нацелено это предложение, мы не полагаемся на принцип «сначала сплетни, а затем доработка». Какая бы среда выполнения ни существовала сегодня для разветвления nonce во время нормального выполнения, здесь не указано как способ выравнивания хостов непосредственно перед финализацией.
Nonce ↔ расписание исполнителя (гипотеза). Со строгой привязкой между nonce и хостом-исполнителем (например. N хостов в фиксированном порядке): если хост A выполнил nonce NoID , то хост A снова запланирован на nonce NoID + N и так далее. После полного цикла N последовательных одноразовых номеров каждый хост выполнил один шаг. Открытое предположение: это означает, что каждый другой хост знает об одной и той же линейной истории (или может получить ее) без дополнительного обмена сообщениями. Прежде чем строить на этом аргументы в пользу безопасности, это должно быть подтверждено точными правилами планирования, транспортировки и хранения.
Совместное использование состояний осуществляется отдельно. Для финализации необходим явный протокол совместного использования состояния (что обменивать, кто что доказывает, как обнаружить задержку или форк). Это принадлежит другому документу предложения (не этому файлу). Это предложение описывает голосование/фиксацию/основную сеть только после успешного разделения состояния.
Случайность коллектора не связана с разделением состояний. Перед этапами 2–4 участники должны договориться о маяке случайности сборщиков — общедоступных материалах, смешанных с начальным числом отбора коллекционеров, чтобы ни один инициатор не мог выбрать подходящие агрегаторы. Синхронизация по высоте не является обязательным условием финализации. Когда используется протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340), его роль здесь заключается только в создании этого маяка (обычно выровненная высота основной сети после проверенных LightBlock s). Другие схемы детерминированной случайности в равной степени действительны, если они соответствуют требованиям маяка случайности коллектора (например, открытые значения из обязательств Педерсена, собранные во время сеанса).
Порядок этапов доработки. Сквозная доработка – это:
Фазы 1–2 могут проходить как одна объединенная церемония или как отдельные этапы; Схемы сообщений ниже соответствуют этапам 3–5. Фаза 1 здесь выходит за рамки в ожидании спецификации совместного использования состояния.
Цели
Причины и необходимые доказательства
FinalizationTriggerReason:
ПОЛЬЗОВАТЕЛЬ_CHEATING
EPOCH_CHANGE_IMMINENT
USER_TIMEOUT
Свидетельство триггера не зависит от маяка случайности коллектора, за исключением случаев, когда один и тот же механизм синхронизации по высоте обеспечивает оба (см. USER_TIMEOUT ).
1) ПОЛЬЗОВАТЕЛЬ_CHEATING
Требуемые доказательства:
конфликтующие подписанные фрагменты одновременно (форк/двусмысленность),
неверный переход последовательности с подписью пользователя,
Каждый предмет доказательств должен включать в себя:
необработанные подписанные байты полезной нагрузки,
подпись пользователя,
nonce/высота/контекст темы,
2) EPOCH_CHANGE_IMMINENT
Требуемые доказательства:
При этом для триггера используются доказательства заголовка основной сети, а не маяк случайности сборщика.
3) ПОЛЬЗОВАТЕЛЬ_ТАЙМ-АУТ
Требуемые доказательства:
Тайм-аут рассчитывается по:
Формат конверта, доказательства и подписи определены в: Протокол синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340) (структурированное тело HTTP: раздел высоты + раздел сообщения).
Примечание. Синхронизация по высоте здесь доказывает отсутствие активности пользователя для триггера. Само по себе это не оправдывает обработку выровненной высоты основной сети как глобальных часов финализации, если только это же значение не будет также принято как Collector_randomness_beacon в случайном_источнике = HEIGHT_SYNC_ALIGNED_HEIGHT.
Депонирование, привязанное к эпохе: валидаторы L1 от участников эпохи
Если срок службы подсети ограничен одной эпохой основной сети и подсеть завершается при переключении эпохи (в соответствии с политикой перехода EPOCH_CHANGE_IMMINENT/эпохи), запуск условного депонирования не обязательно должен включать набор валидаторов L1. Валидаторы CometBFT, которые могут подписывать блоки в течение этой эпохи, определяются участниками эпохи основной сети (каноническое состояние в цепочке; точный модуль/запрос подлежит уточнению). Каждый хост загружает этот список участников один раз за эпоху, преобразует записи в адреса консенсусных валидаторов Cosmos/CometBFT (тот же вывод, что и в блоках), кэширует их и использует результат для вычисления ожидаемого validators_hash на высоте H при проверке LightBlock (например, в доказательствах USER_TIMEOUT или когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT) на шаге 3b в протоколе синхронизации высоты. (https://github.com/gonka-ai/gonka/discussions/1340), поэтому одноранговые LightBlock не могут использовать изготовленный набор валидаторов.
Создание условного депонирования по-прежнему может определять, какая эпоха применяется (например, с помощью высоты создания или дополнительного поля epoch_id) без дублирования ключей валидатора в стартовом сообщении.
Обязательство состояния и хеш завершения
Чтобы избежать двусмысленности и обеспечить детерминированный выбор коллектора, определите:
NonceLeaf_i = H(nonce_i || state_hash_i || tx_digest_i)
NonceMerkleRoot = MerkleRoot(NonceLeaf_1..NonceLeaf_N) (упорядочено по nonce)
Затем дайджест кандидата на доработку:
FinalizationHash = H(escrow_id || round || триггер_причина || триггер_evidence_hash || nonce_merkle_root || терминал_nonce || Settlement_payload_hash)
Trigger_evidence_hash — это корень Merkle для всех элементов триггерных доказательств.
Маяк случайности коллектора не является частью этого дайджеста. Он переносится в FinalizeInit (и отображается в FinalizeSubmit) и смешивается только с начальным числом выбора сборщика (см. Детерминированные сборщики). Отсутствие случайности в FinalizationHash позволяет одному и тому же предложению состояния терминала использовать разные источники или раунды маяков, при этом привязывая голоса/фиксации к одной полезной нагрузке расчета.
Обоснование:
Незавершенная работа на стадии доработки
Когда начинается финализация (состояние завершения раунда фиксировано), протокол применяет детерминированные значения по умолчанию, поэтому расчет всегда закрывается:
Эти правила применяются во время совместного использования состояния при построении представления терминала, которое передает FinalizationHash. Все хосты должны применять одни и те же значения по умолчанию, чтобы поля nonce_merkle_root и payout совпадали. Споры о правильности расчетов (если таковые имеются) выходят за рамки настоящего протокола голосования/фиксации.
Коллекторный маяк случайности
Детерминистическим сборщикам нужен общий источник псевдослучайности, который:
Синхронизация высоты удовлетворяет условиям (1)–(3) при использовании только в качестве источника случайности: стороны запускают правила конвергенции синхронизации высоты из протокола синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340) и принимают полученную выровненную высоту основной сети в качестве материала маяка. Эта высота не требуется для финализации, поскольку хосты должны «согласовать подсказку L1» в целом — она требуется только в той мере, в какой выбранная схема случайности использует ее.
Поддерживаемые источники (расширяемое перечисление)
Реализации выбирают один источник для каждого условного депонирования или каждого параметра цепочки. FinalizeInit должен объявить источник, чтобы верификаторы не предполагали синхронизацию высоты при использовании другой церемонии.
Почему бы не использовать только FinalizationHash?
FinalizationHash фиксируется по предложению инициатора. Без внешней случайности начальное значение = H(FinalizationHash || «коллекторы») полностью предсказуемо для инициатора, который может пробовать альтернативные представления доказательств/состояний до тех пор, пока сборщики не отдадут предпочтение своему слоту. Маяк разрушает эту шлифовку.
Детерминированные коллекторы
Коллекторы выбираются из активных слотов с помощью FinalizationHash, randomness_source и Collector_randomness_beacon из FinalizeInit (одна и та же тройка, которую каждый хост и основная сеть должны использовать в раунде).
Параметры:
Collector_count = c (например, c=3 или c=5, параметр цепочки)
семя выбора: семя = H(FinalizationHash || случайный_источник || коллектор_рандомность_маяк || "коллекторы")
семя = H(FinalizationHash || источник_рандомизма || коллектор_рандомность_маяк || "коллекторы")
Хэш H — это та же функция, которая используется в других местах этого предложения (например, Хеш финализации). Детерминированное «случайное» перемешивание: начальное число фиксирует псевдослучайную перестановку слотов; все верификаторы получают один и тот же набор сборщиков без дополнительных сообщений.
Эталонное кодирование для синхронизации по высоте: когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT, Collector_randomness_beacon ДОЛЖЕН быть 8-байтовым выравниванием_mainnet_height с прямым порядком байтов из протокола синхронизации по высоте (https://github.com/gonka-ai/gonka/discussions/1340).
Алгоритм:
Обязанности коллекторов:
агрегировать голоса и строить VoteQC,
собирать аттестации коммитов и строить CommitQC,
Резервный вариант:
Точный протокол (инициатор, заказ, транспорт)
В этом разделе указывается, кто запускает, в каком порядке передаются сообщения и по какому пути проходит каждое сообщение. Предполагается, что разделение состояния (этап 1) прошло успешно, участники совместно используют состояние терминала и имеют проверенный маяк случайности коллектора для попытки (этап 2).
Инициатор
Порядок сообщений (один раунд, счастливый путь)
Для фиксированного (escrow_id, round):
Несчастливый путь: если шаг 3 никогда не дает результата VoteQC (недостаточно AGREE , все REJECT или тайм-аут) или шаг 5 никогда не дает CommitQC , в этом раунде не происходит отправки в основную сеть. Хосты ждут unlock_timeout_certificate (или участия локального таймаута в его формировании), затем новый FinalizeInit с round := round + 1 может начать следующую попытку.
Транспорт
Минимизация трафика коммитов: достаточно, чтобы FinalizeCommit отправлялся только сборщикам; это ограничивает разветвление фиксации до O(hosts ×collector_count) вместо лавинной рассылки между хостами. Никакого отдельного пути фиксации «все ко всем» не требуется.
Полезные данные доказательств: большие триггер_evidence_items ДОЛЖНЫ использовать хэш + выборку после первого объявления; FinalizeInit содержит корни и дополнительные ссылки, соответствующие минимизации связи.
Протокольные сообщения
Эти сообщения реализуют этапы 3–5 раздела «Важно учитывать» (после соглашения о совместном использовании состояний и случайности). Они не определяют разделение штатов или церемонии вручения маяков.
Все сообщения должны содержать:
escrow_id
круглый (монотонный uint64)
отправитель_слот
sender_sig
тип_сообщения
message_hash
Финализеинит
Поля:
escrow_id
круглый
триггер_причина
триггер_evidence_root
триггер_evidence_items (или получить ссылки)
nonce_merkle_root
терминал_нонсе
Settlement_payload_hash
Finalization_hash
Продвижение раундов: чтобы открыть round = r_new > 1, инициатор включает unlock_timeout_certificate для предыдущей попытки (обычно r_new - 1), если политика цепочки не определяет другое сопоставление. Хосты проверяют сертификат перед принятием нового FinalizeInit, если они удерживают блокировку из предыдущего раунда.
Псевдоним синхронизации высоты: когда randomness_source = HEIGHT_SYNC_ALIGNED_HEIGHT, Collector_randomness_beacon равен uint64_be(aligned_mainnet_height) из протокола синхронизации высоты (https://github.com/gonka-ai/gonka/discussions/1340). В более старых черновиках это поле в сообщении называлось Align_mainnet_height; байты маяка представляют собой каноническую кодировку.
Завершить голосование
Поля:
escrow_id
круглый
Finalization_hash
голосовать ( СОГЛАСЕН / ОТКЛОНЕН )
код_отклонения (необязательно)
ignore_evidence_hash (необязательно)
ГолосоватьQC
Произведено коллекционерами после 2f+1 совпадения голосов AGREE. Распространен на все хосты после агрегации. Включено в FinalizeSubmit в основную сеть.
Поля:
escrow_id
круглый
Finalization_hash
voice_signers_bitmap
агрегированный_vote_signature (или список явных подписей)
voice_count
Завершить фиксацию
Отправляется хостами сборщикам только после проверки VoteQC (не передается между хостами; см. Точный протокол — Транспорт).
Поля:
escrow_id
круглый
Finalization_hash
voice_qc_hash
зафиксировать (СОВЕРШИТЬ)
CommitQC
Создается сборщиками после достижения порога фиксации.
Поля:
escrow_id
круглый
Finalization_hash
voice_qc_hash
commit_signers_bitmap
агрегированный_commit_signature (или список явных подписей)
commit_count
FinalizeSubmit (в основную сеть)
Поля:
escrow_id
круглый
случайный_источник
триггер_причина
триггер_evidence_root
nonce_merkle_root
терминал_нонсе
Settlement_payload
Finalization_hash
voice_qc
commit_qc
Блокировка голосования и несколько туров
Правило:
Изменение Finalization_hash в более позднем раунде: Реализации ДОЛЖНЫ требовать unlock_timeout_certificate перед принятием FinalizeInit с другим Finalization_hash, отличным от хеша, за который хост ранее проголосовал AGREE, поэтому нечестный инициатор не может перенаправлять честных избирателей между конфликтующими предложениями без истечения времени ожидания или неудачного предыдущего раунда.
Практическое состояние каждого хоста:
Повторить попытку без повторного раунда (необязательная оптимизация): если VoteQC существует, но CommitQC никогда не формируется, реализация МОЖЕТ повторно передать VoteQC и запустить еще одну волну FinalizeCommit в том же раунде вместо увеличения round . По умолчанию в этом документе используется круглая монотонность + новый FinalizeInit с unlock_timeout_certificate, поэтому каждая повторная попытка явно открывается.
Нет двойной финализации (идемпотентность)
Сплетни в подсети могут доставлять один и тот же материал FinalizeSubmit много раз, и нескольким сборщикам разрешено транслировать/отправлять его. Расчет по-прежнему должен происходить не более одного раза за каждое условное депонирование в основной сети.
Гарантии исходят из правил уровня приложения в keeper , а не только из протокола голосования/фиксации:
Состояние условного депонирования терминала: цепочка хранит каждый escrow_id в жизненном цикле (например, АКТИВ → УСТАНОВЛЕНО / ЗАКРЫТО). Обработчик отклоняет любое сообщение завершения, если это условное депонирование уже оплачено (или уже прервано по определенному пути спора). Это основные ворота «никогда дважды».
Необязательная привязка дайджеста: хранитель МОЖЕТ записать Last_finalization_hash (или Settled_terminal_nonce + обязательство по полезной нагрузке) для условного депонирования и отклонить вторую отправку, которая отличается (конфликтующая повторная попытка). Байт-идентичное воспроизведение одной и той же действительной отправки должно быть отклонено как дубликат или рассматриваться как недействующее (идемпотентный успех), чтобы сборщики, участвующие в гонках с одними и теми же сертификатами, не применяли эффекты дважды.
Те же сертификаты, один эффект: VoteQC и CommitQC связывают отправку с одним Finalization_hash. Честные хозяева подписывают только один гарантированный результат за успешный раунд; для двух разных результатов потребуются разные хеши, и они не смогут пройти оба, если цепочка не разрешит второй раунд, который все равно должен соблюдать (1).
Дедупликация на уровне передачи: дедупликация последовательности/пула памяти Cosmos SDK предотвращает двукратное выполнение одной и той же подписанной передачи; отдельные транзакции, повторяющие один и тот же расчет, все равно должны завершиться неудачей в (1)–(2).
Фаза фиксации предотвращает подписание кворумом конфликтующих финалов без нового раунда и правил разблокировки; Идемпотентность основной сети предотвращает повторное применение расчетов для одного и того же условного депонирования.
Взаимодействие с основной сетью: одиночный проход туда и обратно
Фазы голосования и фиксации выполняются только на уровне devshard-local. FinalizeInit и контроль качества, созданные сборщиком, используют слухи о подсети; FinalizeCommit управляется только сборщиком (см. Транспорт). Во время выполнения этих этапов в основную сеть не поступает никаких сообщений — нет «отчета о голосовании по контролю качества» или «отчета о подтверждении контроля качества» как отдельных транзакций цепочки.
Одно цепное взаимодействие: когда подсеть завершена, сборщик (или резервный отправитель) передает одну подписанную транзакцию FinalizeSubmit, которая включает в себя полезную нагрузку расчета, поля случайности, VoteQC, CommitQC и все поля, необходимые для повторного вычисления Finalization_hash. Узел возвращает успешную передачу (расчет применен) или неудачу (ошибка проверки → отклонено).
Почему бы не увеличить количество шагов в основной сети: промежуточные события «голосование подтверждено» / «проверено подтверждение» будут подразумевать дополнительный трафик devshard↔ в основной сети и не повышать безопасность, если хранитель применяет состояние только к окончательному принятому сообщению. Проверка VoteQC и CommitQC происходит внутри этого одного обработчика.
События (для хостов devshard, а не дополнительные круговые обходы): хранитель должен генерировать события Cosmos по результатам, чтобы каждый хост devshard мог узнать результат, наблюдая за цепочкой, даже если отправляющий сборщик выйдет из строя, прежде чем сообщить об успехе:
Необязательно: один общий Finalization_outcome с перечислением SETLED | REJECTED вместо двух типов событий. Не создавайте отдельные события цепочки, которые отражают внутренние проверки голосования и фиксации, если только потребность продукта не требует аудита (который может оставаться в журналах, а не через p2p в основную сеть).
Изменения проверки в основной сети
Обработчик основной сети должен отклонять отправки финализации, если:
Пункты 4–5 — это проверки в памяти внутри одного tx, а не отдельных сообщений основной сети.
Минимизация связи
Открытые вопросы
сообщить о совместном использовании до того, как будет принято окончательное предложение,
агрегированные BLS,
продолжительность хранения доказательств и гарантии сокращения,