Files
nexus/wiki/concepts/Checks-Effects-Interactions.md
2026-05-03 05:42:12 +08:00

2.6 KiB
Raw Blame History

title, type, tags, sources, last_updated
title type tags sources last_updated
Checks-Effects-Interactions Pattern concept
blockchain
security
smart-contract
reentrancy
best-practices
blockchain-security-auditor
2026-05-30

Aliases

  • Checks-Effects-Interactions
  • CEI Pattern
  • Checks-Effects-Interactions Pattern

Definition

Checks-Effects-InteractionsCEI检查-效果-交互)模式是智能合约安全编程的核心防御模式,用于防止重入攻击和其他逻辑漏洞。其核心原则是:在执行任何外部调用之前,先完成所有的状态检查和状态更新

Pattern

function withdraw() external {
    // 1. CHECKS — 验证前置条件
    require(balances[msg.sender] > 0, "No balance");
    
    // 2. EFFECTS — 更新合约状态(在外部调用之前)
    balances[msg.sender] = 0;
    
    // 3. INTERACTIONS — 执行外部调用(最后一步)
    (bool success,) = msg.sender.call{value: amount}("");
    require(success, "Transfer failed");
}

Why It Works

传统重入攻击利用的漏洞链:

外部调用ETH转账→ 攻击者receive()被触发 
→ 攻击者 re-enter withdraw() 
→ balances[msg.sender] 仍 > 0未清零
→ 重复提取资金

CEI 模式切断漏洞链:状态在外部调用之前清零,即使攻击者 re-enter条件检查阶段 require(balances[msg.sender] > 0) 已失败。

Common Mistakes

Wrong Order (Vulnerable)

// VULNERABLE: 外部调用在状态更新之前
(bool success,) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] = 0; // 攻击者可在此之前 re-enter

Missing Update (Vulnerable)

// VULNERABLE: 状态根本没有更新
require(balances[msg.sender] > 0);
(bool success,) = msg.sender.call{value: amount}("");
require(success);
// balances[msg.sender] = 0; ← 忘记更新!

ERC-20 Transfer Before Update

// VULNERABLE: ERC-20 transfer 触发外部调用
IERC20(token).transfer(msg.sender, amount); // 外部调用
balances[msg.sender] -= amount; // 状态更新太晚

Relationship to Other Defenses

  • CEI is the primary defense — should always be applied first
  • ReentrancyGuard is additional defense — use when CEI is difficult to apply (complex logic, callbacks)
  • CEI + ReentrancyGuard together provide defense in depth

Connections