Часть III · Глава 20 из 43 · Berlin

EIP-2929 и 2930: цена доступа к состоянию по реальным затратам

Чтение состояния — самая дорогая для диска операция узла, но EVM брала за неё фиксированную, слишком низкую цену — так что атакующий мог тронуть тысячи слотов почти бесплатно и поставить каждый узел на колени. Решение оценивает первое касание по реальной цене, а повторы делает дешёвыми; списки доступа позволяют транзакции заранее объявить, чего она коснётся.

Обновлено 13 сент. 2026 г. · 11 мин
Предполагается
  • модель газа
  • хранилище и SLOAD

Газ должен отслеживать реальную стоимость работы, чтобы сеть нельзя было дёшево перегрузить. Но годами EVM неверно оценивала самую дорогую свою операцию: чтение состояния. SLOAD или обращение к аккаунту заставляют узел пройти через дерево Меркла-Патриции и достать данные с диска — медленная, настоящая работа, — но за это брали фиксированную, крошечную плату. Этот разрыв был не просто неэффективностью — он был поверхностью для атаки, и в 2016 году его использовали, чтобы поставить Ethereum на колени. EIP-2929 переоценил доступ к состоянию, а EIP-2930 смягчил побочные эффекты списками доступа. Давайте выведем оба.

1 шаг Занижена и опасна

Проблема: фиксированная цена намного ниже реальной стоимости

Обращение к состоянию — самая дорогая на единицу газа операция для узла, потому что она означает поиск в trie Чтобы прочитать слот хранилища или аккаунт, узел обходит дерево Меркла-Патриции, забирая узлы с диска вдоль пути. Это операция, упирающаяся в ввод-вывод, и она гораздо медленнее вычислений EVM в памяти — реальное узкое место валидации блока. и обращение к диску. Прежние переоценки уже подняли фиксированную цену — после EIP-150 и EIP-1884 SLOAD стоил 800 газа, а обращение к аккаунту — 700, — но одно фиксированное число всё равно неверной формы. Назначьте его под холодное первое обращение, которое реально идёт на диск, — и переплатите за обычный случай повторного чтения того же слота из памяти; назначьте под этот обычный случай — и транзакция, касающаяся тысяч различных слотов или аккаунтов, платит почти ничего за касание, заставляя каждый узел на Земле проделать колоссальную работу с диском, чтобы провалидировать ваш блок.

плоский, недооценённый доступ к состоянию tx атакующего cheap per touch 200 200 200 200 200 200 200 200 200 200 каждые ~200 газа → узлы делают огромный disk I/O плоская низкая цена позволяла дешёвым tx трогать тысячи ячеек принуждает каждый узел к огромной дисковой работе — DoS Shanghai 2016
Одна фиксированная цена за доступ к состоянию — неверной формы: задайте её достаточно высокой для холодного первого обращения к диску — переплатите за каждый тёплый повтор; задайте под обычный случай — и тысячи различных холодных касаний стоят почти ничего, вынуждая каждый узел на огромный объём ввода-вывода.

Это не гипотеза: атаки «Shanghai» 2016 года заваливали сеть опкодами доступа к состоянию — тогда стоившими всего 20–50 газа, — растягивая обработку блока до десятков секунд. Фиксированные повышения EIP-150 и EIP-1884 были немедленной заплаткой; EIP-2929 — структурное исправление, к которому они вели.

→ Шаг 2: заметим, что повторы недорого стоят.

2 шаг Не просто поднимайте цену

Почему простое повышение — неверное решение

Очевидный ход — сделать SLOAD стоящим, скажем, 2100 газа повсеместно — переплачивает за самый распространённый честный паттерн. В первый раз, когда вы читаете слот X, узел действительно платит за поиск в trie. Но второе и третье чтение того же слота в той же транзакции почти бесплатны: данные уже загружены в память узла. Фиксированная высокая цена берёт со всех трёх полную плату, делая обычные контракты, перечитывающие слот в цикле, драматически дороже за работу, которую узел на самом деле не переделывает.

плоское повышение переплачивает за повторы — красное = впустую потраченный газ access #1 · disk fetch 2100 access #2 · cached 2100 access #3 · cached 2100 зелёный = реальная стоимость красный = переплата
Простое повышение фиксированной цены переплачивает за обычный случай: контракт, читающий один и тот же слот три раза, платит полную цену каждый раз, хотя после первой загрузки слот уже кешируется в памяти, а повторы по сути бесплатны.

Так что одно число не может быть верным. Стоимость зависит от того, трогали ли вы уже эту вещь в этой транзакции. Именно на этом наблюдении строится настоящее решение.

→ Шаг 3: разделим цену надвое.

3 шаг Холодный против тёплого

EIP-2929: холодно в первый раз, тепло после

Оцениваем по новизне. EVM ведёт набор доступа Два множества, которые EVM отслеживает во время транзакции — accessed_addresses и accessed_storage_keys. Обращение к адресу или слоту добавляет его в множество; множество определяет, будет ли следующее обращение холодным (первым) или тёплым (повторным). для каждой транзакции — множество каждого адреса и слота, к которым вы обратились. Первое обращение к данному адресу или слоту — это холодный доступ Первое касание адреса или слота хранилища в транзакции. Оно стоит по реальной, высокой цене — 2600 газа за аккаунт, 2100 за слот хранилища, — отражая поиск в trie / на диске. , и оно стоит по реальной цене — 2600 газа за аккаунт, 2100 за слот хранилища. Каждое последующее обращение в той же транзакции — тёплое и стоит всего 100 газа. Опасный случай (коснуться тысяч различных слотов) теперь платит полную цену каждый раз и теряет смысл как DoS; обычный случай (перечитать один и тот же слот) остаётся дешёвым. Одно различие чинит обе проблемы.

первое обращение — cold, повторные — warm 1-е обращение · холодно 2100 gas 2-е · тепло 100 gas 3-е · тепло 100 gas access set: { slot X, addr A, … } первое обращение — холодное (полная цена); повтор — тёплый, 100 газа
EIP-2929 берёт за первое касание адреса или слота реальную холодную цену (2600 / 2100), а затем 100 газа за каждый тёплый повтор. Набор доступа на транзакцию помнит, что уже было тронуто — так что DoS-спам платит полную цену, а честные перечтения остаются почти бесплатными.
Формула
доступ = холодный (2100 / 2600) 1 тёплый (100) 2
  1. 1 первое касание в транзакции: слот стоит 2100, аккаунт — 2600 — реальная цена диска
  2. 2 каждое следующее касание: уже закешировано, поэтому почти бесплатно
Оценивайте по новизне: дорогая часть — это первая выборка, поэтому именно туда идёт газ.
cumulative gas for N reads of one slot 5k 10k 15k 20k naive flat 2100 each cold once, then warm 100 number of accesses to the same slot →
Почему простое повышение — неверное решение, в виде кривой. При чтении одного слота N раз реальное холодно-тёплое ценообразование (2100 один раз, затем по 100) остаётся почти плоским; наивная линия «просто поднять фиксированную цену» (2100 за каждое обращение) убегает вверх. Заштрихованный разрыв — это ровно то, что тёплая цена экономит честному контракту.

→ Шаг 4: дадим транзакции заранее всё разогреть.

4 шаг Списки доступа

EIP-2930: объявите, чего коснётесь, и разогрейте это заранее

Дадим транзакциям способ заплатить и разогреть заранее. список доступа Необязательный список (адрес, ключи хранилища), которые транзакция заранее объявляет, что затронет. Перечисленные записи входят в транзакцию уже тёплыми, поэтому их первое обращение внутри исполнения оценивается по тёплой цене. Несёт транзакция типа 0x01. — это список (адрес, ключи хранилища), которые транзакция заявляет заранее. Всё объявленное добавляется в набор доступа до исполнения, так что первое обращение к этому внутри контракта оценивается по тёплой цене вместо холодной. Вы платите скромную предоплату за объявление — 2400 газа за адрес и 1900 за слот, чуть ниже холодных цен, — так что это небольшая скидка, но что важнее, она устраняет сюрприз холодного доступа и стала аварийным выходом для контрактов, которые переоценка иначе бы сломала. И доставляется это через совершенно новый тип транзакции, 0x01, — самый первый пользователь типизированного конверта EIP-2718.

объявить доступы заранее, чтобы прогреть их type 0x01 · access-list tx accessList: [addr A, keys k1 k2] [addr B, key k3] прогрев объявлено = warm first access: 100 небольшая предоплата (2400 / 1900) покупает тёплый первый доступ EIP-2930 — первый пользователь типизированного конверта EIP-2718 (type 0x01)
Транзакция со списком доступа (тип 0x01) заранее объявляет адреса и ключи хранилища, которые будет использовать. Они входят в набор доступа уже тёплыми, так что их первое обращение стоит 100 газа за небольшую предоплату (2400 за адрес, 1900 за слот).
04 Глубже Куда двигаться дальше