Skip to content

EVM 合约内部 create(Solidity new)地址冲突:同一笔交易内 factory 创建的多个子合约地址相同,后者覆盖前者,且交易显示成功 #1351

Open

Description

@andyYuanFZM

问题描述
编写 factory 工厂模式合约(比如像: 发射平台 / 批量部署类场景)时,在同一笔交易内通过工厂合约连续 new 多个子合约:同一份合约代码在 BSC 上运行正常,但部署到 bityuan 链后,同一交易内创建的多个子合约得到相同的合约地址,后创建的子合约覆盖先创建的,导致工厂内的记录与实际合约状态错乱,内部逻辑出错。

示例合约:
contract Token { constructor() public {} }

contract Factory {
address[] public tokens;
function createTwo() external {
tokens.push(address(new Token())); // 第 1 次 new
tokens.push(address(new Token())); // 第 2 次 new —— 得到与第 1 次相同的地址
}
}

BSC:两次 new 得到两个不同的地址,一切正常。
bityuan:两次 new 返回完全相同的地址,交易状态仍为成功(status=1),无任何报错;第二个子合约实际覆盖了第一个

预期行为
同一工厂在同一笔交易内创建的多个子合约地址应该是互不相同(即使 init code 完全相同),若目标地址已存在应报错回滚。
合约内部 CREATE 的地址由“调用者合约 + 其递增 nonce”决定,bityuan的实现可能不是这样,可以对比以太坊的实现确认下。

Activity

  1. bysomeone commented on Nov 11, 2026

    @bysomeone
    Collaborator

    已复现并定位,确认是 bug,不是预期行为。

    根因是两处叠加:

    1. 内部 CREATE 的地址不是「创建者合约 + 其 nonce」,而是 hash(txHash || origin)(vm/runtime/instructions.go 的 opCreate)。同一笔交易里 origin 和 txHash 都不变,所以该交易内所有内部 CREATE 都拿到同一个地址。
    2. EVM.Create 没有做地址碰撞检查,CreateAccount 对已存在的账户静默跳过,随后 SetCode 直接覆盖——第二个子合约覆盖第一个,交易仍然返回成功。

    修复方式(以 fork 门控,fork 之前的区块执行结果不变):

    • CREATE 地址改为 CreateAddress(执行合约地址, 该合约 nonce),nonce 在创建前递增并落库,跨交易保持;
    • 新建合约 nonce 初始为 1(EIP-161);
    • CREATE/CREATE2 目标地址已有 nonce 或 code 时返回 ErrContractAddressCollision,并耗尽转发的 gas;
    • ErrCodeStoreOutOfGas 时整体回滚;CREATE/CREATE2 的 gas 改用 EIP-150 的 63/64 规则。

    一并处理的同类问题:CREATE2 目标地址已占用不报错、合约 nonce 从不持久化、CREATE2 的可用 gas 被砍半、ETH 签名交易的 CREATE2 value 精度与 CREATE 不一致。

    一点已知边界:fork 之前部署的合约没有 nonce 记录(按 0 处理),它们 fork 后第一次内部 CREATE 派生出的地址与以太坊仍不完全一致;fork 之后部署的合约会完全对齐。

  2. bysomeone commented on Nov 11, 2026

    @bysomeone
    Collaborator

    修复已在 #1354 提交(draft)。同一 PR 一并处理 #1352 的 PUSH0(以及 BASEFEE),全部收在同一个分叉 ForkEVMCompat 下。计价模型(EIP-2929/2200/3529 等)未纳入本次改动。分叉默认关闭,需部署时指定高度。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions