EIP-3541: резервируем байт для будущего
Как оставить место для добавления совершенно нового формата контрактов позже, если каждый возможный первый байт кода уже является валидным опкодом? Никак — если только не сделать один байт запретным намеренно. EIP-3541 запрещает деплой нового кода, начинающегося с 0xEF, превращая этот байт в зарезервированное пространство, на котором строятся более поздние апгрейды (EOF и делегирующий дескриптор EIP-7702).
- код контракта и опкоды
- деплой контрактов
London, август 2021 года. Наряду с рынком комиссий и исправлением возвратов, London принёс изменение, которое само по себе ничего не делает — оно просто заставляет определённый деплой провалиться. Звучит бессмысленно, пока не увидишь, для чего это нужно. Ethereum хотел оставить себе пространство для внедрения совершенно нового формата кода контрактов в будущем форке — структурированного, версионированного, проверяемого заранее — вместо сегодняшнего байткода, который принимается как есть. Но добавление нового формата требует способа отличить его от старого, и это оказывается на удивление сложным. EIP-3541 — небольшой, дальновидный ход, который делает это возможным. Выведем его.
Проблема: каждый байт уже опкод
Код контракта — это просто последовательность байтов, и EVM читает их как опкоды Однобайтовые инструкции EVM. Код контракта — это сырая байтовая строка, интерпретируемая по одному опкоду за раз — 0x60 это PUSH1, 0x01 это ADD и так далее. Нет ни заголовка, ни тега типа; первый байт — это просто первая инструкция. . Чтобы внедрить новый формат, хотелось бы иметь магический префикс — первый байт, говорящий: «не читай меня как обычный байткод, я — новая вещь». Проблема в том, что каждое значение байта от 0x00 до 0xff уже что-то значит как опкод (или является определённой недействительной инструкцией), так что нет значения, которое можно объявить маркером, не будучи уже валидным кодом. Новому формату нечем заявить о себе.
→ Шаг 2: намеренно сделать один байт запретным.
EIP-3541: отклоняем новый код, начинающийся с 0xEF
Решение — это правило, а не механизм: начиная с London, любая попытка задеплоить новый код контракта, чей первый байт — 0xEF, проваливается — создание откатывается, и контракт не создаётся. Этот единственный запрет превращает 0xEF в зарезервированный префикс Значение байта, с которого протокол запрещает начинать новый код контракта, чтобы будущие апгрейды могли безопасно придать ему особое значение. EIP-3541 зарезервировал таким образом 0xEF. — байт, гарантированно никогда не начинающий обычный байткод, а значит свободный для будущего формата. (0xEF выбрали, потому что это был неопределённый опкод, напоминающий «EVM Format»; горстка уже задеплоенных контрактов, начинающихся с 0xEF, получает освобождение задним числом, поскольку правило блокирует только новые деплои.)
→ Шаг 3: обналичить резервацию.
Итог: магический префикс для новых форматов
Когда 0xEF гарантированно свободен, будущий форк может безопасно объявить: «код, начинающийся с 0xEF…, — не устаревший байткод, интерпретируй его особо», с нулевым риском неверно прочитать настоящий контракт. На этом напрямую строятся две вещи. EOF EVM Object Format — структурированный, версионированный контейнер контракта (заголовок, секции кода/данных, проверяемый при деплое), начинающийся с магических байтов 0xEF00. Он полагается на то, что 3541 зарезервировал 0xEF. использует префикс 0xEF00 для своего версионированного контейнера. А ещё — связь, замыкающая петлю в этой книге, — делегирующий дескриптор EIP-7702 — это 0xef0100 ‖ address: когда 7702 присваивает коду EOA это значение, он использует зарезервированный префикс 0xEF именно для того, чтобы это значение нельзя было спутать с обычным байткодом.