不换地址换合约,还能怎么实现
合约升级的老办法是给旧地址配一个代理合约,把调用转发到新实现上,用户侧看到的地址不变,链上多了一个永远在线的转发层。2022 年 12 月 20 日提交的 EIP-6189 把这件事推到了极端:与其让转发逻辑写进代码,不如让协议亲自来做——把一个账户标记成”别名合约”,此后所有打到这个地址的调用、查询乃至交易验证,都由虚拟机自动改道到真正的合约上,转发代码本身根本不需要存在。

一个账户怎样才算别名合约
提案给出的判定条件苛刻到近乎奇怪:账户的 nonce 恰好等于 2 的 64 次方减 1,同时代码恰好是一个字节的 0x1,两者同时满足才算别名合约。这个 nonce 值不是随便挑的,它正是 EIP-6188 在序号封顶时专门预留下来的顶格值,见 序号用尽之前:EIP-6188 把 nonce 顶上的两个值留了出来;换句话说,6189 的魔法身份完全建立在 6188 留出的门牌号之上,提案的依赖声明里同时列着 EIP-2929 和 EIP-6188。真地址写在哪里?答案朴素得让人意外:别名合约自己存储布局的第 0 号槽,放的就是被别名合约指向的下一个合约的地址。
转发、路径压缩与只读例外
规则本身不难读。CALL、CALLCODE、DELEGATECALL、STATICCALL 等一切指令和 EOA 交易碰到别名为 2^64-1 的被调方时,必须改道去调第 0 号槽里的地址,链式多跳则一直追到第一个非别名合约为止,而 CALLER 全程保持不变——调用者在被调用合约眼里始终是原主。有一个反直觉的细节:如果路径上出现两级以上别名,除了最后一级,其余别名的第 0 号槽必须当场改写成最终目标的地址,也就是顺手做一次路径压缩;而且这动作即便发生在 STATICCALL 这种只读上下文里也必须执行。无限循环转发按提案的说法应当烧光 Gas 并回滚。
Gas 账本与 RPC 补漏
每走一个账户多收 25 Gas,提案解释这代表”取出 nonce 比对一下”的成本;每当场改写一个第 0 号槽,再收 5000 Gas。这些是在 EIP-2929 的状态访问费之上叠加的,别名单独看几乎免费,走完整条链的账单并不温柔。查询侧的漏洞也被堵了:eth_getStorageAt 对别名合约必须直接报错,因为那口第 0 号槽的行为已不是普通存储。ADDRESS 保持原义,永远指向那个没有顶格 nonce 的真实合约。
为什么停在 Stagnant
别名合约单看几乎没有独立价值:多花 Gas、多一层判定,却不做任何业务。它真正的用途必须与 EIP-6190 配套——后者想把 SELFDESTRUCT 改造成 Verkle 树兼容的形态:合约自毁后原地留下一个别名合约壳子,老地址上的调用自动流向新家,从用户视角看销毁变成无痛搬家。问题是这对双子提案双双停在 Stagnant,Verkle 路线本身近年也明显降温。今天的现实仍是代理合约与 EIP-7702 委托指示器的时代,销毁与存储清理相关的另一条清理线见 自毁合约留下的存储,谁来清:EIP-2936 与它的操作码之争。
交易验证也要过这道门
容易漏掉的是提案连交易发起方都没放过:如果交易 origin(最早签名发交易的那个账户)的 nonce 恰好是顶格值,验证阶段必须先把 origin 改写成其第 0 号槽指向的账户,一路循环直到遇到非别名账户才继续常规验证,同样按每个被访问账户 25 Gas 追加费用。这意味着别名身份甚至能”发交易”——签名仍然来自那把私钥,但协议眼里花钱和记账的主体已经是转发链末端的那个账户。设计者把这条写进规格,是为了让 6190 的自毁壳子不会变成只能收钱不能干活的死地址。读到这里可以把整套心智模型收拢成一句:别名合约是”用账户元数据实现的永久 301 重定向”,代码、事件、存储都属于新家,只有门牌号还挂在旧墙上当指示牌。
与普通钱包用户的关系
对钱包使用者来说,这个提案的实际意义是一条读链常识的反面教材:主网不存在 nonce 为 2 的 64 次方减 1、代码为 0x1 的转发合约,因为 6189 从未激活;区块浏览器里真看到这种形态的账户,只能说明遇到了部署者手写的模仿品或异常账户,绝不代表某个提案已生效。把”提案描述的行为”当成”链上存在的行为”,是读提案时最容易犯的错。本文只提供技术与防御信息,不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。