Материал проверен 2 ноября 2026?
БК

ГЛАВНАЯ / ИНСТРУКЦИИ / CHECKS-EFFECTS-INTERACTIONS: ПОРЯДОК ОПЕРАЦИЙ ПРОТИВ REENTRANCY

Checks-Effects-Interactions: порядок операций против reentrancy

Checks-Effects-Interactions (CEI) – способ упорядочить функцию: сначала проверить условия, затем зафиксировать изменения собственного состояния и только после этого обращаться к внешнему коду. Такой порядок уменьшает окно, в котором callback может использовать старые данные, но его нужно применять к целому инварианту и корректно обрабатывать отказ взаимодействия.

Три этапа

Проверки, эффекты и взаимодействия имеют разный смысл

Checks проверяют право вызвать функцию, корректность входных данных, статус протокола и достаточность баланса. Effects обновляют storage так, чтобы собственный учёт уже отражал результат операции. Interactions вызывают другой контракт или передают управление внешнему адресу.

В функции снятия средств безопасный порядок обычно означает: определить доступную долю, убедиться в условиях, уменьшить учётную долю и затем отправить актив. Если сначала отправить Ether, получатель-контракт может выполнить callback до обновления баланса. Пример описывает общий принцип, а не универсальную реализацию для любого токена или протокола.

  • checks определяют допустимость операции
  • effects приводят storage к согласованному состоянию
  • interactions передают управление после обновлений
ЭтапВопросПример
ChecksМожно ли выполнить действие?Доступ, сумма, статус и лимит
EffectsКак меняется внутреннее состояние?Обновить долю до передачи управления
InteractionsКуда передаётся управление?Внешний вызов или перевод актива
Порядок

Согласованное состояние нужно записать до callback

Перечислите все effects, которые должны считаться завершёнными до вызова наружу. Иногда это больше одной переменной: balance, reserved amount, nonce, статус заявки и aggregate total могут образовывать единый инвариант. Обновление только одного поля способно оставить связанную функцию в противоречивом состоянии.

Если внешний вызов возвращает ошибку, контракт должен явно определить результат. При bubbling revert внешняя транзакция откатывает изменения её call tree; при обработке false без повторного revert код может оставить обновлённое состояние, хотя передача актива не удалась. Оба поведения требуют осознанного соответствия логике протокола.

  • обновления охватывают весь инвариант
  • ошибка передачи обработана явно
  • неуспешное взаимодействие не выдаётся за успешное
Где применять

Проверяйте не только прямую передачу Ether

Внешнее взаимодействие может происходить при вызове произвольного контракта, token hook, отправке Ether или маршрутизации через router. Интерфейс функции не всегда сразу показывает, что реализация адреса может выполнить callback. Даже проверенный контракт может обратиться к другому адресу и вернуть управление через цепочку вызовов.

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

Ограничения паттерна

CEI не заменяет проверку всей модели состояния

CEI снижает риск reentrancy, но не доказывает корректность доступа, арифметики или экономической модели. Сложный протокол может требовать reentrancy guard, pull-payment схемы, отдельного статуса обработки или иной архитектуры. Если guard защищает только одну функцию, связанные entrypoint всё ещё нужно проверить вместе.

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

Проверка

Подтвердите порядок тестами на внешнем адресате

Создайте тестовый контракт-получатель, который в callback пытается вызвать исходный entrypoint и связанные функции. Проверьте, что он видит уже обновлённое состояние либо получает отказ без нарушения инварианта. Добавьте тест неуспешного внешнего вызова и убедитесь, что состояние и перевод согласованы.

В ревью отметьте места изменения storage и взаимодействия, а затем сопоставьте их с трассой теста. Проверяйте эффект транзакции целиком: событие об успешном выводе не должно появляться до подтверждённого шага, а остаток баланса должен соответствовать правилам контракта.

FAQ

Частые вопросы

В каком порядке расположены CEI этапы?

Checks, затем Effects, после них Interactions.

CEI гарантирует отсутствие всех атак?

Нет. Паттерн закрывает часть рисков порядка операций, но не заменяет аудит модели и доступа.

Если внешний вызов неуспешен, state всегда откатывается?

Только если ошибка откатывается вызывающим кодом. При обработке false без revert изменения могут сохраниться.

Нужно ли обновлять все переменные до callback?

Нужно привести к согласованному состоянию весь инвариант, который может увидеть внешний код.

Нужен ли reentrancy guard при CEI?

Зависит от пути вызовов и модели состояния; одно не исключает необходимости другого.

Итоговая проверка

Чек-лист: checks-effects-interactions: порядок операций против reentrancy

  • предусловия отделены от effects;
  • все связанные storage-поля найдены;
  • внешние взаимодействия перечислены;
  • инвариант согласован до callback;
  • ошибка взаимодействия обработана явно;
  • повторный вход проверен для связанных функций;
  • успешный результат подтверждается корректным состоянием и тестом.

Материал подготовлен редакцией сайта и проверен 2 ноября 2026 года. Условия бирж, кошельков и блокчейн-сетей могут меняться. Перед операцией сверяйте данные в интерфейсе выбранного сервиса.