Смарт-контракты Ethereum: как они выполняются, откуда берётся газ и почему код нельзя изменить после деплоя

Смарт-контракт в Ethereum — это программа, хранящаяся в блокчейне по определённому адресу и выполняемая виртуальной машиной Ethereum (EVM). Он представляет собой набор функций (кода) и состояния (данных), которые детерминированно обрабатываются при каждой транзакции. В отличие от обычного серверного приложения, смарт-контракт не контролируется ни одним пользователем: после деплоя он работает строго так, как запрограммировано, а результат выполнения одинаков на каждом узле сети.

Смарт-контракт как тип аккаунта​


В Ethereum существует два типа аккаунтов:

ТипУправлениеМожет содержать кодИнициирует транзакции
EOA (Externally Owned Account)Приватный ключ пользователяНетДа
Contract AccountЛогика смарт-контрактаДаТолько в ответ на входящую транзакцию

Контрактный аккаунт имеет баланс в ETH, может быть получателем транзакций и хранит два ключевых поля:

  • codeHash — хеш байткода контракта.
  • storageRoot — корень дерева Меркла, описывающего состояние хранилища контракта.

EOA не может напрямую «запустить» контракт: он отправляет транзакцию, которая вызывает определённую функцию. Контракт, в свою очередь, может вызывать другие контракты и даже деплоить новые — это основа композируемости (composability) в экосистеме DeFi.

Жизненный цикл: от исходного кода до выполнения​


Написание и компиляция​


Смарт-контракты пишутся на языках высокого уровня — чаще всего Solidity или Vyper. Исходный код не исполняется напрямую: он компилируется в EVM-байткод — последовательность опкодов, которые понимает виртуальная машина Ethereum.

Компилятор также генерирует ABI (Application Binary Interface) — JSON-описание публичных функций контракта, их параметров и возвращаемых значений. ABI используется кошельками и dApp-фронтендами для корректного формирования вызовов.

Деплой​


Развёртывание контракта — это обычная транзакция, в которой поле to пустое, а поле data содержит байткод с аргументами конструктора. Адрес нового контракта вычисляется детерминированно из адреса отправителя и nonce транзакции.

После включения в блок байткод записывается в состояние сети и становится доступен для вызовов. Стоимость деплоя значительно выше, чем у простого перевода ETH, потому что газ расходуется на запись кода в хранилище.

Выполнение​


Когда EOA или другой контракт отправляет транзакцию на адрес смарт-контракта, EVM выполняет следующие шаги:

  1. Загружает байткод контракта по целевому адресу.
  2. Декодирует data транзакции с помощью ABI, определяя вызываемую функцию и аргументы.
  3. Исполняет опкоды последовательно, читая и записывая состояние в storage.
  4. Если выполнение завершается успешно — изменения состояния фиксируются. Если происходит revert — все изменения откатываются, но газ не возвращается.

Каждый узел сети выполняет одну и ту же транзакцию независимо. Детерминизм EVM гарантирует, что результат будет идентичным везде — это основа консенсуса.

Газ: почему выполнение стоит денег​


Газ — единица измерения вычислительной работы в EVM. Каждая операция (опкод) имеет фиксированную стоимость в газе. Например, сложение стоит дешевле, чем запись в storage или вызов другого контракта.

Пользователь задаёт два параметра транзакции:

  • gas limit — максимальное количество газа, которое он готов потратить.
  • gas price (или maxFeePerGas / maxPriorityFeePerGas после EIP-1559) — цена за единицу газа в wei.

Итоговая комиссия = использованный газ × цена газа. Если выполнение выходит за gas limit, транзакция откатывается с ошибкой out of gas, но комиссия всё равно списывается — валидатор уже потратил ресурсы на вычисление.

Газ выполняет две функции:

  1. Экономическая защита от спама. Бесконечный цикл или тяжёлое вычисление стоит реальных денег, что делает DoS-атаки экономически невыгодными.
  2. Компенсация валидаторам. Сборы за газ — часть вознаграждения за включение транзакции в блок.

При деплое контракта газ расходуется не только на выполнение конструктора, но и на запись байткода в состояние сети. Чем больше код, тем дороже деплой.

Почему код нельзя изменить после деплоя​


Иммутабельность смарт-контрактов — не ограничение, а архитектурное свойство, вытекающее из модели хранения данных в Ethereum:

  • Байткод контракта записан в состояние блокчейна и защищён хешем. Изменение кода потребовало бы пересчёта всех последующих блоков, что невозможно без контроля большинства вычислительной мощности (в PoS — большинства застейканного ETH).
  • Каждый узел хранит полную копию состояния. Нет единой точки, где можно было бы «подменить» код.
  • Транзакции необратимы: после включения в блок откатить или модифицировать результат нельзя.

Это означает, что ошибка в коде контракта остаётся навсегда. Если в логике есть уязвимость, злоумышленник может эксплуатировать её неограниченно долго.

Паттерны обхода иммутабельности​


На практике разработчики используют несколько подходов, когда нужна возможность обновления логики:

  • Proxy-паттерн. Адрес, на который пользователи отправляют транзакции, остаётся неизменным (proxy), но делегирует выполнение другому контракту (implementation). Владелец proxy может сменить адрес implementation, фактически обновив логику без изменения пользовательского интерфейса.
  • Diamond-паттерн (EIP-2535). Расширение proxy-подхода: один контракт делегирует вызовы нескольким implementation-контрактам (facets), что позволяет обойти лимит размера в 24 КБ и обновлять отдельные модули независимо.
  • Миграция. Деплой нового контракта и перенос состояния из старого. Требует явного действия пользователей или автоматизированного скрипта.

Все эти паттерны вводят элемент централизации: кто-то должен иметь право менять implementation. Поэтому при взаимодействии с proxy-контрактами важно проверять, кто владеет правом обновления.

Ограничения исполнения​


Лимит размера контракта​


Максимальный размер байткода смарт-контракта — 24 КБ (EIP-170). Контракт большего размера не может быть задеплоен. Это ограничение защищает сеть от атак, при которых злоумышленник загружает огромный код и затем вызывает его, заставляя каждый узел тратить непропорционально много ресурсов.

Отсутствие доступа к внешним данным​


Смарт-контракт не может самостоятельно запросить данные извне блокчейна: курс валюты, результат спортивного матча, показания датчика. Это ограничение заложено в архитектуру: если бы контракт зависел от внешнего источника, разные узлы могли бы получить разные данные и прийти к разным результатам, что разрушило бы консенсус.

Для передачи внешних данных используются оракулы — доверенные сервисы или децентрализованные сети (например, Chainlink), которые записывают офчейн-данные в блокчейн через транзакции.

Детерминизм и отсутствие случайности​


EVM не имеет доступа к генератору случайных чисел в привычном смысле. Все операции должны давать одинаковый результат на каждом узле. Для псевдослучайности используются хеши блоков или специализированные оракулы (VRF), но это всегда компромисс между случайностью и предсказуемостью.

Безопасность взаимодействия со смарт-контрактами​


Слепое подписание​


Когда кошелёк предлагает подписать транзакцию, он показывает адрес контракта и количество ETH, но не всегда понятно, какую именно функцию вы вызываете и какие разрешения даёте. Это называется blind signing — подписание без понимания последствий.

Риск: пользователь подписывает транзакцию, которая выдаёт неограниченное разрешение (approve) на списание токенов, и злоумышленник позже использует его для опустошения кошелька.

Экосистема движется к стандарту Clear Signing (ERC-7730), который переводит сырые данные транзакции в человекочитаемое описание: какая функция вызывается, какие параметры передаются, какие токены и в каком количестве затрагиваются.

Контроль разрешений (approvals)​


При взаимодействии с DeFi-протоколами контракты часто запрашивают разрешение на списание токенов ERC-20. Рекомендуется:


Проверка кода перед взаимодействием​


Поскольку смарт-контракты публичны, их байткод и исходный код (если верифицирован на Etherscan или аналогичном сервисе) доступны для аудита. Перед отправкой значительных средств стоит убедиться, что:

  • Контракт верифицирован и исходный код совпадает с байткодом.
  • Логика соответствует заявленной функциональности.
  • Нет неограниченных привилегий у владельца (owner), если только это не осознанный proxy-паттерн.

Мультисиг как защита от единой точки отказа​


Для контрактов, управляющих значительными средствами, применяется схема мультиподписи: транзакция выполняется только при наличии N подписей из M возможных участников. Типичные конфигурации — 3 из 5 или 4 из 7. Это защищает от потери одного приватного ключа и требует консенсуса нескольких сторон для критических действий.

Практический чек-лист перед взаимодействием с контрактом​


  • Проверьте, верифицирован ли контракт в блок-эксплорере.
  • Убедитесь, что адрес контракта совпадает с официальным источником (сайт проекта, документация).
  • Прочитайте сообщение транзакции перед подписанием; если кошелёк показывает только хеш — это признак blind signing.
  • Не выдавайте unlimited approve, если протокол не требует этого явно.
  • Для крупных сумм используйте аппаратный кошелёк Аппаратный кошелёк (hardware wallet): что это, как работает и где границы защиты с включённым режимом подтверждения на устройстве.
  • Если контракт использует proxy-паттерн, выясните, кто имеет право обновлять implementation и при каких условиях.

Источники​


 
Назад
Верх Низ