В первый раз, когда я прочитал собственный пример из протокола для медианного консенсуса, он выглядел как сноска. Три оператора, три числа, одна медиана — готово. Потребовался второй проход, честно говоря, чтобы заметить, что именно эта сноска на самом деле признаёт.
Протокол — это Newton, и механизм настолько прост, что его можно объяснить одним предложением. В том, что Ньютон называет фазой Prepare, Gateway отправляет newt_fetchPolicyData набору независимых операторов, каждый из которых должен получить одно и то же внешнее значение — цену, баланс, что угодно, что требуется политикой, — и затем сообщить обратно, не подписывая данные.
Собственная документация Ньютона разбирает это на примере трёх операторов, которые подтягивают ценовой фид: 100.0, 102.0, 101.0. Достаточно похоже, чтобы договориться, и достаточно различно, чтобы было видно, что никто не списывал. Gateway вычисляет медиану 101.0, проверяет, что каждое значение лежит в пределах 10‑процентного диапазона tolerance, и только после этого переводит раунд в фазу Commit, где newt_evaluateAndSign заставляет операторов подписать результат политики, построенный на этом одном общем числе.
Ни один из этих троих операторов не подписывает то, что он действительно увидел.
Я снова и снова возвращаюсь к этой строке, потому что это настолько конкретный выбор дизайна, стоит с ним пожить. Оператор 1 никогда не подписывает 100.0. То, что подписывается BLS на этапе Commit — это вычисление Gateway, медиана, а не сырое наблюдение какого‑либо оператора. Это не неряшливость — это принуждение математикой: агрегация подписи остаётся дешёвой on‑chain только если каждый подписант подписывает идентичное сообщение, а три по‑настоящему независимые выборки почти никогда не дадут один и тот же результат «сами по себе». Ньютон вырабатывает идентичное сообщение, отбрасывая различия ещё до того, как кто‑то подписывает. Сырые значения не исчезают полностью — они сохраняются в том, что в документации называется Full Digest, чтобы их можно было использовать для верификации при чэллендже. Но объект, который на самом деле несёт «вес» подписи, Consensus Digest, имеет индивидуальные аттестации обнулёнными.

Запись, собранная для споров, в итоге хранит больше правды, чем запись, собранная для консенсуса. Забавно, как так выходит.
На той же самой жёсткой одинаковости лежит и второй «ценник», и он проявляется только когда что‑то идёт не так. Ньютон не может тихо отбросить выброс и продолжить с теми операторами, которые согласны, — не нарушив правило об идентичном сообщении, от которого зависит BLS. Поэтому остаётся ровно два исхода: либо все попадают в диапазон tolerance, либо весь раунд проваливается с ToleranceExceeded. Никакого сценария, где два хороших оператора просто перевесят одного плохого.
Один устаревший фид. Неправильно настроенная конечная точка. Делиберательно неверное число. Ни одно из них не «перевесит» голосами остальных. Любое из них останавливает раунд для всех.
Отойди на секунду от механики и посмотри, к каким это выводам ведёт по стимулам. Ньютон задаёт порог квора на уровне 67 процентов от стейка операторов. Сеть операторов сама работает как EigenLayer AVS, так что этот стейк — это перевложенная безопасность, заимствованная у Ethereum, а не валидаторский набор, который протокол собрал с нуля. Математика квора устроена явно так, чтобы допускать существенное меньшинство стейка, не согласного с остальными, и всё равно прийти к консенсусу — при условии, что несогласие происходит на стадии подписания. Проверка медианы по tolerance стоит выше всего этого. Один оператор вне диапазона никогда не доходит до точки, где вообще применяется квора: раунд просто не доходит туда.
Вот та часть, которая у меня ещё не до конца уложилась. Ньютон описывает два условия «распила» — некорректную оценку и эвокацию (equivocation), и оба описывают, что происходит после того, как оператор подписывает что‑то. ToleranceExceeded срабатывает раньше — до того, как вообще существует какая‑либо подпись, которую можно было бы сравнить с политикой. Если отправлять число не из ожидаемого диапазона многократно, оператору это что‑то стоит помимо того пари, которое он и так бы держал, независимо? В документации не сказано. Если не стоит, то самый дешёвый способ сорвать раунд — не подделывать подпись и не ломать агрегацию BLS: оба этих шага рискуют реальным перевложенным капиталом, если их поймают. Всё сводится к запуску медленной ленты и предоставлению проверке tolerance сделать остальное.

Всё это не делает дизайн неправильным, и стоит сказать это прямо. Тихо отбросить того оператора, который не согласен, и продолжить с «чистой» медианой по остальным — это решило бы проблему зависаний и создало бы худшую: это полностью спрятало бы факт несогласия. Раунд, который «валится громко», сообщает всем наблюдающим сторонам, что конкретный вход расходился с остальными — это честнее, чем аккуратная медиана, которая молча исключает источник и «отчитывается», будто ничего не произошло. Хранение сырых значений в Full Digest, даже при том что их выкидывают из того, что подписывается, означает, что несогласие не стирается — оно просто переносится туда, где живут чэлленджи, а не туда, где живёт консенсус.
Так проваливается весь раунд из‑за одного ToleranceExceeded — это предохранитель от плохих данных, или просто более медленный и тихий способ, как один неверно настроенный оператор держит подпись всех остальных в заложниках? Похоже, зависит от того, ждёте ли вы это, или от того, чья лента сегодня попала за пределы диапазона.
