Enshrined zk-EVM. Перевод
Перевод
Это вольный перевод статьи: notes.ethereum.org/@vbuterin/enshrined_zk_evm.
Введение
Протоколы EVM второго уровня поверх Ethereum (L2), включая оптимистичные роллапы и zk-роллапы, зависят от верификации EVM. Однако это требует от них доверия к большой кодовой базе, и если в этой базе есть ошибка, то эти Виртуальные машины (ВМ) рискуют быть взломанными. Кроме того, это означает, что даже ZK-EVM, которые хотят оставаться полностью эквивалентными L1 EVM, должны иметь некоторую форму управления для копирования изменений в L1 EVM в свою собственную реализацию EVM.
Такая ситуация является неоптимальной, поскольку эти проекты копируют функциональность, которая уже существует в протоколе Ethereum, и где говернанс Ethereum уже отвечает за внесение обновлений и исправление ошибок: ZK-EVM, по сути, выполняет ту же работу, что и верификация блоков первого уровня Ethereum!
Более того, в ближайшие несколько лет ожидаем, что лёгкие клиенты (см. оригинал) будут становиться всё мощнее и мощнее и вскоре смогут использовать ZK-SNARK для полной верификации выполнения L1 EVM. В этот момент сеть Ethereum фактически будет иметь встроенный ZK-EVM.
И тогда возникает вопрос: почему бы не сделать этот ZK-EVM нативно доступным и для роллапов?
В этом посте опишем несколько версий "встроенного ZK-EVM", которые могут быть реализованы, а также рассмотрим компромиссы и проблемы проектирования, и причины, по которым не стоит двигаться в определённых направлениях. Плюсы реализации той или иной функции протокола должны быть взвешены в сравнении с преимуществами предоставления возможностей экосистеме и сохранения простоты базового протокола.
Какие ключевые свойства мы хотим получить от зафиксированного ZK-EVM?
Основная функциональность: верификация блоков Ethereum. Функция протокола (пока остаётся открытым вопрос о том, будет ли это опкод, прекомпиляция или другой механизм) должна принимать на вход (как минимум) корень с пред-состоянием, блок и корень с пост-состоянием и проверять, что корень с пост-состоянием действительно является результатом выполнения блока поверх корня с пред-состоянием.
Совместимость с философией много-клиентности Ethereum. Это означает, что мы хотим избежать закрепления единой системы доказательств, а вместо этого позволить разным клиентам использовать разные системы доказательств. Из этого, в свою очередь, вытекает несколько моментов:
- Требование доступности данных: для любого выполнения EVM, которое доказывается с помощью зафиксированной ZK-EVM, мы хотим получить гарантию доступности базовых данных, чтобы доказатели, использующие другую систему доказательств, могли повторно доказать выполнение, а клиенты, полагающиеся на эту систему доказательств, могли проверить эти вновь созданные доказательства.
- Доказательства живут вне EVM и блочной структуры данных (оффчейн): функция ZK-EVM не будет буквально принимать SNARK в качестве входа в EVM, поскольку разные клиенты будут ожидать SNARK разных типов. Вместо этого она может работать аналогично проверке блобов (см. смежный пример): транзакции могут включать в себя (пред-состояние, тело блока, пост-состояние) утверждения, которые должны быть доказаны, опкод или прекомпиляция могут получить доступ к содержимому этих стейтментов, а правила консенсуса клиента будут отдельно проверять наличие данных и наличие доказательства для каждого утверждения, которое делается в блоке.
Проверяемость. Если какое-либо выполнение будет доказано, мы хотим, чтобы базовые данные были доступны, чтобы, если что-то пойдёт не так, пользователи и разработчики могли их проверить. На практике это добавляет ещё одну причину, по которой требование доступности данных является важным.
Возможность модернизации. Если в конкретной схеме ZK-EVM обнаружится ошибка, мы хотим иметь возможность быстро её исправить. Это подразумевает, что для исправления не требуется хардфорк. Это добавляет ещё одну причину, по которой доказательства, живущие вне EVM и структуры данных блока, важны.
Поддержка почти-EVM. Часть привлекательности L2 заключается в возможности внедрять инновации на уровне исполнения и делать расширения EVM. Если ВМ данного L2 отличается от EVM лишь незначительно, было бы неплохо, если бы L2 мог использовать встроенный в протокол ZK-EVM для частей, идентичных EVM, и полагаться на свой собственный код для частей, которые отличаются. Это можно сделать, разработав функцию ZK-EVM таким образом, чтобы она позволяла вызывающей стороне указывать битовое поле или список опкодов или адресов, которые будут обрабатываться внешней таблицей, а не самим EVM. Мы также можем сделать газовые расходы открытыми для настройки в ограниченной (мере).
"Открытые" и "закрытые" много-клиентские системы
Философия многоклиентности - пожалуй, самое спорное требование в этом списке. Есть вариант отказаться от неё и сосредоточиться на одной схеме ZK-SNARK, что упростит дизайн, но ценой гораздо большего "философского поворота" для Ethereum (поскольку де-факто это будет отказ от давней философии много-клиентности Ethereum) и ценой внесения больших рисков. В долгосрочной перспективе, когда, например, технология формальной верификации станет намного лучше, возможно, будет проще пойти по этому пути, но пока риски кажутся слишком большими.
Другой вариант - закрытая много-клиентская система, где существует фиксированный набор систем доказательства, который известен в рамках протокола. Например, можем (так) решить, что используем три ZK-EVM: PSE ZK-EVM, Polygon ZK-EVM и Kakarot. Чтобы блок был действительным, он должен иметь доказательства от двух из этих трёх (систем). Это лучше, чем одна система доказательств, но делает (всю) систему менее адаптируемой, поскольку пользователям придётся поддерживать верификаторы для каждой существующей системы доказательств, неизбежно возникнет процесс управления для включения новых систем доказательств и т. д.
Поэтому предпочитаю открытую много-клиентскую систему, где доказательства размещаются "вне блока" и проверяются клиентами отдельно. Отдельные пользователи могли бы использовать любой клиент для верификации блоков, и они могли бы делать это до тех пор, пока есть хотя бы один доказатель, создающий доказательства для этой доказательной системы. Доказательные системы будут приобретать влияние, убеждая пользователей запускать их, а не убеждая процесс управления протоколом. Однако, как увидим, такой подход связан с большими издержками.
Какие ключевые свойства мы хотим получить от реализаций ZK-EVM?
Наиболее важным свойством, помимо базовых гарантий корректной функциональности и безопасности, является скорость. Хотя можно разработать внутри-протокольную функцию ZK-EVM, которая будет асинхронной, возвращая ответ на каждое утверждение только после задержки в N слотов, проблема станет намного проще, если сможем точно (надёжно) гарантировать, что доказательство может быть сгенерировано в течение нескольких секунд, так что всё, что происходит в каждом блоке, является самодостаточным.
Хотя сегодня генерация доказательства для блока Ethereum занимает много минут или часов, мы знаем, что нет никаких теоретических причин, препятствующих массовому распараллеливанию: всегда можем собрать достаточно GPU для распределённого доказательства различных частей выполнения блока, а затем использовать рекурсивные SNARK для объединения доказательств. Кроме того, аппаратное ускорение с помощью FPGA и ASIC может помочь оптимизировать доказательство ещё больше. Однако достижение этой цели - серьёзная инженерная задача, которую не стоит недооценивать.
Как может выглядеть конкретная функция ZK-EVM в протоколе?
По аналогии с блоб-транзакциями EIP-4844 мы вводим новый тип транзакций, содержащих требования ZK-EVM:
class ZKEVMClaimTransaction(Container): pre_state_root: bytes32 post_state_root: bytes32 transaction_and_witness_blob_pointers: List[VersionedHash] ...
Как и в EIP-4844, объект, передаваемый в mempool, будет измененной версией транзакции:
class ZKEvmClaimNetworkTransaction(Container): pre_state_root: bytes32 post_state_root: bytes32 proof: bytes transaction_and_witness_blobs: List[Bytes[FIELD_ELEMENTS_PER_BLOB * 31]]
Последнее может быть преобразовано в первое, но не наоборот. Мы также расширяем объект блока sidecar (представленный в EIP-4844), чтобы он содержал список доказательств утверждений, выдвигаемых в блоке.
Обратите внимание, что на практике мы вполне можем захотеть разделить боковую ячейку на две отдельные ячейки, одну для блоков и одну для доказательств, и иметь отдельную подсеть для каждого типа доказательств (плюс дополнительную подсеть для блоков).
На уровне консенсуса добавляем правило проверки, согласно которому блок принимается только после того, как клиент увидел достоверное доказательство для каждого утверждения в блоке. Доказательство должно быть ZK-SNARK, доказывающим утверждение, что конкатенация transaction_and_witness_blobs является сериализацией пары (Block, Witness), и выполнение блока поверх pre_state_root с использованием Witness (i) является действительным, и (ii) выводит правильный post_state_root. Потенциально клиенты могут выбрать ожидание M-of-N из нескольких типов доказательств.
Философское замечание заключается в том, что само выполнение блока можно рассматривать как просто один из ( σ -p r e , σ- p o s t , Proof ) триплетов, которые необходимо проверить вместе с триплетами, предоставленными в объектах ZKEVMClaimTransaction.
Таким образом, пользовательская реализация ZK-EVM может заменить клиент выполнения; клиенты выполнения по-прежнему будут использоваться (i) проверяющими и создателями блоков, и (ii) узлами, которые заботятся об индексировании и хранении данных для локального использования.
Проверка и повторное доказательство
Предположим, что существуют два клиента Ethereum, один из которых использует PSE ZK-EVM, а другой - Polygon ZK-EVM. Предположим, что к этому моменту обе реализации продвинулись настолько, что могут доказать выполнение блока Ethereum в течение 5 секунд, и для каждой системы доказательства существует достаточно много независимых добровольцев, работающих с аппаратным обеспечением для генерации доказательства.
К сожалению, поскольку отдельные системы доказательств не закреплены, их нельзя стимулировать в рамках протокола; однако мы ожидаем, что стоимость работы доказательств будет низкой по сравнению с затратами на исследования и разработки, и поэтому можем просто финансировать доказательные системы, используя институты общего назначения для финансирования общественных благ.
Предположим, что кто-то публикует ZKEvmClaimNetworkTransaction, но публикует только версию доказательства для PSE ZK-EVM. Проверяющий узел ZK-EVM Polygon видит это, вычисляет и повторно публикует объект с доказательством для ZK-EVM Polygon.
Это увеличивает общую максимальную задержку между самым ранним честным узлом, принимающим блок, и самым поздним честным узлом, принимающим тот же блок, с δ к 2 δ + T p r o v e (предполагая, что здесь T p r o v e < 5 s ).
Хорошая новость, однако, заключается в том, что если примем однослотовое завершение, то почти наверняка сможем "конвейеризировать" эту дополнительную задержку вместе с многораундовыми задержками консенсуса, присущими SSF. Например, в этом предложении с 4 субслотами шаг "хэд-голосование" может потребовать только проверки достоверности базового блока, но затем шаг "замораживание и подтверждение" потребует наличия доказательства.
Расширение: поддержка "почти-EVM"
Одной из желательных целей для функции ZK-EVM является поддержка "почти-EVM": EVM, в которые встроено несколько дополнительных возможностей. Это могут быть новые прекомпиляции, новые опкоды, возможность написания контрактов либо в EVM, либо в совершенно другой ВМ (например, как в Arbitrum Stylus), или даже несколько параллельных EVM с синхронной перекрёстной связью.
Некоторые модификации могут быть поддержаны простым способом: мы можем определить язык, который позволяет ZKEVMClaimTransaction передавать полное описание модифицированных правил EVM. Это можно сделать для:
- Пользовательских таблиц стоимости газа (пользователям не разрешалось бы уменьшать стоимость газа, но они могли бы её увеличивать);
- Отключения определённых опкодов;
- Установка номера блока (что подразумевает различные правила в зависимости от хардфорка);
- Установка флага, активирующего целый набор изменений EVM, которые были стандартизированы для использования в L2, но не в L1, или другие более простые изменения.
Чтобы позволить пользователям добавлять новые возможности более открытым способом, вводя новые прекомпиляции (или опкоды), можем добавить транскрипт ввода/вывода прекомпиляции, включенный как часть блоба в ZKEVMClaimNetworkTransaction:
class PrecompileInputOutputTranscript(Container): used_precompile_addresses: List[Address] inputs_commitments: List[VersionedHash] outputs: List[Bytes]
Выполнение EVM будет изменено следующим образом. Массив inputs инициализируется пустым. При i-м вызове адреса из used_precompile_addresses мы добавляем к inputs объект InputsRecord(callee_address, gas, input_calldata) и устанавливаем RETURNDATA вызова в outputs[i]. В конце проверяем, что used_precompile_addresses были вызваны в общей сложности len(outputs) раз, и что inputs_commitments соответствует результату генерации блоб-коммитов для SSZ-сериализации inputs.
Цель раскрытия inputs_commitments заключается в том, чтобы внешнему SNARK было легко доказать связь между входами и выходами.
Обратите внимание на асимметрию между входами, которые хранятся в хэше, и выходами, которые хранятся в байтах, которые должны быть доступны. Это связано с тем, что выполнение должно быть доступно клиентам, которые видят только входные данные и понимают EVM. Исполнение (в) EVM уже генерирует входные данные для них, поэтому им нужно только проверить, что сгенерированные входные данные совпадают с заявленными, что требует только проверки хэша. Однако выходные данные должны быть предоставлены им в полном объёме, а значит, должны быть доступны.
Ещё одной полезной функцией может стать разрешение "привилегированных транзакций", которые совершают вызовы с произвольных учётных записей отправителей. Эти транзакции могут выполняться либо между двумя другими транзакциями, либо во время другой (возможно, также привилегированной) транзакции, когда вызывается предварительная компиляция. Это может быть использовано для того, чтобы позволить механизмам, не относящимся к EVM, самостоятельно обращаться к EVM.
Эта конструкция может быть модифицирована для поддержки новых или модифицированных опкодов в дополнение к новым или модифицированным прекомпиляциям. Даже при использовании только прекомпиляторов эта конструкция довольно мощная. Например:
- Установив used_precompile_addresses в список адресов обычных счетов, у которых в состоянии установлен какой-то флаг в объекте счёта, и сделав SNARK для доказательства того, что он был построен правильно, вы могли бы поддерживать функцию в стиле Arbitrum Stylus, где контракты могли бы иметь свой код, написанный либо в EVM, либо в WASM (см. также) (или другой VM). Привилегированные транзакции могут быть использованы для того, чтобы позволить учётным записям WASM обращаться обратно в EVM.
- Добавив внешнюю проверку верности (правильности) совпадения входных/выходных транскриптов и привилегированных транзакций нескольких исполнений EVM, сможете (собрать) доказательство (для) параллельные систем из нескольких EVM, которые общаются друг с другом по синхронному каналу.
- ZK-EVM четвертого типа может работать, имея несколько реализаций: одну, которая преобразует Solidity или другой язык более высокого уровня в виртуальную машину, дружественную SNARK, и другую, которая компилирует его в EVM-код и исполняет в зафиксированной ZK-EVM. Вторая (неизбежно более медленная) реализация может быть запущена только в том случае, если проверяющий посылает транзакцию с утверждением о наличии ошибки, получая вознаграждение, если он сможет предоставить транзакцию, которую эти два варианта обрабатывают по-разному.
- Чисто асинхронную ВМ можно реализовать, заставив все вызовы возвращать нуль и сопоставив вызовы с привилегированными транзакциями, добавляемыми в конец блока.
Расширение: поддержка доказательств с состоянием
Одна из проблем вышеописанной конструкции заключается в том, что она полностью лишена статичности, что делает её неэффективной в отношении данных. При идеальном сжатии данных отправка ERC-20 может занимать в 3 раза больше места при сжатии с сохранением состояния по сравнению со сжатием без сохранения состояния.
Кроме того, EVM с состоянием не нужно предоставлять данные о свидетелях (witness). В обоих случаях принцип один и тот же: не стоит требовать доступности данных, если уже знаем, что они доступны, поскольку были введены в предыдущих исполнениях EVM или получены в результате их работы.
Если хотим сделать функцию ZK-EVM открытой (к состояниям), то у нас есть два варианта:
- Требовать σ p r e либо быть пустым, либо быть доступным для данных списком заранее объявленных ключей и значений, либо быть σ p o s t (для) предыдущего выполнения.
- Добавить блоб-обязательство к квитанции R, сгенерированную блоком ( σ p r e , σ p o s t , Proof ) в кортеж. Любые ранее созданные или использованные блоб-обязательства, включая те, которые представляют блоки, свидетелей, квитанции или даже обычные блоб-транзакции EIP-4844, возможно, с некоторым временным ограничением, могут быть упомянуты в ZKEVMClaimTransaction и доступны во время её выполнения (возможно, через серию инструкций: "вставить байты N...N+k-1 из обязательства i в позицию j блока+свидетельских данных").
[Вариант] (1), по сути, говорит: вместо того чтобы закреплять верификацию EVM без состояния, будем закреплять под-цепочки EVM. [Вариант] (2) - создание минимального встроенного алгоритма сжатия с сохранением состояния, который использует ранее использованные или сгенерированные блобы в качестве словаря. Оба варианта накладывают на узлы проверки, и только на узлы проверки, бремя хранения дополнительной информации; в случае (2) это бремя легче сделать ограниченным по времени, чем в случае (1).
Аргументы в пользу закрытых мульти-провайдеров и оффчейн-данных
Закрытая много-проверочная система, в которой существует фиксированное число систем доказательств в структуре M-of-N, позволяет избежать значительной части вышеописанных сложностей. В частности, закрытым много-проверочным системам не нужно заботиться о том, чтобы данные были ончейн. Кроме того, закрытая многопроверочная система позволяет ZK-EVM доказывать выполнение оффчейн; это делает её совместимой с решениями EVM Plasma.
Однако закрытая много-проверочная система усложняет управление и лишает возможности аудита, а это большие затраты, которые необходимо сопоставить с преимуществами.
Если закрепим ZK-EVM и сделаем их функцией протокола, то какова будет дальнейшая роль "проектов второго уровня"?
Функции проверки EVM, которые команды L2-решений в настоящее время реализуют самостоятельно, будут переданы протоколу, но проекты L2 по-прежнему будут отвечать за многие важные функции:
- Быстрые предварительные подтверждения: финализация в один слот, вероятно, сделает слоты уровня 1 более медленными, в то время как проекты уровня 2 уже предоставляют своим пользователям "предварительные подтверждения", подкреплённые собственной безопасностью уровня 2, с задержкой гораздо меньшей, чем один слот. Эта услуга по-прежнему будет исключительно обязанностью уровня 2.
- Стратегии смягчения MEV: могут включать шифрованные пулы памяти, выбор секвенсора [секвенсор — компонент блокчейн-решений второго уровня, который отвечает за выполнение транзакций на втором уровне и отправку их обратно в основной блокчейн: он получает транзакции, проверяет и объединяет их в блоки] на основе репутации и другие возможности, которые уровень 1 не готов реализовать.
- Расширения EVM: проекты уровня 2 могут включать существенные расширения EVM, которые обеспечивают значительную ценность для их пользователей. Сюда входят как "почти-EVM", так и радикально иные подходы, такие как поддержка WASM в Arbitrum Stylus и дружественный SNARK язык Cairo.
- Удобство для пользователей и разработчиков: команды второго уровня проделывают большую работу по привлечению пользователей и проектов в свои экосистемы, чтобы они чувствовали себя желанными гостями; за это они получают компенсацию в виде сбора MEV и платы за перегрузку в своих сетях. Эти отношения будут продолжаться.
[Если есть дополнения по переводу, то подписывайтесь на канал https://t.me/web3news и см. там мои контактные данные], а пока всё и