You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Attack合约调用GuessTheRandomNumberChallenge的guess()函数持续回退求助

问题排查:调用GuessTheRandomNumberChallenge.guess()触发回退的原因

以下是几种可能导致交易回退的核心原因及对应解决方案:

1. 攻击合约未实现ETH接收函数

当guess()调用成功时,目标合约会向攻击合约转账2 ETH。如果攻击合约没有定义receive()或fallback()函数,ETH转账会失败,进而触发整个交易回滚。这是最常见的触发回退的原因。

修复方式:在攻击合约中添加ETH接收函数:

// 必须添加,用于接收目标合约转来的奖励ETH
receive() external payable {}

2. 猜测的数值x计算错误

虽然错误的猜测不会直接触发交易回退,但如果测试代码中验证了isComplete()状态,会误以为是交易回退。目标合约的答案计算逻辑是在构造函数中执行的:

answer = uint8(uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))));

需要确保攻击合约(或测试代码)中使用与构造函数完全一致的参数计算x:

  • 如果在测试中,部署目标合约后立刻计算答案,需保证block.number和block.timestamp与构造函数执行时一致(可在同一个setUp或测试函数中连续执行)
  • 如果攻击合约在目标合约部署后的区块调用,需确保能正确获取目标合约构造时的blockhash(block.number -1)(区块哈希在256个块内可访问)

示例测试代码中正确计算答案的方式:

function testAttack() public {
    // 部署目标合约后立刻计算答案,此时block.number和timestamp与构造函数一致
    uint8 correctAnswer = uint8(uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))));
    
    vm.startPrank(attackerAddr);
    // 传入正确的答案调用攻击函数
    attacker.attack{value: 1 ether}(correctAnswer);
    assertTrue(challenge.isComplete());
    vm.stopPrank();
}

3. 交易ETH金额不匹配

目标合约的guess()函数要求调用时必须传入恰好1 ETH,如果攻击合约调用victim.guess{value: 1 ether}(x)时自身余额不足,或者测试中给攻击合约的ETH不够,会触发回退。

验证方式:

  • 确保测试代码中用vm.deal()给攻击地址分配足够的ETH(至少1 ETH)
  • 确保攻击合约的attack()函数被调用时传入了{value: 1 ether}

4. Solidity版本或ABI兼容性问题

如果目标合约和攻击合约使用的Solidity版本差异过大(比如目标用0.6.0,攻击用0.8.0),可能存在函数签名或编码差异导致调用失败。

修复方式:

  • 确保两个合约使用相同或兼容的Solidity版本(比如统一用^0.8.19)
  • 检查合约导入路径是否正确,避免ABI生成错误

内容的提问来源于stack exchange,提问作者nebula

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 05:58:40