Смарт-контракт в Ethereum — это программа, хранящаяся в блокчейне по определённому адресу и выполняемая виртуальной машиной Ethereum (EVM). Он представляет собой набор функций (кода) и состояния (данных), которые детерминированно обрабатываются при каждой транзакции. В отличие от обычного серверного приложения, смарт-контракт не контролируется ни одним пользователем: после деплоя он работает строго так, как запрограммировано, а результат выполнения одинаков на каждом узле сети.
В Ethereum существует два типа аккаунтов:
Контрактный аккаунт имеет баланс в ETH, может быть получателем транзакций и хранит два ключевых поля:
EOA не может напрямую «запустить» контракт: он отправляет транзакцию, которая вызывает определённую функцию. Контракт, в свою очередь, может вызывать другие контракты и даже деплоить новые — это основа композируемости (composability) в экосистеме DeFi.
Смарт-контракты пишутся на языках высокого уровня — чаще всего Solidity или Vyper. Исходный код не исполняется напрямую: он компилируется в EVM-байткод — последовательность опкодов, которые понимает виртуальная машина Ethereum.
Компилятор также генерирует ABI (Application Binary Interface) — JSON-описание публичных функций контракта, их параметров и возвращаемых значений. ABI используется кошельками и dApp-фронтендами для корректного формирования вызовов.
Развёртывание контракта — это обычная транзакция, в которой поле
После включения в блок байткод записывается в состояние сети и становится доступен для вызовов. Стоимость деплоя значительно выше, чем у простого перевода ETH, потому что газ расходуется на запись кода в хранилище.
Когда EOA или другой контракт отправляет транзакцию на адрес смарт-контракта, EVM выполняет следующие шаги:
Каждый узел сети выполняет одну и ту же транзакцию независимо. Детерминизм EVM гарантирует, что результат будет идентичным везде — это основа консенсуса.
Газ — единица измерения вычислительной работы в EVM. Каждая операция (опкод) имеет фиксированную стоимость в газе. Например, сложение стоит дешевле, чем запись в storage или вызов другого контракта.
Пользователь задаёт два параметра транзакции:
Итоговая комиссия = использованный газ × цена газа. Если выполнение выходит за gas limit, транзакция откатывается с ошибкой out of gas, но комиссия всё равно списывается — валидатор уже потратил ресурсы на вычисление.
Газ выполняет две функции:
При деплое контракта газ расходуется не только на выполнение конструктора, но и на запись байткода в состояние сети. Чем больше код, тем дороже деплой.
Иммутабельность смарт-контрактов — не ограничение, а архитектурное свойство, вытекающее из модели хранения данных в Ethereum:
Это означает, что ошибка в коде контракта остаётся навсегда. Если в логике есть уязвимость, злоумышленник может эксплуатировать её неограниченно долго.
На практике разработчики используют несколько подходов, когда нужна возможность обновления логики:
Все эти паттерны вводят элемент централизации: кто-то должен иметь право менять implementation. Поэтому при взаимодействии с proxy-контрактами важно проверять, кто владеет правом обновления.
Максимальный размер байткода смарт-контракта — 24 КБ (EIP-170). Контракт большего размера не может быть задеплоен. Это ограничение защищает сеть от атак, при которых злоумышленник загружает огромный код и затем вызывает его, заставляя каждый узел тратить непропорционально много ресурсов.
Смарт-контракт не может самостоятельно запросить данные извне блокчейна: курс валюты, результат спортивного матча, показания датчика. Это ограничение заложено в архитектуру: если бы контракт зависел от внешнего источника, разные узлы могли бы получить разные данные и прийти к разным результатам, что разрушило бы консенсус.
Для передачи внешних данных используются оракулы — доверенные сервисы или децентрализованные сети (например, Chainlink), которые записывают офчейн-данные в блокчейн через транзакции.
EVM не имеет доступа к генератору случайных чисел в привычном смысле. Все операции должны давать одинаковый результат на каждом узле. Для псевдослучайности используются хеши блоков или специализированные оракулы (VRF), но это всегда компромисс между случайностью и предсказуемостью.
Когда кошелёк предлагает подписать транзакцию, он показывает адрес контракта и количество ETH, но не всегда понятно, какую именно функцию вы вызываете и какие разрешения даёте. Это называется blind signing — подписание без понимания последствий.
Риск: пользователь подписывает транзакцию, которая выдаёт неограниченное разрешение (approve) на списание токенов, и злоумышленник позже использует его для опустошения кошелька.
Экосистема движется к стандарту Clear Signing (ERC-7730), который переводит сырые данные транзакции в человекочитаемое описание: какая функция вызывается, какие параметры передаются, какие токены и в каком количестве затрагиваются.
При взаимодействии с DeFi-протоколами контракты часто запрашивают разрешение на списание токенов ERC-20. Рекомендуется:
Поскольку смарт-контракты публичны, их байткод и исходный код (если верифицирован на Etherscan или аналогичном сервисе) доступны для аудита. Перед отправкой значительных средств стоит убедиться, что:
Для контрактов, управляющих значительными средствами, применяется схема мультиподписи: транзакция выполняется только при наличии N подписей из M возможных участников. Типичные конфигурации — 3 из 5 или 4 из 7. Это защищает от потери одного приватного ключа и требует консенсуса нескольких сторон для критических действий.
Смарт-контракт как тип аккаунта
В 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 выполняет следующие шаги:
- Загружает байткод контракта по целевому адресу.
- Декодирует
dataтранзакции с помощью ABI, определяя вызываемую функцию и аргументы.
- Исполняет опкоды последовательно, читая и записывая состояние в storage.
- Если выполнение завершается успешно — изменения состояния фиксируются. Если происходит revert — все изменения откатываются, но газ не возвращается.
Каждый узел сети выполняет одну и ту же транзакцию независимо. Детерминизм EVM гарантирует, что результат будет идентичным везде — это основа консенсуса.
Газ: почему выполнение стоит денег
Газ — единица измерения вычислительной работы в EVM. Каждая операция (опкод) имеет фиксированную стоимость в газе. Например, сложение стоит дешевле, чем запись в storage или вызов другого контракта.
Пользователь задаёт два параметра транзакции:
- gas limit — максимальное количество газа, которое он готов потратить.
- gas price (или maxFeePerGas / maxPriorityFeePerGas после EIP-1559) — цена за единицу газа в wei.
Итоговая комиссия = использованный газ × цена газа. Если выполнение выходит за gas limit, транзакция откатывается с ошибкой out of gas, но комиссия всё равно списывается — валидатор уже потратил ресурсы на вычисление.
Газ выполняет две функции:
- Экономическая защита от спама. Бесконечный цикл или тяжёлое вычисление стоит реальных денег, что делает DoS-атаки экономически невыгодными.
- Компенсация валидаторам. Сборы за газ — часть вознаграждения за включение транзакции в блок.
При деплое контракта газ расходуется не только на выполнение конструктора, но и на запись байткода в состояние сети. Чем больше код, тем дороже деплой.
Почему код нельзя изменить после деплоя
Иммутабельность смарт-контрактов — не ограничение, а архитектурное свойство, вытекающее из модели хранения данных в 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. Рекомендуется:
- Устанавливать лимит approvals только на необходимую сумму, а не на
uint256.max.
- Периодически проверять активные разрешения и отзывать неиспользуемые. Подробнее — в материале Token approvals в Ethereum: что даёт разрешение смарт-контракту и как отозвать лишние доступы.
Проверка кода перед взаимодействием
Поскольку смарт-контракты публичны, их байткод и исходный код (если верифицирован на Etherscan или аналогичном сервисе) доступны для аудита. Перед отправкой значительных средств стоит убедиться, что:
- Контракт верифицирован и исходный код совпадает с байткодом.
- Логика соответствует заявленной функциональности.
- Нет неограниченных привилегий у владельца (owner), если только это не осознанный proxy-паттерн.
Мультисиг как защита от единой точки отказа
Для контрактов, управляющих значительными средствами, применяется схема мультиподписи: транзакция выполняется только при наличии N подписей из M возможных участников. Типичные конфигурации — 3 из 5 или 4 из 7. Это защищает от потери одного приватного ключа и требует консенсуса нескольких сторон для критических действий.
Практический чек-лист перед взаимодействием с контрактом
- Проверьте, верифицирован ли контракт в блок-эксплорере.
- Убедитесь, что адрес контракта совпадает с официальным источником (сайт проекта, документация).
- Прочитайте сообщение транзакции перед подписанием; если кошелёк показывает только хеш — это признак blind signing.
- Не выдавайте unlimited approve, если протокол не требует этого явно.
- Для крупных сумм используйте аппаратный кошелёк Аппаратный кошелёк (hardware wallet): что это, как работает и где границы защиты с включённым режимом подтверждения на устройстве.
- Если контракт использует proxy-паттерн, выясните, кто имеет право обновлять implementation и при каких условиях.
