文章深入探讨了在后 ZKEVM 时代,EIP-8141 帧交易与无状态或部分状态节点之间的技术冲突。分析了三种内存池策略对节点状态的需求,指出账户抽象(AA)导致的账户“增重”与无状态化趋势之间的结构性矛盾,并强调若验证状态需求过高,将削弱 FOCIL 的抗审查能力。
AA 与 EIP-8141 内存池策略如何在后 ZKEVM 世界中与无状态节点交互
ZKEVM 将重新执行(re-execution)替换为证明验证。一旦 SNARK 证明可以在毫秒内验证一个区块,节点就不再需要完整状态来参与共识。曾经要求每个全节点持有约 280 GB 状态的约束——即重新执行——消失了。剩下的需求是经济上的:构建者、RPC 提供商和搜索者持有状态,因为他们的业务依赖于此。除此之外的其他人都可以停止持有完整状态。
预期的应对方案是部分状态化(Partial Statefulness):节点持有完整的账户树(每个账户的 Nonce、余额、代码哈希和存储根),以及他们选择跟踪的合约的选择性存储。服务于 DeFi 协议的节点跟踪该协议的存储;专注于抗审查的节点除了账户之外什么都不跟踪。这种最低限度的方案——仅验证部分无状态(VOPS)——对于约 4 亿个账户来说,成本约为 10 GB。部分状态化(PS)位于 VOPS 之上:同样的完整账户树,加上选定合约的完整存储树,通过 区块访问列表 (EIP-7928) 而非重新执行来跟随链尖。
为什么这对比交易格式很重要?因为内存池的健康状况关乎抗审查性。能够本地验证交易的节点可以维护内存池,将交易传播给对等节点,并参与 FOCIL 包含列表 (EIP-7805)。如果一个节点无法验证某种交易类型,它就无法将其包含在包含列表中,无法强制其包含,该类交易的抗审查性就会默默退化。能够验证的节点越少,审查就越容易。在大多数节点都是部分状态化的后 ZKEVM 世界中,任何新的交易格式都必须针对这一现实进行评估。
如今,在内存池中验证交易的成本很低。对于遗留交易和 EIP-1559 交易,节点对签名运行 ecrecover 以推导出发送者,检查发送者的 Nonce,并验证发送者的余额是否足以支付交易成本。这是纯粹的计算加上一次账户查找。任何拥有账户树的节点(包括 VOPS 和 PS 节点)都可以做到这一点。
Frame 交易 (EIP-8141) 从根本上改变了这一点。Frame 交易在传统意义上没有加密签名。相反,交易显式声明其发送者,并将执行分解为有序的 frames。其中一个 frame 的模式为 VERIFY:它执行发送者的账户代码,该代码必须调用 APPROVE 操作码来授权交易。验证逻辑是任意的——它可以通过读取发送者的存储并执行账户代码定义的任何验证逻辑来实现任何签名方案(后量子、多签、社交恢复)。
这意味着验证节点需要发送者的字节码和验证期间访问的存储槽,而不仅仅是账户叶子节点中的两个字段(Nonce、余额)。而且发送者是一个智能合约钱包:它可以是网络上的任何账户。验证从“查找两个字段”转变为“针对任意账户状态执行任意代码”。

图:遗留交易验证仅需要账户树查找(约 3,000 Gas,所有节点类型)。Frame 交易验证需要针对发送者的字节码和存储执行 VERIFY frame(最高约 100k Gas,仅限具有相关状态的节点)。
EIP-8141 的内存池策略文档提出了三种渐进式的政策,用于规定公共内存池将接受哪些 frame 交易。每种策略都在无许可性与 DoS 保护之间进行权衡。这里重要的是每种策略对验证节点所需的状态要求。
策略 1 仅接受自筹资金的 frame 交易。VERIFY 期间的存储读取仅限于 tx.sender 的槽位,并且每个发送者允许一笔待处理的 frame 交易。但“发送者的代码和存储”值得仔细拆解——实际的状态占用取决于发送者的账户类型。
任何账户都可以发送 frame 交易。EIP 指定了三种验证路径:
APPROVE 来处理 VERIFY。没有存储读取,没有自定义字节码。这与验证遗留交易一样便宜——任何拥有账户树的节点(包括 VOPS)都可以做到。VERIFY 期间运行,读取发送者自己的存储。这很直接——节点需要发送者的代码和存储。0xef0100 || delegate_address)。当 EVM 在 VERIFY frame 中遇到这种情况时,它会跟随指针并加载委托合约的字节码——但在发送者的上下文中执行。address(this) 返回发送者的地址。SLOAD 读取发送者的存储树,而不是委托合约的。这在语义上与代理合约的工作方式相同:委托合约编译后的存储布局(槽 0 = owner,槽 1 = Nonce 等)针对发送者的原始键值存储进行解释。委托合约自身的存储永远不会被触及。这引发了一个问题:EOA 的存储从何而来?EOA 传统上拥有空的存储树。答案是:一旦 EOA 通过 SetCode 交易进行委托,随后的交易就会在 EOA 的上下文中执行委托代码——而 SSTORE 写入会进入 EOA 的存储树。第一次交互通常会初始化关键槽位(所有者地址、守护者、Nonce)。从那时起,EOA 在状态中其地址下携带一个真实的存储树,结构上与合约相同。
策略 1 的实际状态占用取决于发送者类型:
tx.sender 的账户叶子(Nonce、余额)。tx.sender 的存储槽以及辅助库字节码。
图:策略 1 VERIFY 执行的状态访问模式。存储读取(绿色箭头)始终解析为 tx.sender 的树。
策略 2 通过标准化的规范支付主合约增加了赞助交易。策略 2 通过 only_verify → pay 序列将验证分为两个 frame。
在策略 2 的赞助流程中,only_verify frame 针对 tx.sender——发送者的代码运行并调用 APPROVE 以授权执行但不承诺支付。然后 pay frame 针对规范支付主合约——支付主合约的代码运行,检查其存款余额,并调用 APPROVE 代表发送者授权支付。
规范支付主合约通过精确的运行时代码哈希进行识别。这是一种内存池策略,而非共识规则。支付主合约的安全性依赖于两个结构性约束:延迟提款和节点侧待处理余额跟踪。
在 pay frame 期间,规范支付主合约获得了通用 SLOAD 限制的豁免。它可以读取自己的存储(存款余额和提款时间戳)。
策略 2 的状态占用包括策略 1 的所有内容,外加:
这带来了一个风险:实例激增。由于规范支付主合约是通过代码哈希识别的,任何人都可以部署实例。如果存在成百上千个实例,状态需求就会随之增长。另一个风险是规范支付主合约的采用率。如果非规范实现获得多数采用,它们的交易将无法进入公共内存池,FOCIL 对此类交易也将失效。

图:策略 2 将验证分为两个 frame。实例激增决定了支付主状态负担是否受限。
策略 3 允许任意支付主合约——任何合约都可以充当支付主合约,通过质押和节点本地信誉系统进行门控。这是最宽松的策略,也是对状态要求最高的策略。
节点通过信誉系统管理 DoS 风险。状态占用在多个维度上是无限制的:
tx.sender 之外的其他合约的存储。Frame 交易与部分状态节点之间的紧张关系直接影响通过 FOCIL 实现的抗审查性。
Thomas Thiery 的提案 定义了一个 FOCIL 可以强制执行的 符合条件的子集,并引入了 AA-VOPS 概念。AA-VOPS 扩展了 VOPS,为每个账户缓存前 N 个存储槽(N 在 2-4 之间)。
AA-VOPS 部分解决了存储问题,但并未解决字节码可用性问题。如果 AA-VOPS 节点缺少委托合约的字节码,它仍然无法执行 VERIFY frame。这是一个开放的设计缺陷。
无论采取哪种策略,都存在一个根本性的紧张关系:账户抽象使账户变得更“重”,而无状态化需要账户保持“轻”。
原生 AA 通过两条路径改变了每个账户的权重:EIP-7702 委托赋予 EOA 非空代码字段和不断增长的存储树;EIP-8141 的 deploy frame 可以在单笔交易中将地址转换为完整的合约。
AA-VOPS 的 N 槽约束限制了每次验证读取的内容,但它并没有限制节点为验证来自任意发送者的 frame 交易而必须持有的总状态。如果 25% 的账户采用 AA 钱包,在 N=4 的情况下,验证关键状态集将增加约 15 GB,几乎使 VOPS 基准翻倍。

图:验证关键状态随 AA 采用率线性增长。虽然仍远低于 ~280 GB 的全状态,但 VOPS 的“底线”大幅上升。
这种方法还创建了一个二元系统。简单的钱包交易获得完整的 FOCIL 抗审查性,而需要更多资源的交易(如后量子签名验证、隐私协议交互)则被排除在合规子集之外。
| 节点类型 | 全节点 | PS (含支付主) | PS (无支付主) | VOPS | AA-VOPS |
|---|---|---|---|---|---|
| 账户 Nonce + 余额 | 是 | 是 | 是 | 是 | 是 |
| 委托 + 辅助字节码 | 是 | 若已跟踪 | 若已跟踪 | 否 | 否* |
| 发送者存储 (N 槽) | 是 | 若已跟踪 | 若已跟踪 | 否 | 是 |
| 支付主存储 | 是 | 若已跟踪† | 否 | 否 | 否 |
| 任意合约存储 | 是 | 否 | 否 | 否 | 否 |
| 策略 1 (自中继) | 是 | 部分 | 部分 | 否 | 否 |
| 策略 2 (规范支付主) | 是 | 部分–是† | 部分 | 否 | 否 |
| 策略 3 (ERC-7562) | 是 | 否 | 否 | 否 | 否 |
* AA-VOPS 缓存存储槽但不缓存字节码。VERIFY 执行需要委托代码。 † 兼容性取决于实例数量。
Frame 交易是原生账户抽象的强大原语,但它们带来了两个深层次的紧张关系。
首先是结构性的:无状态化需要账户保持精简,而账户抽象需要它们变得丰富。N 槽规则介导了这一点,但总状态仍随采用率线性增长。
其次是经济性的:策略 2 的抗审查保证仅适用于使用规范支付主合约的交易。如果用户转向功能更丰富的非规范支付主合约,这些交易将通过私有构建者路由,FOCIL 将无法覆盖大多数 AA 交易。
我们必须在考虑无状态化的前提下做出决策。一旦 ZKEVM 落地,绝大多数节点将是无状态或部分状态的——如果验证内存池所需的状态增长过大,几乎没有人能保持内存池健康或参与 FOCIL。如果我们搞错了规范支付主合约,那么即使是能负担得起状态的节点也无从强制执行,抗审查性将大幅退化。
- 原文链接: ethresear.ch/t/frame-tra...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!