EIP-2929 и 2930: цена доступа к состоянию по реальным затратам
Чтение состояния — самая дорогая для диска операция узла, но EVM брала за неё фиксированную, слишком низкую цену — так что атакующий мог тронуть тысячи слотов почти бесплатно и поставить каждый узел на колени. Решение оценивает первое касание по реальной цене, а повторы делает дешёвыми; списки доступа позволяют транзакции заранее объявить, чего она коснётся.
- модель газа
- хранилище и SLOAD
Газ должен отслеживать реальную стоимость работы, чтобы сеть нельзя было дёшево перегрузить. Но годами EVM неверно оценивала самую дорогую свою операцию: чтение состояния. SLOAD или обращение к аккаунту заставляют узел пройти через дерево Меркла-Патриции и достать данные с диска — медленная, настоящая работа, — но за это брали фиксированную, крошечную плату. Этот разрыв был не просто неэффективностью — он был поверхностью для атаки, и в 2016 году его использовали, чтобы поставить Ethereum на колени. EIP-2929 переоценил доступ к состоянию, а EIP-2930 смягчил побочные эффекты списками доступа. Давайте выведем оба.
Проблема: фиксированная цена намного ниже реальной стоимости
Обращение к состоянию — самая дорогая на единицу газа операция для узла, потому что она означает поиск в trie Чтобы прочитать слот хранилища или аккаунт, узел обходит дерево Меркла-Патриции, забирая узлы с диска вдоль пути. Это операция, упирающаяся в ввод-вывод, и она гораздо медленнее вычислений EVM в памяти — реальное узкое место валидации блока. и обращение к диску. Прежние переоценки уже подняли фиксированную цену — после EIP-150 и EIP-1884 SLOAD стоил 800 газа, а обращение к аккаунту — 700, — но одно фиксированное число всё равно неверной формы. Назначьте его под холодное первое обращение, которое реально идёт на диск, — и переплатите за обычный случай повторного чтения того же слота из памяти; назначьте под этот обычный случай — и транзакция, касающаяся тысяч различных слотов или аккаунтов, платит почти ничего за касание, заставляя каждый узел на Земле проделать колоссальную работу с диском, чтобы провалидировать ваш блок.
Это не гипотеза: атаки «Shanghai» 2016 года заваливали сеть опкодами доступа к состоянию — тогда стоившими всего 20–50 газа, — растягивая обработку блока до десятков секунд. Фиксированные повышения EIP-150 и EIP-1884 были немедленной заплаткой; EIP-2929 — структурное исправление, к которому они вели.
→ Шаг 2: заметим, что повторы недорого стоят.
Почему простое повышение — неверное решение
Очевидный ход — сделать SLOAD стоящим, скажем, 2100 газа повсеместно — переплачивает за самый распространённый честный паттерн. В первый раз, когда вы читаете слот X, узел действительно платит за поиск в trie. Но второе и третье чтение того же слота в той же транзакции почти бесплатны: данные уже загружены в память узла. Фиксированная высокая цена берёт со всех трёх полную плату, делая обычные контракты, перечитывающие слот в цикле, драматически дороже за работу, которую узел на самом деле не переделывает.
Так что одно число не может быть верным. Стоимость зависит от того, трогали ли вы уже эту вещь в этой транзакции. Именно на этом наблюдении строится настоящее решение.
→ Шаг 3: разделим цену надвое.
EIP-2929: холодно в первый раз, тепло после
Оцениваем по новизне. EVM ведёт набор доступа Два множества, которые EVM отслеживает во время транзакции — accessed_addresses и accessed_storage_keys. Обращение к адресу или слоту добавляет его в множество; множество определяет, будет ли следующее обращение холодным (первым) или тёплым (повторным). для каждой транзакции — множество каждого адреса и слота, к которым вы обратились. Первое обращение к данному адресу или слоту — это холодный доступ Первое касание адреса или слота хранилища в транзакции. Оно стоит по реальной, высокой цене — 2600 газа за аккаунт, 2100 за слот хранилища, — отражая поиск в trie / на диске. , и оно стоит по реальной цене — 2600 газа за аккаунт, 2100 за слот хранилища. Каждое последующее обращение в той же транзакции — тёплое и стоит всего 100 газа. Опасный случай (коснуться тысяч различных слотов) теперь платит полную цену каждый раз и теряет смысл как DoS; обычный случай (перечитать один и тот же слот) остаётся дешёвым. Одно различие чинит обе проблемы.
- 1 первое касание в транзакции: слот стоит 2100, аккаунт — 2600 — реальная цена диска
- 2 каждое следующее касание: уже закешировано, поэтому почти бесплатно
→ Шаг 4: дадим транзакции заранее всё разогреть.
EIP-2930: объявите, чего коснётесь, и разогрейте это заранее
Дадим транзакциям способ заплатить и разогреть заранее. список доступа Необязательный список (адрес, ключи хранилища), которые транзакция заранее объявляет, что затронет. Перечисленные записи входят в транзакцию уже тёплыми, поэтому их первое обращение внутри исполнения оценивается по тёплой цене. Несёт транзакция типа 0x01. — это список (адрес, ключи хранилища), которые транзакция заявляет заранее. Всё объявленное добавляется в набор доступа до исполнения, так что первое обращение к этому внутри контракта оценивается по тёплой цене вместо холодной. Вы платите скромную предоплату за объявление — 2400 газа за адрес и 1900 за слот, чуть ниже холодных цен, — так что это небольшая скидка, но что важнее, она устраняет сюрприз холодного доступа и стала аварийным выходом для контрактов, которые переоценка иначе бы сломала. И доставляется это через совершенно новый тип транзакции, 0x01, — самый первый пользователь типизированного конверта EIP-2718.