Найти тему
Владислав Утушкин

Стоит ли Ethereum допускать закрепление в протоколе большего количества функций?

Оглавление

С самого начала существования проекта Ethereum в нем прослеживалась философия, направленная на то, чтобы сделать ядро Ethereum как можно более простым, и как можно больше сделать за счет создания протоколов поверх него. В блокчейн-пространстве дискуссия "делать это на L1" и "сосредоточиться на L2" обычно воспринимается в первую очередь как дискуссия о масштабировании, но в действительности аналогичные проблемы существуют для удовлетворения многих потребностей пользователей Ethereum: обмен цифровыми активами, конфиденциальность, имена пользователей, продвинутая криптография, безопасность учетных записей, устойчивость к цензуре, защита от фронтраннинга и т.д. Можно и дальше продолжать список. Однако в последнее время наблюдается осторожный интерес к желанию закрепить большее количество этих функций в основном протоколе Ethereum.

В этой статье мы рассмотрим некоторые философские обоснования, лежащие в основе первоначальной философии минимального закрепления, а также некоторые более современные способы осмысления некоторых из этих идей. Целью статьи является создание основы для более точного определения возможных целей, для которых стоит рассмотреть возможность закрепления определенных функций в протоколе.

Ранняя философия протокольного минимализма

В самом начале истории того, что тогда называлось "Ethereum 2.0", было сильное желание создать чистый, простой и красивый протокол, который старался бы сам делать как можно меньше, а почти все оставлял бы на усмотрение пользователей. В идеале протокол должен был просто стать виртуальной машиной, а верификация блока — просто одним вызовом виртуальной машины.

Очень приблизительная реконструкция Виталика Бутерина 2015 года, показывающая, как должен был выглядеть Ethereum 2.0.
Очень приблизительная реконструкция Виталика Бутерина 2015 года, показывающая, как должен был выглядеть Ethereum 2.0.

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

Эти обсуждения в 2015 году в особенности касались двух областей, которые нас волновали: абстракции аккаунтов и масштабирования. В случае с масштабированием идея заключалась в том, чтобы попытаться создать максимально абстрагированную форму масштабирования, которая выглядела бы как естественное продолжение приведенной выше диаграммы. Контракт мог бы обращаться к части данных, которая не хранится на большинстве нод Ethereum, а протокол обнаруживал бы это и разрешал вызов через некую очень общую функциональность масштабирования вычислений. С точки зрения виртуальной машины, вызов должен был уйти в какую-то отдельную подсистему, а затем через некоторое время волшебным образом вернуться с правильным ответом.

Этот вариант был рассмотрен вкратце, но вскоре от него отказались, поскольку мы были слишком озабочены проверкой того, что масштабирование блокчейна вообще возможно. Хотя, как мы увидим далее, сочетание выборки доступности данных и ZK-EVM (расширение виртуальной машины Ethereum, которое предоставляет возможность выполнения смарт-контрактов с применением протоколов "нулевого разглашения") означает, что одно из возможных будущих решений для масштабирования Ethereum может оказаться удивительно близким к этому видению! Что касается абстракции аккаунтов, то мы с самого начала знали, что какая-то реализация возможна, и поэтому сразу же начали исследования, чтобы попытаться воплотить в реальность что-то максимально близкое к пуристской отправной точке "транзакция — это просто вызов системы".

Между обработкой транзакции и выполнением фактического вызова EVM по адресу отправителя возникает множество бойлерплейт-кода (прим.ред. – шаблонного кода), и еще большее количество "бойлерплейта" возникает после. Как свести этот код к нулю, насколько это вообще возможно?
Между обработкой транзакции и выполнением фактического вызова EVM по адресу отправителя возникает множество бойлерплейт-кода (прим.ред. – шаблонного кода), и еще большее количество "бойлерплейта" возникает после. Как свести этот код к нулю, насколько это вообще возможно?

Одна из основных частей кода здесь — validate_transaction(state, tx), которая проверяет корректность nonce и подписи транзакции. Практическая цель абстракции аккаунтов с самого начала заключалась в том, чтобы дать возможность пользователям заменить базовое наращивание nonce и проверку ECDSA на собственную логику проверки, чтобы пользователям было проще использовать такие вещи, как социальное восстановление и мультисиг-кошельки. Таким образом, поиск способа реорганизации apply_transaction в простой вызов EVM был не просто задачей "сделать код чистым ради чистоты кода"; скорее, речь шла о переносе логики в код учетной записи пользователя, чтобы предоставить пользователям необходимую гибкость.

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

Характеристики

Если block.number >= METROPOLIS_FORK_BLKNUM, то: 1. Если подпись транзакции равна (0, 0, 0) (т.е. v = r = s = 0), то считать ее действительной и установить адрес отправителя равным 2**160 – 1 2. Установить адрес любого контракта, созданного в результате транзакции создания, равным sha3(0 + init code) % 2**160, где + представляет собой конкатенацию, заменив прежнюю формулу адреса sha3(rlp.encode([sender, nonce])). 3. Создать новый опкод по адресу 0xfb, CREATE_P2SH, который устанавливает адрес создания в sha3(sender + init code) % 2**160. Если контракт по этому адресу уже существует, то происходит сбой и возвращается 0, как если бы у кода init закончился бензин.

По сути, если подпись установлена как (0, 0, 0), то транзакция действительно становится "просто вызовом". Сам аккаунт будет отвечать за наличие кода, который анализирует транзакцию, извлекает и проверяет подпись и nonce, а также выплачивает комиссионные; ранний пример такого кода см. здесь, а очень похожий код validate_transaction, который этот код аккаунта заменит, см. здесь.

В обмен на эту простоту на уровне протокола майнеры (или, как сегодня принято говорить, провайдеры блоков) получают дополнительную ответственность за выполнение дополнительной логики, позволяющей принимать и пересылать транзакции только на те счета, код которых настроен на реальную выплату вознаграждения. Что это за логика? Честно говоря, в EIP-86 об этом не слишком задумывались:

Обратите внимание, что майнерам в таком случае необходимо иметь стратегию приема подобных транзакций. Эта стратегия должна быть очень разборчивой, поскольку в противном случае они рискуют принимать транзакции для кода validate_transaction, который будет заменен этим кодом предварительного аккаунта, не выплачивающие им никаких вознаграждений, и, возможно, даже транзакции, не имеющие эффекта (например, потому что транзакция уже была включена и поэтому nonce уже неактуален). Один из простых подходов заключается в том, чтобы иметь вайтлист для кодового хэша счетов, на которые разрешается отправлять транзакции; одобренный код будет включать логику, которая выплачивает майнерам комиссионные за транзакции. Однако такой подход, пожалуй, является слишком ограничительным; более мягкой, но все же эффективной стратегией было бы принятие любого кода, который соответствует общему формату, описанному выше, потребляя лишь ограниченное количество газа для выполнения проверки nonce и подписи и имея гарантию того, что плата за транзакции будет выплачена майнеру. Другая стратегия заключается в том, чтобы наряду с другими подходами пытаться обрабатывать любую транзакцию, запрашивающую менее 250 000 газа, и включать ее только в том случае, если баланс майнера после выполнения транзакции будет соответственно выше, чем до нее.

Если бы EIP-86 был включен как есть, это уменьшило бы сложность EVM, но при этом значительно увеличило бы сложность других частей стека Ethereum, потребовало бы написания по сути точно такого же кода в других местах, а также ввело бы совершенно новые классы странностей, такие как возможность появления одной и той же транзакции с одним и тем же хэшем несколько раз в блокчейне, не говоря уже о проблеме мультивалидации.

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

Далее абстракция аккаунтов развивалась поэтапно. EIP-86 превратился в EIP-208, который впоследствии стал постом на ethresear.ch о "компромиссах в предложениях по абстракции аккаунтов", который через полгода превратился в этот пост на ethresear.ch. В конце концов, из всего этого получился реально работающий EIP-2938.

Однако EIP-2938 оказался совсем не минималистичным. В состав EIP входят:

  • Новый тип транзакции
  • Три новые глобальные переменные для всей транзакции
  • Два новых опкода, включая очень громоздкий опкод PAYGAS, который одновременно выполняет проверку цены на газ и лимита газа, является точкой прерывания выполнения EVM и временно хранит ETH для оплаты комиссии.
  • Набор сложных стратегий майнинга и ретрансляции, включая список запрещенных опкодов для этапа подтверждения транзакции

Чтобы запустить абстракцию аккаунта без привлечения разработчиков ядра Ethereum, которые были заняты героическими усилиями по оптимизации клиентов Ethereum и реализации слияния, EIP-2938 в итоге был перестроен в полностью внепротокольный ERC-4337.

ERC-4337. Он действительно полностью полагается на вызовы EVM!
ERC-4337. Он действительно полностью полагается на вызовы EVM!

Поскольку это ERC, он не требует хард форка и технически живет "вне протокола Ethereum". Эт что значит, проблема .... решена? Как оказалось, далеко не совсем. Текущая среднесрочная дорожная карта для ERC-4337 действительно предполагает превращение значительной части ERC-4337 в ряд протокольных функций, и это полезный поучительный пример, позволяющий увидеть причины, по которым рассматривается такой путь.

Закрепление ERC-4337

Обсуждалось несколько основных причин, по которым ERC-4337 может быть возвращен в протокол:

  • Экономия газа: все, что делается внутри EVM, влечет за собой определенный уровень накладных расходов виртуальной машины, включая неэффективность использования таких газозатратных функций, как слоты для хранения данных. В настоящее время эти дополнительные неэффективные затраты составляют не менее ~20 000 газа, а зачастую и больше. Вынесение этих компонентов в протокол — самый простой способ устранить эти проблемы.
  • Риск кодовых ошибок: если в "контракте точки входа" ERC-4337 будет обнаружена достаточно серьезная ошибка, то все кошельки, совместимые с ERC-4337, могут лишиться всех своих средств. Замена контракта на внутрипротокольную функциональность создает подразумеваемую ответственность за исправление ошибок в коде при хард форке, что снимает риск потери средств для пользователей.
  • Поддержка опкодов EVM типа tx.origin. ERC-4337 сам по себе заставляет tx.origin возвращать адрес "связующего", который упаковывает набор пользовательских операций в транзакцию. Абстракция нативного аккаунта может исправить это, заставив tx.origin указывать на фактический аккаунт, отправляющий транзакцию, что позволяет работать так же, как и в случае с EOA.
  • Устойчивость к цензуре: одна из проблем разделения претендентов (proposer) и строителей (builder) заключается в том, что становится проще подвергать цензуре отдельные транзакции. В мире, где отдельные транзакции читаемы для протокола Ethereum, эта проблема может быть значительно смягчена с помощью списков включения, которые позволяют предлагающим указать список транзакций, которые должны быть включены в следующие два слота почти во всех случаях. Однако внепротокольный ERC-4337 оборачивает "пользовательские операции" внутри одной транзакции, делая пользовательские операции непрозрачными для протокола Ethereum; следовательно, списки включения, предоставляемые протоколом Ethereum, не смогут обеспечить цензуру против пользовательских операций ERC-4337. Закрепление ERC-4337 и превращение пользовательских операций в "правильный" тип транзакций позволило бы решить эту проблему.

Стоит подробнее остановиться на вопросе экономии газа. В своем нынешнем виде ERC-4337 значительно дороже "базовой" транзакции Ethereum: транзакция стоит 21 000 газа, тогда как ERC-4337 — ~42 000 газа. В этом документе перечислены некоторые причины этого:

  • Необходимо оплачивать множество индивидуальных расходов на чтение/запись данных, которые в случае с EOA объединяются в единый платеж за газ в размере 21000:

- Редактирование слота памяти, содержащего pubkey+nonce (~5000)

- Затраты на calldata UserOperation (~4500, при сжатии уменьшаются до ~2500)

- ECRECOVER (~3000)

- Прогрев самого кошелька (~2600)

- Прогрев счета получателя (~2600)

- Перевод ETH на счет получателя (~9000)

- Редактирование хранилища для оплаты комиссии (~5000)

- Доступ к слоту хранения, содержащему прокси (~2100), а затем к самому прокси (~2600)

  • Помимо вышеуказанных затрат на чтение/запись данных в хранилище, контракт должен выполнять "бизнес-логику" (распаковка UserOperation, ее хеширование, перетасовка переменных и т.д.), которую транзакции EOA выполняют "бесплатно" по протоколу Ethereum
  • Необходимость расходовать газ для оплаты логов (EOA не выпускают логов)
  • единовременные затраты на создание контракта (~32000 базовых, плюс 200 газа на каждый байт кода в прокси, плюс 20000 на установку адреса прокси)

Теоретически можно было бы изменить систему газовых издержек EVM так, чтобы внутрипротокольные и внепротокольные издержки доступа к хранилищу совпадали; нет никаких причин, почему передача ETH должна стоить 9000 газа, когда другие виды операций по редактированию хранилища гораздо дешевле. И действительно, два EIP ([1] [2]), связанные с предстоящим переходом на древо Verkle, пытаются это сделать. Но даже если мы это сделаем, есть одна огромная причина, по которой закрепленные функции протокола неизбежно будут значительно дешевле кода EVM, независимо от того, насколько эффективным станет EVM: закрепленному коду не нужно платить газом за то, что он предварительно загружен.

Полнофункциональные кошельки ERC-4337 весьма объемны. Данная реализация, скомпилированная и помещенная в сеть, занимает ~12 800 байт. Конечно, можно развернуть этот большой кусок кода один раз и использовать DELEGATECALL, чтобы позволить каждому отдельному кошельку обращаться к нему, но к этому коду все равно нужно обращаться в каждом блоке, который его использует. В древе Verkle цена газа EIP составляет 12 800 байт, 12 800 байт составляют 413 кусков, и доступ к этим кускам требует оплаты 2x WITNESS_BRANCH_COST (всего 3800 газа) и 413x WITNESS_CHUNK_COST (всего 82 600 газа). И это еще не говоря о самой точке входа ERC-4337, имеющей в версии 0.6.0 23 689 байт в сети (по правилам EIP дерева Verkle, ~158 700 газа для загрузки).

Это приводит к проблеме: газовые затраты на фактический доступ к этому коду должны быть как-то разделены между транзакциями. Текущий подход, используемый в ERC-4337, не очень хорош: первая транзакция в связке съедает одноразовые затраты на хранение/считывание кода, что делает ее гораздо более дорогой, чем остальные транзакции. Закрепление в протоколе позволило бы этим часто используемым библиотекам просто стать частью протокола и быть доступными всем без какой-либо платы.

Что в целом можно извлечь из этого примера в отношении того, когда следует закреплять те или иные элементы?

В данном примере мы увидели несколько различных обоснований необходимости закрепления в протоколе аспектов абстракции аккаунтов.

  • Рыночные подходы, основанные на "перемещении сложности на периферию", в наибольшей степени разрушаются при наличии высоких постоянных затрат. И действительно, долгосрочная дорожная карта абстракции аккаунтов, похоже, будет иметь много постоянных затрат на блок. 244 100 газа на загрузку стандартизированного кода кошелька — это одно, но агрегирование (см. мою презентацию минувшего лета) потенциально добавляет еще сотни тысяч газа на проверку ZK-SNARK плюс затраты на проверку доказательств в сети. Не существует способа взимать плату с пользователей за эти расходы, не создавая при этом большой рыночной неэффективности, в то время как превращение некоторых из этих функций в функции протокола, доступные для всех без взимания платы, полностью решает эту проблему.
  • Реакция сообщества на ошибки в коде. Если некоторый набор фрагментов кода используется всеми пользователями или очень широким кругом пользователей, то зачастую блокчейн-сообществу имеет смысл взять на себя ответственность за хард форк для исправления возникающих ошибок. В ERC-4337 было представлено большое количество глобально разделяемого кода, и в долгосрочной перспективе целесообразнее исправлять ошибки в этом коде с помощью хард форков, чем приводить к потере пользователями большого количества ETH.
  • Иногда более сильная форма функции может быть реализована путем прямого использования возможностей протокола. Ключевым примером здесь являются внутрипротокольные функции противодействия цензуре, такие как списки включения: внутрипротокольные списки включения могут гарантировать более эффективную работу по противодействию цензуре, чем внепротокольные подходы, но для того, чтобы операции на уровне пользователя действительно могли воспользоваться внутрипротокольными списками включения, отдельные операции на уровне пользователя должны быть "читаемы" для протокола. Другой менее известный пример: в конструкциях Ethereum proof of stake 2017 года была предусмотрена абстракция аккаунта для стейкинга ключей, но от нее отказались в пользу закрепления BLS, поскольку BLS поддерживает механизм "агрегирования", который должен быть реализован на уровне протокола и сети, что может сделать обработку очень большого количества подписей гораздо более эффективной.

Однако важно помнить, что даже закрепленная внутрипротокольная абстракция аккаунтов — это все равно масштабное "открепление" по сравнению со статус-кво. Сегодня транзакции верхнего уровня в Ethereum могут быть инициированы только с внешних аккаунтов Ethereum (EOA), которые используют для верификации единственную подпись secp256k1 на эллиптической кривой. Абстракция аккаунтов снимает эту проблему и оставляет условия верификации открытыми для пользователей. Таким образом, в этой истории об абстракции аккаунтов мы увидели и самый главный аргумент против закрепления: гибкость к разнообразным потребностям пользователей.

-5

Попробуем дополнить историю, рассмотрев еще несколько примеров признаков, которые в последнее время рассматриваются на предмет закрепления. Особое внимание мы уделим: ZK-EVM, разделение proposer-builder, приватные mempools, ликвидный стейкинг и новые заранее составленные договоры.

Закрепление ZK-EVM

Переключим внимание на другую потенциальную цель для закрепления в протоколе Ethereum: ZK-EVM. В настоящее время мы имеем большое количество ZK-полос (англ. — Zero Knowledge roll ups), которые все должны писать достаточно похожий код для проверки выполнения блоков, подобных Ethereum, внутри ZK-SNARK. Существует довольно разнообразная экосистема независимых реализаций: PSE ZK-EVM, Kakarot, Polygon ZK-EVM, Linea, Zeth, и так далее.

Один из недавних споров в области EVM ZK-полос связан с тем, как бороться с возможными ошибками в ZK-коде. В настоящее время все существующие системы имеют в той или иной форме механизм "совета безопасности", который может отменить действие системы доказательства в случае обнаружения ошибки. В этом прошлогоднем посте я попытался создать стандартизированную структуру, чтобы побудить проекты четко определить, какой уровень доверия они оказывают системе доказательства, а какой — совету безопасности, и двигаться в направлении предоставления совету безопасности все меньших полномочий с течением времени.

В среднесрочной перспективе "полосы" смогут опираться на несколько систем доказательства, а совет безопасности будет иметь какие-либо полномочия только в крайнем случае, когда две разные системы доказательства не согласны друг с другом.
В среднесрочной перспективе "полосы" смогут опираться на несколько систем доказательства, а совет безопасности будет иметь какие-либо полномочия только в крайнем случае, когда две разные системы доказательства не согласны друг с другом.

Однако есть ощущение, что часть этой работы является излишней. У нас уже есть базовый уровень Ethereum, на котором есть EVM, и уже есть работающий механизм устранения ошибок в реализации: если есть ошибка, клиенты, у которых есть ошибка, обновляются, исправляя ее, и цепочка продолжается. Блоки, которые с точки зрения клиента с ошибкой казались завершенными, в итоге перестанут быть завершенными, но, по крайней мере, пользователи не будут терять средства. Аналогичным образом, если “полосы” (англ. — roll up, роллап) просто хотят быть и оставаться EVM-эквивалентными, кажется неправильным, что они должны внедрять собственное управление, чтобы постоянно менять свои внутренние правила ZK-EVM в соответствии с обновлениями базового слоя Ethereum, когда в конечном итоге они строят поверх самого базового слоя Ethereum, который знает, когда его обновляют и по каким новым правилам.

Поскольку эти L2 ZK-EVM, по сути, используют точно такой же EVM, как и Ethereum, не можем ли мы как-то сделать "проверку выполнения EVM в ZK" функцией протокола и решать исключительные ситуации, такие как ошибки и обновления, просто применяя социальный консенсус Ethereum, как мы уже делаем для выполнения EVM базового уровня?

Это важная и непростая тема. Здесь есть несколько нюансов:

  1. Мы хотим быть совместимыми с философией многоклиентности Ethereum. Это означает, что мы хотим позволить разным клиентам использовать разные системы доказательства. Это, в свою очередь, означает, что для любого выполнения EVM, которое было доказано одной системой ZK-SNARK, мы хотим получить гарантию того, что базовые данные доступны, чтобы доказательства могли быть сгенерированы для других систем ZK-SNARK.
  2. Пока технология незрелая, мы, вероятно, хотим аудируемости. На практике это означает то же самое: если какое-либо выполнение будет доказано, мы хотим, чтобы базовые данные были доступны, чтобы в случае чего пользователи и разработчики могли их проверить.
  3. Нам нужно гораздо более быстрое время доказательства, чтобы при наличии одного типа доказательства другие типы доказательств генерировались достаточно быстро, чтобы другие клиенты могли их подтвердить. Это можно обойти, сделав предкомпиляцию с асинхронным ответом через некоторый промежуток времени, больший, чем слот (например, 3 часа), но это усложняет задачу.
  4. Мы хотим поддерживать не только копии EVM, но и "почти-EVM". Отчасти L2 привлекают возможностью инноваций на уровне исполнения и расширений EVM. Если ВМ данного L2 отличается от EVM лишь незначительно, было бы неплохо, если бы L2 мог использовать собственный внутрипротокольный ZK-EVM для тех частей, которые идентичны EVM, и полагаться на собственный код для тех частей, которые отличаются. Это можно сделать, разработав предкомпиляцию ZK-EVM таким образом, чтобы она позволяла вызывающей стороне указать битовое поле или список опкодов или адресов, которые будут обрабатываться не самим EVM, а таблицей, поставляемой извне. Можно также сделать газовые издержки открытыми для кастомизации в ограниченном объеме.

Одним из возможных спорных вопросов, связанных с доступностью данных в нативном ZK-EVM, является целостность состояния. ZK-EVM гораздо более эффективны в плане работы с данными, если им не нужно носить с собой "свидетельские" данные. То есть, если какой-то фрагмент данных уже был прочитан или записан в каком-то предыдущем блоке, то можно просто считать, что у проверяющих есть к нему доступ, и не делать его снова доступным. Это не просто отсутствие необходимости повторной загрузки хранилища и кода: оказывается, что при правильном сжатии данных в рулонах сжатие с учетом состояния позволяет сэкономить до 3 раз по сравнению со сжатием без учета состояния.

-7

Это означает, что для предкомпиляции ZK-EVM у нас есть два варианта:

  1. Предкомпиляция требует, чтобы все данные были доступны в одном блоке. Это означает, что проверочные машины могут быть без статических данных, но это также означает, что ZK-полосы, использующие такую предкомпиляцию, становятся намного дороже, чем роли, использующие пользовательский код.
  2. Предкомпиляция позволяет использовать указатели на данные, использованные или сгенерированные предыдущими выполнениями. Это позволяет приблизить ZK-полосы к оптимальным, но является более сложным и вводит новый вид состояния, которое должно храниться у проверяющих.

Какие уроки мы можем извлечь из этого? Есть достаточно веские аргументы в пользу того, чтобы каким-то образом закрепить валидацию ZK-EVM: полосы уже создают свои собственные версии этой системы, и кажется неправильным, что Ethereum готов использовать вес своих многочисленных реализаций и внесетевого общественного консенсуса для выполнения EVM на L1, а L2, выполняющие точно такую же работу, вынуждены вместо этого внедрять сложные гаджеты с участием советов по безопасности. Но, с другой стороны, в деталях кроется большой дьявол: существуют различные версии закрепленной ZK-EVM, которые имеют различные затраты и преимущества. Разделение на целостность и нецелостность — лишь малая толика; попытка поддержки "почти-EVM" с пользовательским кодом, проверенным другими системами, скорее всего, откроет еще большее пространство для проектирования. Таким образом, закрепление ZK-EVM несет в себе как перспективы, так и проблемы.

Закрепление разделения претендентов и строителей (ePBS)

С появлением MEV производство блоков превратилось в деятельность, требующую больших масштабов, причем искушенные участники могут производить блоки, приносящие гораздо больший доход, чем стандартные алгоритмы, которые просто следят за транзакциями в мемпуле и включают их. До сих пор сообщество Ethereum пыталось решить эту проблему с помощью внепротокольных схем разделения претендентов и строителей, таких как MEV-Boost, которые позволяют обычным валидаторам ("претендентам") передавать создание блоков специализированным участникам ("строителям").

Однако MEV-Boost несет в себе предположение о доверии к новой категории агентов, называемой "Реле". В последние два года появилось много предложений по созданию "закрепленных PBS". В чем выгода от этого? В данном случае ответ довольно прост: PBS, которую можно построить, непосредственно используя полномочия протокола, просто сильнее (в смысле более слабых предположений о доверии), чем PBS, которую можно построить без них. Это похоже на аргумент в пользу закрепления внутрипротокольных ценовых оракулов — хотя в этой ситуации также существует сильный контраргумент.

Закрепление закрытых мемпулов

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

В последнее время появился ряд проектов, специализирующихся на создании "закрытых мемпулов" (или "зашифрованных мемпулов"), в которых транзакции пользователей хранятся в зашифрованном виде до момента их необратимого принятия в блокчейн.

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

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

  • Шифрование для централизованного оператора, например, Flashbots Protect.
  • Шифрование с временным замком — форма шифрования, которая может быть расшифрована любым человеком после определенного количества последовательных вычислительных шагов, которые не могут быть распараллелены.
  • Пороговое шифрование, доверяющее расшифровку данных честному комитету большинства. Конкретное предложение см. в концепции цепочки маяков с затвором.

К сожалению, каждый из них имеет свои недостатки. Централизованный оператор не может быть включен в протокол по очевидным причинам. Традиционное шифрование с временной блокировкой слишком дорого для работы с тысячами транзакций в публичном mempool. Более мощный примитив, называемый шифрованием с задержкой, позволяет эффективно расшифровывать неограниченное число сообщений, но на практике его трудно построить, а атаки на существующие конструкции все же иногда обнаруживаются. Как и в случае с хэш-функциями, нам, вероятно, потребуется еще несколько лет исследований и анализа, прежде чем шифрование с задержкой станет достаточно совершенным. Пороговое шифрование требует доверия большинства к тому, что оно не вступит в сговор, причем в условиях, когда сговор может быть незаметен (в отличие от 51%-ных атак, где сразу видно, кто участвовал). SGX создает зависимость от одного надежного производителя.

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

Закрепление ликвидного стейкинга

Частым требованием DeFi-пользователей Ethereum является возможность использовать свои ETH одновременно для стейкинга и в качестве обеспечения в других приложениях. Другим распространенным требованием является простое удобство: пользователи хотят иметь возможность стейкать без сложностей, связанных с запуском ноды и ее постоянным нахождением в сети (и защитой своих ключей стейкинга, которые теперь находятся в сети).

Безусловно, самым простым "интерфейсом" для стейкинга, удовлетворяющим обеим этим потребностям, является токен ERC20: конвертируйте свой ETH в " Staked ETH", удерживайте их, а затем конвертируйте обратно. И действительно, появились провайдеры ликвидного стейкинга, такие как Lido и Rocketpool, которые занимаются именно этим. Однако в ликвидном стейкинге действует естественная централизующая механика: люди, естественно, переходят на самую большую версию стейкинга ETH, поскольку она наиболее привычна и ликвидна (и наиболее хорошо поддерживается приложениями, которые, в свою очередь, поддерживают ее, поскольку она более привычна и поскольку о ней слышало большинство пользователей).

В каждой версии ETH должен быть механизм, определяющий, кто может быть оператором базовой ноды. Он не может быть неограниченным, поскольку в этом случае злоумышленники будут присоединяться и усиливать свои атаки за счет средств пользователей. В настоящее время лидируют Lido, в которой DAO ведет вайтлист операторов нод, и Rocket Pool, позволяющий любому желающему управлять нодой, если он внесет 8 ETH (т.е. 1/4 капитала) в качестве депозита. Эти два подхода имеют разные риски: подход Rocket Pool позволяет злоумышленникам атаковать сеть на 51% и заставляет пользователей оплачивать большую часть расходов. При подходе DAO, если один такой стейкинг-токен доминирует, это приводит к тому, что один потенциально атакуемый управляющий гаджет контролирует очень большую часть всех валидаторов Ethereum. К чести протоколов типа Lido, они реализовали защиту от этого, но одного уровня защиты может оказаться недостаточно.

-8

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

Здесь ключевой вопрос: какой именно функционал должен быть внутрипротокольным? Простое создание внутрипротокольного взаимозаменяемого токена "staked ETH" сопряжено с проблемой, связанной с тем, что он должен либо иметь закрепленное в рамках Ethereum управление, позволяющее выбирать управляющих нодами, либо быть с открытым входом, что превращает его в орудие злоумышленников.

Интересной идеей являются труды Данкрада Фейста о максимализме ликвидного стейкинга. Во-первых, мы исходим из того, что если Ethereum будет атакован на 51%, то, возможно, только 5% атакующих ETH будут уничтожены. Это разумный компромисс: сейчас в стейкинге находится более 26 млн. ETH, и стоимость атаки в 1/3 от этой суммы (~8 млн. ETH) является чрезмерной, особенно если учесть, что многие виды атак "вне модели" могут быть проведены за гораздо меньшие деньги. Действительно, подобный компромисс уже рассматривался в предложении "суперкомитета" по внедрению финализации одного слота.

-9

Если мы примем, что только 5% атакующих ETH будут разрушены, то более 90% размещенных в стейкинге ETH будут неуязвимы для разрушения, и таким образом 90% ETH в стейкинге можно будет перевести во внутрипротокольный взаимозаменяемый ликвидный стейкинг-токен, который затем можно будет использовать в других приложениях.

Этот путь интересен. Но остается открытым вопрос: что конкретно будет закреплено? RocketPool уже работает примерно так: каждый оператор нод вносит определенный капитал, а ликвидные стейкеры вносят остальное. Мы можем просто подправить несколько констант, ограничив максимальный санкционный штраф, например, 2 ETH, и существующие в Rocket Pool ETH станут безрисковыми.

Есть и другие умные вещи, которые мы можем сделать с помощью простых изменений в протоколе. Например, представим себе, что мы хотим создать систему, в которой есть два "уровня" стейкинга: операторы нод (высокие требования к залогу) и вкладчики (без минимума, могут присоединяться и уходить в любое время), но при этом мы хотим защитить от централизации оператора нод, предоставив случайно выбранному комитету вкладчиков такие полномочия, как предложение списков транзакций, которые должны быть включены (в целях борьбы с цензурой), контроль выбора форка во время утечки неактивности или необходимость подписывать блоки. Это можно сделать в основном внепротокольным способом, изменив протокол таким образом, чтобы каждый валидатор предоставлял (i) обычный ключ стейкинга и (ii) ETH-адрес, который может быть вызван для вывода вторичного ключа стейкинга во время каждого слота. Протокол будет наделять полномочиями эти два ключа, но механизм выбора второго ключа в каждом слоте можно оставить на усмотрение протоколов стейкинг-пула. Возможно, некоторые вещи все же лучше закрепить прямо, но важно отметить, что такое пространство для проектирования "закрепить некоторые вещи, а другие оставить на усмотрение пользователей" существует.

Закрепление большего количества предкомпилированных контрактов

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

В настоящее время идет активная работа по добавлению предкомпиляции для secp256r1 — эллиптической кривой, несколько отличающейся от secp256k1, используемой для базовых аккаунтов Ethereum, поскольку она хорошо поддерживается доверенными аппаратными модулями, а значит, ее широкое использование может повысить безопасность кошелька. В последние годы также предпринимались попытки добавить предкомпиляции для BLS-12-377, BW6-761, обобщенные пары и другие возможности.

Контраргументом против этих просьб о большем количестве предкомпиляционных контрактов является то, что многие, которые были добавлены ранее (например, RIPEMD и BLAKE), в итоге использовались гораздо меньше, чем предполагалось, и нам следует извлечь из этого урок. Вместо того чтобы добавлять новые предкомпиляторы для конкретных операций, нам, возможно, следует сосредоточиться на более умеренном подходе, основанном на таких идеях, как EVM-MAX и спящее, но все еще сохраняющее актуальность предложение SIMD, которое позволит реализациям EVM выполнять широкие классы кода с меньшими затратами. Возможно, даже существующие малоиспользуемые предкомпиляции могут быть удалены и заменены (неизбежно менее эффективными) реализациями EVM-кода той же функции. Тем не менее, не исключено, что существуют специфические криптографические операции, которые достаточно ценны для ускорения, чтобы имело смысл добавлять их в качестве предкомпиляционных контрактов.

Что мы узнали из всего этого?

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

Во многих случаях эти другие примеры повторяют уроки, аналогичные тем, которые мы видели в абстракции аккаунтов. Но есть и несколько новых уроков:

  • Закрепление функций позволяет избежать рисков централизации в других областях стека. Часто сохранение минимального и простого базового протокола приводит к тому, что сложность переносится в некую экосистему вне протокола. С точки зрения философии Unix это хорошо. Однако иногда возникает риск централизации этой экосистемы вне протокола, часто (но не только) из-за высоких постоянных затрат. Закрепление иногда может уменьшить де-факто централизацию.
  • Закрепление слишком большого количества функций может привести к чрезмерному увеличению нагрузки на протокол в плане доверия и управления. Это тема предыдущего поста о том, как не перегружать консенсус Ethereum: если закрепление определенной функции ослабляет модель доверия и делает Ethereum в целом гораздо более "субъективным", это ослабляет доверительную нейтральность Ethereum. В таких случаях лучше оставить эту особенность в качестве механизма поверх Ethereum и не пытаться перенести ее в сам Ethereum. В данном случае зашифрованные мемпулы являются лучшим примером того, что может быть слишком сложно закрепить, по крайней мере, до тех пор, пока технология шифрования задержки не улучшится.
  • Закрепление слишком большого количества функций может привести к чрезмерному усложнению протокола. Сложность протокола — это системный риск, а добавление слишком большого количества функций в протокол увеличивает этот риск. Предкомпиляция — лучший пример этого.
  • В долгосрочной перспективе закрепление может привести к обратному результату, поскольку потребности пользователей непредсказуемы. Функция, которую многие считают важной и которая будет использоваться многими пользователями, на практике может оказаться малоприменимой.

Кроме того, примеры с ликвидным стейкингом, ZK-EVM и предкомпиляцией показывают возможность срединного пути: минимально жизнеспособного закрепления. Вместо того чтобы закреплять всю функциональность, протокол может закрепить конкретную часть, которая решает ключевые проблемы, обеспечивающие простоту реализации этой функциональности, не будучи при этом слишком категоричным или узконаправленным. Примерами могут служить:

  • Вместо закрепления полноценной системы ликвидного стейкинга изменить правила штрафов за стейкинг, чтобы сделать более жизнеспособным бездоверительный ликвидный стейкинг
  • Вместо того, чтобы вводить больше предкомпиляций, можно ввести EVM-MAX и/или SIMD, чтобы сделать более широкий класс операций более простым для эффективной реализации
  • Вместо того чтобы закреплять всю концепцию полос (роллапов), можно просто закрепить верификацию EVM.

Мы можем расширить нашу диаграмму, приведенную ранее в этой заметке, следующим образом:

-10

Иногда даже имеет смысл отказаться от определенных вещей. Одним из примеров является открепление малоиспользуемых предкомпиляций. Абстракция аккаунтов в целом, как уже говорилось, также является значительной формой открепления. Если мы хотим поддержать обратную совместимость для существующих пользователей, то механизм может быть удивительно похож на тот, что используется для удаления прекомпиляций: одним из предложений является EIP-5003, который позволит EOA конвертировать свой существующий аккаунт в контракт с той же (или лучшей) функциональностью.

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