问题描述 编写 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
bysomeone commentedon Nov 11, 2026
已复现并定位,确认是 bug,不是预期行为。
根因是两处叠加:
hash(txHash || origin)(vm/runtime/instructions.go的opCreate)。同一笔交易里 origin 和 txHash 都不变,所以该交易内所有内部 CREATE 都拿到同一个地址。EVM.Create没有做地址碰撞检查,CreateAccount对已存在的账户静默跳过,随后SetCode直接覆盖——第二个子合约覆盖第一个,交易仍然返回成功。修复方式(以 fork 门控,fork 之前的区块执行结果不变):
CreateAddress(执行合约地址, 该合约 nonce),nonce 在创建前递增并落库,跨交易保持;ErrContractAddressCollision,并耗尽转发的 gas;ErrCodeStoreOutOfGas时整体回滚;CREATE/CREATE2 的 gas 改用 EIP-150 的 63/64 规则。一并处理的同类问题:CREATE2 目标地址已占用不报错、合约 nonce 从不持久化、CREATE2 的可用 gas 被砍半、ETH 签名交易的 CREATE2 value 精度与 CREATE 不一致。
一点已知边界:fork 之前部署的合约没有 nonce 记录(按 0 处理),它们 fork 后第一次内部 CREATE 派生出的地址与以太坊仍不完全一致;fork 之后部署的合约会完全对齐。
bysomeone commentedon Nov 11, 2026
修复已在 #1354 提交(draft)。同一 PR 一并处理 #1352 的 PUSH0(以及 BASEFEE),全部收在同一个分叉
ForkEVMCompat下。计价模型(EIP-2929/2200/3529 等)未纳入本次改动。分叉默认关闭,需部署时指定高度。