В Ethereum ресурсы до недавнего времени были ограничены и ценообразованы с использованием единственного ресурса, называемого "газом". Газ - это мера количества "вычислительных усилий", необходимых для обработки заданной транзакции или блока. Газ объединяет в себе несколько типов "усилий", прежде всего:
Например, эта транзакциячто я отправил, стоит в общей сложности 47 085 газа. Это разделено между (i) «базовая стоимость» в размере 21000 газа, (ii) 1556 газа за байты в вызываемых данных, включенных в транзакцию (iii) 16500 газа для чтения и записи в хранилище, (iv) газ 2149 за созданиежурнал, и остальное для выполнения EVM. Комиссия за транзакцию, которую пользователь должен заплатить, пропорциональна газу, который потребляет транзакция. Блок может содержать максимум 30 миллионов газа, и цены на газ постоянно корректируются через @vbuterin/eip-1559-faq">Механизм целевой настройки EIP-1559, обеспечивающий, что в среднем блоки содержат 15 миллионов Газ.
Этот подход имеет одно основное преимущество: поскольку все сливается в один виртуальный ресурс, это приводит к очень простому дизайну рынка. Оптимизация транзакции для минимизации издержек проста, оптимизация блока для сбора максимальных возможных сборов относительно легкая (не включаяMEV) и нет никаких странных стимулов, которые могли бы поощрять объединение некоторых транзакций с другими для экономии на комиссиях.
Но этот подход также имеет одну основную неэффективность: он рассматривает различные ресурсы как взаимозаменяемые, когда фактические ограничения того, что сеть может обработать, не соблюдаются. Один из способов понять эту проблему - посмотреть на эту диаграмму:
Лимит газа налагает ограничение
𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗компутация<𝑁
Фактическое базовое ограничение безопасности часто ближе к
макс(х1*дата,х2*компутация)<Н
. Это расхождение приводит либо к тому, что предел газа ненужно исключает фактически безопасные блоки, либо принимает фактически небезопасные блоки, либо к какому-то их сочетанию.
Если есть
𝑛
ресурсы, у которых есть четкие пределы безопасности, вероятно, уменьшают пропускную способность одномерного газа до фактора
n
Именно по этой причине долгое время существовал интерес к концепции многомерного газа и сEIP-4844у нас действительно сегодня работает многомерный Газ на Ethereum. В этом посте рассматриваются преимущества такого подхода и перспективы его дальнейшего увеличения.
В начале этого года средний блок был150 кБ по размеруБольшая часть этого размера - это данные rollup: протоколы уровня 2хранение данных на цепочке для обеспечения безопасности. Эти данные были дорогими: даже если транзакции на роллапах будут стоить ~5-10 раз меньше, чем соответствующие транзакции на Ethereum L1, даже эта стоимость была слишком высокой для многих случаев использования.
Почему бы не уменьшить стоимость газа для передачи данных (в настоящее время 16 газа за ненулевой байт и 4 газа за нулевой байт), чтобы сделать rollups дешевле? Мы делал это раньшеМы могли бы сделать это снова. Ответ здесь: худший возможный размер блока был
30,000,00016=1,875,000
ненулевые байты, и сеть уже едва справляется с блоками такого размера. Снижение затрат еще на 4 раза увеличило бы максимум до 7,5 МБ, что представляло бы огромный риск для безопасности.
В конечном итоге эта проблема была решена путем введения в каждый блок отдельного пространства данных, подходящих для свертки, известных как «большие двоичные объекты». Эти два ресурса имеют разные цены и разные ограничения: после хардфорка Dencun блок Ethereum может содержать не более (i) 30 миллионов газа и (ii) 6 блобов, каждый из которых может содержать ~125 КБ calldata. Оба ресурса имеют отдельные цены, скорректированные на отдельные механизмы ценообразования, аналогичные EIP-1559, нацеливаясь на средний объем использования 15 миллионов газа и 3 блоба на блок.
В результате стоимость роллапов снизилась в 100 раз, объем транзакций на роллапах увеличился более чем в 3 раза, а теоретический максимальный размер блока был увеличен незначительно: с ~1,9 МБ до ~2,6 МБ.
Комиссии за транзакции на роллапах, любезно предоставленные Gate.iogrowthepie.xyzФорк Dencun, в результате которого были введены блобы с многомерной ценовой политикой, произошел 13 марта 2024 года.
В ближайшем будущем возникнет аналогичная проблема с доказательствами хранения для бессостоятельных клиентов. Бессостоятельные клиенты - это новый тип клиента, который сможет проверять цепочку без хранения многих или каких-либо данных локально. Бессостоятельные клиенты делают это, принимая доказательства конкретных частей состояния Ethereum, которые транзакции в этом блоке должны затронуть.
Безсостоятельный клиент получает блок вместе с доказательствами, подтверждающими текущие значения в определенных частях состояния (например, балансы счетов, код, хранилище), с которыми связано выполнение блока. Это позволяет узлу проверить блок без наличия собственного хранилища.
Стоимость чтения хранилища составляет 2100-2600 газа в зависимости от типа операции чтения, а запись в хранилище стоит дороже. В среднем блок выполняет около 1000 операций чтения и записи в хранилище (включая проверку баланса ETH, вызовы SSTORE и SLOAD, чтение кода контракта и другие операции). Теоретический максимум, однако, составляет
30,000,0002,100=14,285
читает. Нагрузка на пропускную способность клиента без состояния прямо пропорциональна этому числу.
Сегодня план состоит в поддержке бессостоятельных клиентов путем переноса дизайна дерева состояний Ethereum изДеревья Меркла-ПатрициикДеревья VerkleОднако деревья Verkle не устойчивы к квантовым вычислениям и не оптимальны для новых волн систем доказательства STARK. В результате многие люди заинтересованы в поддержке бессостоятельных клиентов через двоичные деревья Меркля и STARKsвместо этого - либо полностью пропуская Веркл, либо обновляясь через пару лет после перехода на Веркл, когда STARKs станут более зрелыми.
Доказательства STARK двоичных ветвей хэш-дерева имеют много преимуществ, но у них есть ключевое слабое место: доказательства требуют много времени на генерацию: в то время как Деревья Verkleможет доказатьболее ста тысяч значений в секунду, хэш-основанные STARKs обычно могут доказать только несколько тысяч хэшей в секунду, и для доказательства каждого значения требуется «ветвь», содержащая много хэшей.
Учитывая числа, которые сегодня проецируются из гипероптимизированных доказательственных систем, таких как Binius и Plonky3и специализированные хеши, такие какVision-Mark-32, кажется, что в течение некоторого времени мы будем находиться в режиме, когда практично доказать 1 000 значений менее чем за секунду, но не 14 285 значений. Средние блоки подошли бы, но в случае наихудшего сценария, потенциально опубликованные злоумышленником блоки сломают сеть.
Таким образом, "стандартным" способом, которым мы обработали такой сценарий, является повторное ценообразование: сделать чтение хранилища более дорогим для снижения максимума на каждый блок до более безопасного значения. Однако у насужесделаноэтомногиевремена, и это сделало бы слишком много приложений слишком дорогими для повторения этого снова. Лучшим подходом был бы многомерный газ: ограничивать и взимать плату за доступ к хранилищу отдельно, поддерживая средний использование на уровне 1 000 доступов к хранилищу на блок, но устанавливая предельный лимит на блок, например, 2 000.
Еще одним ресурсом, о котором стоит задуматься, является рост размера состояния: операции, которые увеличивают размер состояния Ethereum, который полные узлы будут держать отныне. Уникальное свойство роста размера состояния заключается в том, что обоснование его ограничения полностью происходит от долгосрочного устойчивого использования, а не от всплесков. Следовательно, может быть ценность в добавлении отдельного газового измерения для операций увеличения размера состояния (например, переход от нуля к ненулевому SSTORE, создание контракта), но с другой целью: мы могли бы установить плавающую цену для достижения определенного среднего использования, но вообще не устанавливать никакого предела на блок.
Это показывает одно из мощных свойств многомерного газа: это позволяет нам отдельно задавать вопросы (i) каков идеальный средний расход, и (ii) каков безопасный максимальный расход на блок для каждого ресурса. Вместо того чтобы устанавливать цены на газ на основе максимальных значений на блок и позволять среднему расходу следовать, мы имеем
2𝑛
степеней свободы для установки
2𝑛
параметры, настройка каждого из них в зависимости от того, что безопасно для сети.
Более сложные ситуации, например, когда два ресурса имеют частично аддитивные соображения безопасности, могут быть решены путем назначения опкода или стоимости ресурса некоторого количества типов газа (например, SSTORE от нуля к ненулевому мог бы стоить 5000 газа для доказательства безопасности клиента и 20000 газа для расширения хранилища).
Пусть
𝑥1
быть стоимость газа данных и
𝑥2
быть стоимость газа вычисления, так что в одномерной газовой системе мы можем написать стоимость газа транзакции:
Газ=х1∗дата+х2∗компутация
В этой схеме мы вместо этого определяем стоимость газа транзакции как:
Газ=макс(х1*дата,х2*компутация)
То есть, вместо того чтобы взиматься плата за данные плюс вычисления, плата за транзакцию зависит от того, какой из двух ресурсов она потребляет больше. Это легко расширить, чтобы охватить больше измерений (например.
макс(…,х3*стораге_акцесс)
).
Легко увидеть, как это улучшает пропускную способность, сохраняя при этом безопасность. Теоретический максимальный объем данных в блоке все еще
ГАСЛИМИТх1
, точно так же, как в одномерной схеме газа. Точно так же, теоретический максимальный объем вычислений составляет
ГАСЛИМИТх2
, снова точно так же, как в одномерной схеме газа. Однако стоимость газа любой транзакции, которая потребляет как данные, так и вычисления, уменьшается.
Это примерно схема, используемая в предложенном EIP-7623, чтобы уменьшить максимальный размер блока, увеличивая количество блобов дальше. Точный механизм в EIP-7623 немного сложнее: он сохраняет текущую цену calldata в размере 16 Газ за байт, но добавляет «минимальную цену» в размере 48 Газ за байт; транзакция платит большую сумму из (16 байтов + execution_gas) и (48 байт). В результате EIP-7623 уменьшает теоретический максимальный объем данных транзакции в блоке с ~1.9 МБ до ~0.6 МБ, оставляя при этом стоимость большинства приложений неизменной. Преимущество такого подхода заключается в том, что это очень маленькое изменение по сравнению с текущей одномерной схемой газа, и поэтому его очень легко реализовать.
Есть два недостатка:
Я бы возражал, что правило в стиле EIP-7623, как для данных транзакции, так и для других ресурсов, может принести достаточно большие преимущества, чтобы оправдать это даже несмотря на эти недостатки. Однако, если и когда мы готовы приложить (значительно большие) усилия по разработке, есть более идеальный подход.
Давайте сначала кратко рассмотрим, как работает «обычный» EIP-1559. Мы сосредоточимся на версии, которая была представлена в EIP-4844 для блобов, потому что она математически более элегантна.
Мы отслеживаем параметр, excess_blobs. Во время каждого блока мы устанавливаем:
избыточные_блобы <— макс(избыточные_блобы + len(block.blobs) - ЦЕЛЬ, 0)
Где TARGET = 3. То есть, если у блока больше блобов, чем цель, excess_blobs увеличивается, а если у блока меньше цели, то уменьшается. Затем мы устанавливаем blob_basefee = exp(excess_blobs / 25.47), где exp - это приближение экспоненциальной функции.
𝑒𝑥𝑝(𝑥)=2.71828𝑥
.
То есть, когда excess_blobs увеличивается примерно на 25, базовая плата за blob увеличивается в ~2.7 раза. Если blobs становятся слишком дорогими, среднее использование снижается, и excess_blobs начинает уменьшаться, автоматически снижая цену снова. Цена blob постоянно корректируется, чтобы убедиться, что в среднем блоки заполнены наполовину - то есть в каждом из них содержится в среднем по 3 блоба.
Если возникает кратковременный всплеск использования, то вступает в силу лимит: каждый блок может содержать только максимум 6 блобов, и в таком случае транзакции могут конкурировать друг с другом, предлагая повышение своих приоритетных сборов. Однако в обычном случае каждому блобу достаточно заплатить базовый сбор за блоб плюс крошечный дополнительный приоритетный сбор в качестве стимула для включения вообще.
Такая ценовая политика существует в Ethereum для газа уже много лет: очень похожий механизм был введен с @vbuterin/eip-1559-faq">EIP-1559 вернулся в 2020 году. С EIP-4844 у нас теперь есть две отдельно фиксированные цены на газ и на блобы.
Базовая плата за газ за один час 2024-05-08 года, в гвей. Источник: ultrasound.money.
В принципе, мы могли бы добавить еще несколько отдельных плавающих сборов за чтение хранилища и другие виды операций, хотя с одним замечанием, о котором я подробнее расскажу в следующем разделе.
Для пользователей этот опыт удивительно похож на сегодняшний: вместо того, чтобы платить одну базовую комиссию, вы платите две базовые, но ваш кошелек может абстрагироваться от вас и просто показать вам ожидаемую комиссию и максимальную комиссию, которую вы можете ожидать заплатить.
Для строителей блоков, в большинстве случаев оптимальная стратегия такая же, как и сегодня: включить всё, что действительно. Большинство блоков не полные - ни в газенив каплях. Одним из сложных случаев является ситуация, когда достаточно газа или достаточно блобов, чтобы превысить лимит блока, и строителю потенциально придется решить Многомерная ранцевая задачадля максимизации своей прибыли. Однако даже там существуют довольно хорошие приближенные алгоритмы, и выгоды от создания собственных алгоритмов для оптимизации прибыли в этом случае намного меньше, чем выгоды от того же самого сделать с MEV.
Для разработчиков основной вызов заключается в необходимости переработки функций EVM и окружающей инфраструктуры, которые сегодня разработаны вокруг одной цены и одного лимита, в дизайн, который учитывает несколько цен и несколько лимитов. Одной из проблем для разработчиков приложений является то, что оптимизация становится немного сложнее: в некоторых случаях нельзя однозначно сказать, что A эффективнее B, потому что если A использует больше calldata, а B использует больше выполнения, то A может быть дешевле, когда calldata дешев, и дороже, когда calldata дорог. Однако разработчики всё равно смогут получить разумно хорошие результаты, оптимизируясь на основе длительного исторического среднего уровня цен.
Есть одна проблема, которая не возникала с блобами и не возникнет с EIP-7623 или даже с «полной» многомерной реализацией ценообразования для calldata, но возникнет, если мы попытаемся отдельно ценообразовать доступ к состоянию или любой другой ресурс: газовые лимиты при подвызовах.
Лимиты газа в EVM существуют в двух местах. Во-первых, каждая транзакция устанавливает лимит газа, который ограничивает общее количество газа, которое может быть использовано в этой транзакции. Во-вторых, при вызове контракта другим контрактом вызывающий контракт может установить свой собственный лимит газа. Это позволяет контрактам вызывать другие контракты, которым они не доверяют, и все равно гарантировать, что после этого вызова у них останется газ для выполнения других вычислений.
След абстрактной транзакции учетной записи, где учетная запись вызывает другую учетную запись и передает вызываемому ограниченное количество газа, чтобы гарантировать, что внешний вызов может продолжаться даже если вызываемая сторона потребляет весь выделенный ей газ.
Изгиб заключается в том, что сделать газ многомерным между различными типами исполнения кажется так, будто это потребует подвызовов для установки множественных лимитов для каждого типа газа, что потребует действительно глубоких изменений в EVM и не будет совместимо с существующими приложениями.
Вот почему многомерные предложения по газу часто ограничиваются двумя измерениями: данными и выполнением. Данные (будь то данные вызова транзакции или блобы) назначаются только за пределами EVM, поэтому ничего внутри EVM не нужно изменять, чтобы установить отдельные цены на вызовы транзакций или блобы.
Мы можем подумать о решении в стиле "EIP-7623" для этой проблемы. Вот одна простая реализация: во время выполнения увеличьте стоимость операций с хранилищем в 4 раза; для упрощения анализа давайте скажем, что 10000 газа за операцию с хранилищем. По окончании транзакции вернуть min(7500 * операции_с_хранилищем, газ_выполнения). Результатом будет то, что после вычета возврата пользователю будет начислено:
execution_Газ + 10000 storage_operations - min(7500операции хранения, выполнение Газ)
Который равен:
max(execution_gas + 2500операции хранения, 10000storage_operations)
Это отражает структуру EIP-7623. Другой способ сделать это - отслеживать storage_operations и execution_gas в реальном времени и взимать плату в размере 2500 или 10000 в зависимости от того, сколько max(execution_gas + 2500Операции хранения, 10000Потребление газа (storage_operations) увеличивается в тот момент, когда вызывается опкод. Это позволяет избежать необходимости перераспределения газа в транзакциях, поскольку большая часть его будет возвращена через возвратные средства.
У нас нет тонкой настройки разрешений для подвызовов: подвызов может потреблять всю "квоту" транзакции для дешевых операций хранения. Но у нас есть достаточно хорошее решение, где контракт, делающий подвызов, может установить ограничение и гарантировать, что после завершения подвызова у основного вызова все еще будет достаточно газа для выполнения всех пост-обработок, которые ему нужны.
Самое простое «полное многомерное решение ценообразования», о котором я могу подумать, - это то, что мы рассматриваем пределы газа для подвызовов как пропорциональные. То есть, предположим, что есть
𝑘
различные типы исполнения, и каждая транзакция устанавливает многомерный предел
𝐿1…𝐿𝑘
Предположим, что на текущем этапе выполнения остался газ
𝑔1…𝑔𝑘
Предположим, что вызывается операция CALL, с лимитом газа для подвызова
𝑆
. Пусть
𝑠1=𝑆
, и затем
𝑠2=𝑠1𝑔1∗Газ2
,
𝑠3=𝑠1𝑔1∗𝑔3
, и так далее.
То есть мы рассматриваем первый тип газа (реалистично, выполнение VM) как своего рода привилегированный "единицу учета", а затем назначаем другие типы газа так, чтобы подвызов получал тот же процент доступного газа по каждому типу. Это несколько некрасиво, но это максимизирует обратную совместимость. Если мы хотим сделать схему более "нейтральной" между различными типами газа, за счет жертвы обратной совместимости, мы могли бы просто иметь параметр ограничения газа подвызова, представляющий собой дробь (например, [1...63] / 64) оставшегося газа в текущем контексте).
В любом случае, однако, стоит подчеркнуть, что как только вы начинаете вводить многомерный выполнение газа, врожденный уровень уродства увеличивается, и это кажется трудным избежать. Следовательно, наша задача состоит в том, чтобы сделать сложный компромисс: мы принимаем ли немного больше уродства на уровне EVM, чтобы безопасно разблокировать значительные приросты масштабируемости L1, и если да, то какое конкретное предложение лучше всего подходит для экономики протокола и разработчиков приложений? Довольно вероятно, что ни одно из упомянутых мной выше предложений не является лучшим вариантом, и всё ещё есть возможность придумать что-то более элегантное и лучшее.
Mời người khác bỏ phiếu
Nội dung
В Ethereum ресурсы до недавнего времени были ограничены и ценообразованы с использованием единственного ресурса, называемого "газом". Газ - это мера количества "вычислительных усилий", необходимых для обработки заданной транзакции или блока. Газ объединяет в себе несколько типов "усилий", прежде всего:
Например, эта транзакциячто я отправил, стоит в общей сложности 47 085 газа. Это разделено между (i) «базовая стоимость» в размере 21000 газа, (ii) 1556 газа за байты в вызываемых данных, включенных в транзакцию (iii) 16500 газа для чтения и записи в хранилище, (iv) газ 2149 за созданиежурнал, и остальное для выполнения EVM. Комиссия за транзакцию, которую пользователь должен заплатить, пропорциональна газу, который потребляет транзакция. Блок может содержать максимум 30 миллионов газа, и цены на газ постоянно корректируются через @vbuterin/eip-1559-faq">Механизм целевой настройки EIP-1559, обеспечивающий, что в среднем блоки содержат 15 миллионов Газ.
Этот подход имеет одно основное преимущество: поскольку все сливается в один виртуальный ресурс, это приводит к очень простому дизайну рынка. Оптимизация транзакции для минимизации издержек проста, оптимизация блока для сбора максимальных возможных сборов относительно легкая (не включаяMEV) и нет никаких странных стимулов, которые могли бы поощрять объединение некоторых транзакций с другими для экономии на комиссиях.
Но этот подход также имеет одну основную неэффективность: он рассматривает различные ресурсы как взаимозаменяемые, когда фактические ограничения того, что сеть может обработать, не соблюдаются. Один из способов понять эту проблему - посмотреть на эту диаграмму:
Лимит газа налагает ограничение
𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗компутация<𝑁
Фактическое базовое ограничение безопасности часто ближе к
макс(х1*дата,х2*компутация)<Н
. Это расхождение приводит либо к тому, что предел газа ненужно исключает фактически безопасные блоки, либо принимает фактически небезопасные блоки, либо к какому-то их сочетанию.
Если есть
𝑛
ресурсы, у которых есть четкие пределы безопасности, вероятно, уменьшают пропускную способность одномерного газа до фактора
n
Именно по этой причине долгое время существовал интерес к концепции многомерного газа и сEIP-4844у нас действительно сегодня работает многомерный Газ на Ethereum. В этом посте рассматриваются преимущества такого подхода и перспективы его дальнейшего увеличения.
В начале этого года средний блок был150 кБ по размеруБольшая часть этого размера - это данные rollup: протоколы уровня 2хранение данных на цепочке для обеспечения безопасности. Эти данные были дорогими: даже если транзакции на роллапах будут стоить ~5-10 раз меньше, чем соответствующие транзакции на Ethereum L1, даже эта стоимость была слишком высокой для многих случаев использования.
Почему бы не уменьшить стоимость газа для передачи данных (в настоящее время 16 газа за ненулевой байт и 4 газа за нулевой байт), чтобы сделать rollups дешевле? Мы делал это раньшеМы могли бы сделать это снова. Ответ здесь: худший возможный размер блока был
30,000,00016=1,875,000
ненулевые байты, и сеть уже едва справляется с блоками такого размера. Снижение затрат еще на 4 раза увеличило бы максимум до 7,5 МБ, что представляло бы огромный риск для безопасности.
В конечном итоге эта проблема была решена путем введения в каждый блок отдельного пространства данных, подходящих для свертки, известных как «большие двоичные объекты». Эти два ресурса имеют разные цены и разные ограничения: после хардфорка Dencun блок Ethereum может содержать не более (i) 30 миллионов газа и (ii) 6 блобов, каждый из которых может содержать ~125 КБ calldata. Оба ресурса имеют отдельные цены, скорректированные на отдельные механизмы ценообразования, аналогичные EIP-1559, нацеливаясь на средний объем использования 15 миллионов газа и 3 блоба на блок.
В результате стоимость роллапов снизилась в 100 раз, объем транзакций на роллапах увеличился более чем в 3 раза, а теоретический максимальный размер блока был увеличен незначительно: с ~1,9 МБ до ~2,6 МБ.
Комиссии за транзакции на роллапах, любезно предоставленные Gate.iogrowthepie.xyzФорк Dencun, в результате которого были введены блобы с многомерной ценовой политикой, произошел 13 марта 2024 года.
В ближайшем будущем возникнет аналогичная проблема с доказательствами хранения для бессостоятельных клиентов. Бессостоятельные клиенты - это новый тип клиента, который сможет проверять цепочку без хранения многих или каких-либо данных локально. Бессостоятельные клиенты делают это, принимая доказательства конкретных частей состояния Ethereum, которые транзакции в этом блоке должны затронуть.
Безсостоятельный клиент получает блок вместе с доказательствами, подтверждающими текущие значения в определенных частях состояния (например, балансы счетов, код, хранилище), с которыми связано выполнение блока. Это позволяет узлу проверить блок без наличия собственного хранилища.
Стоимость чтения хранилища составляет 2100-2600 газа в зависимости от типа операции чтения, а запись в хранилище стоит дороже. В среднем блок выполняет около 1000 операций чтения и записи в хранилище (включая проверку баланса ETH, вызовы SSTORE и SLOAD, чтение кода контракта и другие операции). Теоретический максимум, однако, составляет
30,000,0002,100=14,285
читает. Нагрузка на пропускную способность клиента без состояния прямо пропорциональна этому числу.
Сегодня план состоит в поддержке бессостоятельных клиентов путем переноса дизайна дерева состояний Ethereum изДеревья Меркла-ПатрициикДеревья VerkleОднако деревья Verkle не устойчивы к квантовым вычислениям и не оптимальны для новых волн систем доказательства STARK. В результате многие люди заинтересованы в поддержке бессостоятельных клиентов через двоичные деревья Меркля и STARKsвместо этого - либо полностью пропуская Веркл, либо обновляясь через пару лет после перехода на Веркл, когда STARKs станут более зрелыми.
Доказательства STARK двоичных ветвей хэш-дерева имеют много преимуществ, но у них есть ключевое слабое место: доказательства требуют много времени на генерацию: в то время как Деревья Verkleможет доказатьболее ста тысяч значений в секунду, хэш-основанные STARKs обычно могут доказать только несколько тысяч хэшей в секунду, и для доказательства каждого значения требуется «ветвь», содержащая много хэшей.
Учитывая числа, которые сегодня проецируются из гипероптимизированных доказательственных систем, таких как Binius и Plonky3и специализированные хеши, такие какVision-Mark-32, кажется, что в течение некоторого времени мы будем находиться в режиме, когда практично доказать 1 000 значений менее чем за секунду, но не 14 285 значений. Средние блоки подошли бы, но в случае наихудшего сценария, потенциально опубликованные злоумышленником блоки сломают сеть.
Таким образом, "стандартным" способом, которым мы обработали такой сценарий, является повторное ценообразование: сделать чтение хранилища более дорогим для снижения максимума на каждый блок до более безопасного значения. Однако у насужесделаноэтомногиевремена, и это сделало бы слишком много приложений слишком дорогими для повторения этого снова. Лучшим подходом был бы многомерный газ: ограничивать и взимать плату за доступ к хранилищу отдельно, поддерживая средний использование на уровне 1 000 доступов к хранилищу на блок, но устанавливая предельный лимит на блок, например, 2 000.
Еще одним ресурсом, о котором стоит задуматься, является рост размера состояния: операции, которые увеличивают размер состояния Ethereum, который полные узлы будут держать отныне. Уникальное свойство роста размера состояния заключается в том, что обоснование его ограничения полностью происходит от долгосрочного устойчивого использования, а не от всплесков. Следовательно, может быть ценность в добавлении отдельного газового измерения для операций увеличения размера состояния (например, переход от нуля к ненулевому SSTORE, создание контракта), но с другой целью: мы могли бы установить плавающую цену для достижения определенного среднего использования, но вообще не устанавливать никакого предела на блок.
Это показывает одно из мощных свойств многомерного газа: это позволяет нам отдельно задавать вопросы (i) каков идеальный средний расход, и (ii) каков безопасный максимальный расход на блок для каждого ресурса. Вместо того чтобы устанавливать цены на газ на основе максимальных значений на блок и позволять среднему расходу следовать, мы имеем
2𝑛
степеней свободы для установки
2𝑛
параметры, настройка каждого из них в зависимости от того, что безопасно для сети.
Более сложные ситуации, например, когда два ресурса имеют частично аддитивные соображения безопасности, могут быть решены путем назначения опкода или стоимости ресурса некоторого количества типов газа (например, SSTORE от нуля к ненулевому мог бы стоить 5000 газа для доказательства безопасности клиента и 20000 газа для расширения хранилища).
Пусть
𝑥1
быть стоимость газа данных и
𝑥2
быть стоимость газа вычисления, так что в одномерной газовой системе мы можем написать стоимость газа транзакции:
Газ=х1∗дата+х2∗компутация
В этой схеме мы вместо этого определяем стоимость газа транзакции как:
Газ=макс(х1*дата,х2*компутация)
То есть, вместо того чтобы взиматься плата за данные плюс вычисления, плата за транзакцию зависит от того, какой из двух ресурсов она потребляет больше. Это легко расширить, чтобы охватить больше измерений (например.
макс(…,х3*стораге_акцесс)
).
Легко увидеть, как это улучшает пропускную способность, сохраняя при этом безопасность. Теоретический максимальный объем данных в блоке все еще
ГАСЛИМИТх1
, точно так же, как в одномерной схеме газа. Точно так же, теоретический максимальный объем вычислений составляет
ГАСЛИМИТх2
, снова точно так же, как в одномерной схеме газа. Однако стоимость газа любой транзакции, которая потребляет как данные, так и вычисления, уменьшается.
Это примерно схема, используемая в предложенном EIP-7623, чтобы уменьшить максимальный размер блока, увеличивая количество блобов дальше. Точный механизм в EIP-7623 немного сложнее: он сохраняет текущую цену calldata в размере 16 Газ за байт, но добавляет «минимальную цену» в размере 48 Газ за байт; транзакция платит большую сумму из (16 байтов + execution_gas) и (48 байт). В результате EIP-7623 уменьшает теоретический максимальный объем данных транзакции в блоке с ~1.9 МБ до ~0.6 МБ, оставляя при этом стоимость большинства приложений неизменной. Преимущество такого подхода заключается в том, что это очень маленькое изменение по сравнению с текущей одномерной схемой газа, и поэтому его очень легко реализовать.
Есть два недостатка:
Я бы возражал, что правило в стиле EIP-7623, как для данных транзакции, так и для других ресурсов, может принести достаточно большие преимущества, чтобы оправдать это даже несмотря на эти недостатки. Однако, если и когда мы готовы приложить (значительно большие) усилия по разработке, есть более идеальный подход.
Давайте сначала кратко рассмотрим, как работает «обычный» EIP-1559. Мы сосредоточимся на версии, которая была представлена в EIP-4844 для блобов, потому что она математически более элегантна.
Мы отслеживаем параметр, excess_blobs. Во время каждого блока мы устанавливаем:
избыточные_блобы <— макс(избыточные_блобы + len(block.blobs) - ЦЕЛЬ, 0)
Где TARGET = 3. То есть, если у блока больше блобов, чем цель, excess_blobs увеличивается, а если у блока меньше цели, то уменьшается. Затем мы устанавливаем blob_basefee = exp(excess_blobs / 25.47), где exp - это приближение экспоненциальной функции.
𝑒𝑥𝑝(𝑥)=2.71828𝑥
.
То есть, когда excess_blobs увеличивается примерно на 25, базовая плата за blob увеличивается в ~2.7 раза. Если blobs становятся слишком дорогими, среднее использование снижается, и excess_blobs начинает уменьшаться, автоматически снижая цену снова. Цена blob постоянно корректируется, чтобы убедиться, что в среднем блоки заполнены наполовину - то есть в каждом из них содержится в среднем по 3 блоба.
Если возникает кратковременный всплеск использования, то вступает в силу лимит: каждый блок может содержать только максимум 6 блобов, и в таком случае транзакции могут конкурировать друг с другом, предлагая повышение своих приоритетных сборов. Однако в обычном случае каждому блобу достаточно заплатить базовый сбор за блоб плюс крошечный дополнительный приоритетный сбор в качестве стимула для включения вообще.
Такая ценовая политика существует в Ethereum для газа уже много лет: очень похожий механизм был введен с @vbuterin/eip-1559-faq">EIP-1559 вернулся в 2020 году. С EIP-4844 у нас теперь есть две отдельно фиксированные цены на газ и на блобы.
Базовая плата за газ за один час 2024-05-08 года, в гвей. Источник: ultrasound.money.
В принципе, мы могли бы добавить еще несколько отдельных плавающих сборов за чтение хранилища и другие виды операций, хотя с одним замечанием, о котором я подробнее расскажу в следующем разделе.
Для пользователей этот опыт удивительно похож на сегодняшний: вместо того, чтобы платить одну базовую комиссию, вы платите две базовые, но ваш кошелек может абстрагироваться от вас и просто показать вам ожидаемую комиссию и максимальную комиссию, которую вы можете ожидать заплатить.
Для строителей блоков, в большинстве случаев оптимальная стратегия такая же, как и сегодня: включить всё, что действительно. Большинство блоков не полные - ни в газенив каплях. Одним из сложных случаев является ситуация, когда достаточно газа или достаточно блобов, чтобы превысить лимит блока, и строителю потенциально придется решить Многомерная ранцевая задачадля максимизации своей прибыли. Однако даже там существуют довольно хорошие приближенные алгоритмы, и выгоды от создания собственных алгоритмов для оптимизации прибыли в этом случае намного меньше, чем выгоды от того же самого сделать с MEV.
Для разработчиков основной вызов заключается в необходимости переработки функций EVM и окружающей инфраструктуры, которые сегодня разработаны вокруг одной цены и одного лимита, в дизайн, который учитывает несколько цен и несколько лимитов. Одной из проблем для разработчиков приложений является то, что оптимизация становится немного сложнее: в некоторых случаях нельзя однозначно сказать, что A эффективнее B, потому что если A использует больше calldata, а B использует больше выполнения, то A может быть дешевле, когда calldata дешев, и дороже, когда calldata дорог. Однако разработчики всё равно смогут получить разумно хорошие результаты, оптимизируясь на основе длительного исторического среднего уровня цен.
Есть одна проблема, которая не возникала с блобами и не возникнет с EIP-7623 или даже с «полной» многомерной реализацией ценообразования для calldata, но возникнет, если мы попытаемся отдельно ценообразовать доступ к состоянию или любой другой ресурс: газовые лимиты при подвызовах.
Лимиты газа в EVM существуют в двух местах. Во-первых, каждая транзакция устанавливает лимит газа, который ограничивает общее количество газа, которое может быть использовано в этой транзакции. Во-вторых, при вызове контракта другим контрактом вызывающий контракт может установить свой собственный лимит газа. Это позволяет контрактам вызывать другие контракты, которым они не доверяют, и все равно гарантировать, что после этого вызова у них останется газ для выполнения других вычислений.
След абстрактной транзакции учетной записи, где учетная запись вызывает другую учетную запись и передает вызываемому ограниченное количество газа, чтобы гарантировать, что внешний вызов может продолжаться даже если вызываемая сторона потребляет весь выделенный ей газ.
Изгиб заключается в том, что сделать газ многомерным между различными типами исполнения кажется так, будто это потребует подвызовов для установки множественных лимитов для каждого типа газа, что потребует действительно глубоких изменений в EVM и не будет совместимо с существующими приложениями.
Вот почему многомерные предложения по газу часто ограничиваются двумя измерениями: данными и выполнением. Данные (будь то данные вызова транзакции или блобы) назначаются только за пределами EVM, поэтому ничего внутри EVM не нужно изменять, чтобы установить отдельные цены на вызовы транзакций или блобы.
Мы можем подумать о решении в стиле "EIP-7623" для этой проблемы. Вот одна простая реализация: во время выполнения увеличьте стоимость операций с хранилищем в 4 раза; для упрощения анализа давайте скажем, что 10000 газа за операцию с хранилищем. По окончании транзакции вернуть min(7500 * операции_с_хранилищем, газ_выполнения). Результатом будет то, что после вычета возврата пользователю будет начислено:
execution_Газ + 10000 storage_operations - min(7500операции хранения, выполнение Газ)
Который равен:
max(execution_gas + 2500операции хранения, 10000storage_operations)
Это отражает структуру EIP-7623. Другой способ сделать это - отслеживать storage_operations и execution_gas в реальном времени и взимать плату в размере 2500 или 10000 в зависимости от того, сколько max(execution_gas + 2500Операции хранения, 10000Потребление газа (storage_operations) увеличивается в тот момент, когда вызывается опкод. Это позволяет избежать необходимости перераспределения газа в транзакциях, поскольку большая часть его будет возвращена через возвратные средства.
У нас нет тонкой настройки разрешений для подвызовов: подвызов может потреблять всю "квоту" транзакции для дешевых операций хранения. Но у нас есть достаточно хорошее решение, где контракт, делающий подвызов, может установить ограничение и гарантировать, что после завершения подвызова у основного вызова все еще будет достаточно газа для выполнения всех пост-обработок, которые ему нужны.
Самое простое «полное многомерное решение ценообразования», о котором я могу подумать, - это то, что мы рассматриваем пределы газа для подвызовов как пропорциональные. То есть, предположим, что есть
𝑘
различные типы исполнения, и каждая транзакция устанавливает многомерный предел
𝐿1…𝐿𝑘
Предположим, что на текущем этапе выполнения остался газ
𝑔1…𝑔𝑘
Предположим, что вызывается операция CALL, с лимитом газа для подвызова
𝑆
. Пусть
𝑠1=𝑆
, и затем
𝑠2=𝑠1𝑔1∗Газ2
,
𝑠3=𝑠1𝑔1∗𝑔3
, и так далее.
То есть мы рассматриваем первый тип газа (реалистично, выполнение VM) как своего рода привилегированный "единицу учета", а затем назначаем другие типы газа так, чтобы подвызов получал тот же процент доступного газа по каждому типу. Это несколько некрасиво, но это максимизирует обратную совместимость. Если мы хотим сделать схему более "нейтральной" между различными типами газа, за счет жертвы обратной совместимости, мы могли бы просто иметь параметр ограничения газа подвызова, представляющий собой дробь (например, [1...63] / 64) оставшегося газа в текущем контексте).
В любом случае, однако, стоит подчеркнуть, что как только вы начинаете вводить многомерный выполнение газа, врожденный уровень уродства увеличивается, и это кажется трудным избежать. Следовательно, наша задача состоит в том, чтобы сделать сложный компромисс: мы принимаем ли немного больше уродства на уровне EVM, чтобы безопасно разблокировать значительные приросты масштабируемости L1, и если да, то какое конкретное предложение лучше всего подходит для экономики протокола и разработчиков приложений? Довольно вероятно, что ни одно из упомянутых мной выше предложений не является лучшим вариантом, и всё ещё есть возможность придумать что-то более элегантное и лучшее.