Предкомпилированные контракты EVM (precompiles): что это и какие есть в Ethereum

Предкомпилированные контракты (precompiles) в Ethereum — это набор «встроенных» контрактов по фиксированным адресам, которые выполняются не байткодом EVM, а нативной реализацией в клиенте. Их задача — выполнять тяжёлые операции (обычно криптографические) намного дешевле и быстрее, чем если бы их реализовали как обычный смарт-контракт.

Precompiles:

  • вызываются через CALL / STATICCALL как обычные контракты;
  • живут по заранее зарезервированным адресам (0x01, 0x02, …);
  • имеют чётко заданную формулу газа и поведение, описанное в спеках.

По сути, это «escape hatch» EVM: то, что теоретически можно сделать опкодами, но было бы слишком медленно или дорого по газу.

Предкомпилированные контракты EVM (precompiles): что это и какие есть в Ethereum

Чем precompiles отличаются от обычных контрактов

С точки зрения EVM precompile выглядит как обычный контракт:

  • ему передаётся calldata;
  • он потребляет газ;
  • возвращает return data или вызывает ошибку.

Но есть важные отличия:

  • у precompiles нет байткода в состоянии — логика зашита в реализацию клиента (geth, Nethermind, Besu и т.д.);
  • код и газ-формулы определены в спецификации протокола и меняются только хардфорком;
  • адреса фиксированы и одинаковы для всех сетей, которые следуют Ethereum Mainnet-spec.

Это промежуточный уровень между:

  • опкодами (опкоды EVM) — очень примитивные операции;
  • обычными контрактами — произвольная логика на байткоде.

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

Список precompiles в Ethereum (Mainnet)

На Ethereum Mainnet (после Byzantium, Istanbul и Cancun/Dencun) определены следующие precompiles по низким адресам:

  • 0x01ecRecover

Восстановление публичного ключа (и адреса) по ECDSA-подписи. Используется, например, в ecrecover(...) в Solidity.

  • 0x02SHA2-256

Вычисление SHA-256 от входных данных (стандартный SHA-2, в отличие от Keccak-256).

  • 0x03RIPEMD-160

Криптографический хеш-функция RIPEMD-160.

  • 0x04identity

Тривиальная функция «как есть»: возвращает то же, что получила. Полезна как базовая примитивная операция над данными.

  • 0x05modexp (модульная экспонентация)

Добавлен хардфорком Byzantium. Выполняет дорогую операцию base^exponent mod modulus c газом, зависящим от размеров аргументов.

  • 0x06, 0x07, 0x08операции на эллиптической кривой alt_bn128 (EIP-196/197):​
    • 0x06 — ecAdd
    • 0x07 — ecMul
    • 0x08 — ecPairing

Активно используются в zk-SNARK-схемах и протоколах, которым нужны парные проверки.

  • 0x09BLAKE2 F precompile (EIP-152, Istanbul)

Реализует компрессионную функцию F для BLAKE2b — помогает протоколам и проектам, где BLAKE2 основная хеш-функция.

  • 0x0AKZG point evaluation precompile (Cancun/Dencun, EIP-4844)

Нужен для верификации KZG-коммитментов в рамках протоданкшардинга и блоб-данных (данных L2). Без него rollup’ам приходилось бы использовать гораздо более дорогие по газу схемы.

Важно: этот набор относится именно к Ethereum Mainnet после Dencun. Другие EVM-совместимые сети (L2, sidechain’ы) могут:

  • поддерживать тот же набор;
  • добавлять дополнительные precompiles;
  • реализовывать «system contracts» или «predeploys» с похожими целями, но в другой форме.

Как вызываются precompiles и как считается газ

Вызов precompile на уровне EVM ничем не отличается от обычного контракта:

  • используется опкод CALL или STATICCALL;
  • указывается адрес от 0x01 до 0x0A;
  • передаётся calldata и лимит газа.

Дальше клиент:

  • смотрит, что адрес относится к precompile;
  • применяет описанную в спецификации функцию;
  • снимает газ по формуле, зависящей от размера и содержимого входных данных;
  • возвращает результат как return data.

Особенности:

  • газ-формула для каждой precompile задаётся в соответствующем EIP и, как правило, масштабируется с размером входа;
  • некоторые precompiles исторически «дешевели» (например, alt_bn128 в EIP-1108), чтобы сделать zk-примитивы доступнее;
  • если газа не хватило, результатом будет Out-of-Gas аналогично обычному контракту.

Зачем разработчику знать про precompiles

Понимание precompiles полезно в нескольких сценариях:

  • Криптография и zk-примитивы

Если протокол требует сложных криптоопераций (подписи, zk-доказательства, коммитменты), зачастую выгоднее опираться на уже существующие precompiles, а не реализовывать всё в «чистом» EVM.

  • Оптимизация газа

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

  • Кросс-чейн и L2-совместимость

Многие L2-решения позиционируют себя как «полностью EVM-эквивалентные», что включает не только опкоды, но и поддержку precompiles. При проектировании протокола стоит понимать, на какие precompiles вы завязаны (это влияет на переносимость и поддержку в других сетях).

См. также

Task Runner