为什么调用零地址时,assembly中的delegatecall()返回1而非0?
问题根因
这是不同EVM执行客户端的实现差异,不属于以太坊核心规则的变更,你之前在Ganache观察到的行为属于Ganache的非标准自定义逻辑:
- 原生EVM规则下,delegatecall的返回状态码为success(即1)的唯一前提是调用没有被显式终止/抛出异常。调用没有部署代码的账户(包括零地址)默认是执行成功的,仅返回空数据,状态码会返回
1,不会进入revert分支。零地址本身没有任何代码,触发调用相当于执行了空指令流,EVM不会主动抛出异常,这是符合黄皮书定义的标准行为。 - 旧版本Ganache为了降低开发者的调试成本,额外增加了零地址调用校验逻辑:当检测到
call/delegatecall/staticcall的目标为零地址时,会主动将调用状态置为失败返回0,这个逻辑是Ganache自行实现的,和主网行为不一致。你现在使用的Hardhat Network严格对齐主网EVM规则,所以表现为返回1进入成功分支。
修复建议
你可以选择以下任意一种方式修复该问题:
- 在Solidity层提前做合法性校验,避免进入assembly逻辑:
// 校验目标地址不为零 require(destination != address(0), "Invalid implementation address"); // 可选:额外校验目标地址确实部署了合约代码 require(destination.code.length > 0, "Implementation has no code");
- 直接在assembly块内增加校验逻辑,不需要额外提升到Solidity层:
// 在delegatecall执行前插入以下逻辑 if iszero(destination) { mstore(0x00, 0xa91947cd00000000000000000000000000000000000000000000000000000000) // 错误选择器,可自定义 revert(0x00, 0x04) }
内容的提问来源于stack exchange,提问作者Whytecrowe
相关产品推荐
相关产品推荐

