FOCIL ? 原生账户抽象 - Magicians

这篇文章深入探讨了FOCIL(EIP-7805)在处理原生账户抽象(AA)帧交易(EIP-8141)时的局限性。它提出了一个“合格帧交易”子集,针对其省略包含列表交易设计了更严格的检查机制,包括对post-state的有限VERIFY执行和每个包含列表的VERIFYGas预算,旨在增强审查抵抗能力。

作者:Thomas Thiery

感谢 Jihoon SongJulian MaToni WahrstätterVitalik Buterin 提供的反馈和建议。

摘要: FOCIL 通过针对后状态(post-state)使用廉价的 Nonce/余额代理检查被遗漏的包含列表(inclusion list,简称 IL)交易。这适用于 EOA,但不适用于原生 AA,因为后者的交易有效性需要执行 VERIFY 帧。本文定义了一个符合公共 mempool 条件的 FrameTx 子集,并具有更严格的遗漏检查:针对后状态的有界 VERIFY 执行,以及每个 IL 的 VERIFY-Gas 预算,以限制证明者(attester)的工作量。

背景

在执行区块后,FOCIL (EIP-7805) 会检查每个未被包含的 IL 交易:如果它符合剩余 Gas 要求,并针对后状态通过了 Nonce/余额检查,则该区块违反了 IL 条件,证明者将不会为其投票。

这种代理检查非常廉价(每个排除的交易只需一次账户查询,无需执行),并且在 EOA 和 EIP-7702 中表现良好,因为遗漏冲突会通过发送者 Nonce 和余额体现出来。

该提案不会改变 FOCIL 对 EOA 或 EIP-7702 交易的行为。以下所有内容仅适用于下文定义的符合条件子集中的帧交易(Frame Transactions,EIP-8141)。

符合条件的 FrameTxs

本文在两类 FrameTxs 之间划清了界限。

符合条件的 FrameTxs 是指同时被认为对公共 mempool 有效且受 FOCIL 强制执行的子集。符合条件的子集在设计上取自公共 mempool 符合条件的集合:任何对广泛传播不安全的 FrameTx 对 FOCIL 强制执行也是不安全的,但反之则不成立。所有其他 FrameTxs 仍然可以在选择性加入的替代 mempool 或私有订单流渠道中广播;它们的遗漏总是被允许的。

这反映了更广泛的 AA 生态系统。ERC-4337 使用替代 mempool;ERC-7562 定义了更严格的共享 mempool 规则以及独立的替代 mempool 规则。同样的原则也适用于此:FOCIL 强制执行仅涵盖已获准进行广泛公共传播的 FrameTxs。

为什么原生 AA 会破坏代理检查

与 EOA 不同,Frame Transaction 的有效性不能仅凭发送者状态来确定。VERIFY 帧必须针对状态执行并调用 APPROVE:支付者只能在此执行期间被发现,并且可能与发送者不同。这意味着 Nonce 和余额检查可以通过,但 VERIFY 可能会失败。没有廉价的代理:证明者必须重放验证前缀,以确定排除的符合条件的 FrameTx 是否应该被包含。

通过共享基础设施产生的冲突

AA 还引入了仅从交易字节无法察觉的冲突。考虑 TX_A 和 TX_B 都针对同一个赞助者进行验证:

// 伪代码;APPROVE 是一个 EVM 操作码 (根据 EIP-8141 为 0xaa)
function validateSponsorship() {
    require(address(this).balance >= MIN_RESERVE)
    APPROVE(payment)
}

如果 TX_A 被包含并收取了费用,赞助者的余额可能会降至 MIN_RESERVE 以下,使得 TX_B 在后状态下失效。这在后状态规则下会自然解决:任何在最终后状态下无效的交易都会被豁免。构建者也可以通过耗尽赞助者资金来蓄意进行审查攻击,从而一次性豁免许多遗漏;这会消耗区块资源,并且是任何后状态机制固有的。下面的有界状态访问规则(约束 5)限制了这种攻击面。

更广泛地说,共享合约存储可能允许单个包含的交易使许多排除的 FrameTxs 在后状态下失效,从而产生系统性的集体遗漏借口;约束 5 排除了这种情况。

符合条件的约束

符合条件的 FrameTx 是指满足以下所有约束 1-5 的 FrameTx。约束 1-4 是在Layer1(Tier 1)评估的静态检查;约束 5 是在第 3 层(Tier 3)VERIFY 执行期间评估的运行时检查。FrameTx 只有通过所有五项检查才符合条件。

约束分为两类:

静态检查可以从帧列表中检查,无需任何状态访问或执行。它们在Layer1执行。

运行时检查无法静态评估。它们在第 3 层 VERIFY 执行期间作为不符合条件的条件执行。触及不符合条件条件的交易将被豁免。

VERIFY Gas 权重

$$ \text{verify_gas}(tx) = \sum_{\text{frames with frame.mode} == \text{VERIFY}} \text{frame.gas_limit} $$

可从帧列表中计算,无需任何执行。

参数(初始,可调)

  • MAX_VERIFY_GAS_PER_FRAMETX (例如 100,000)
  • MAX_VERIFY_GAS_PER_INCLUSION_LIST (例如 250,000)

注意:使用这些参数,PQ 签名验证(Falcon, Dilithium)将超过 MAX_VERIFY_GAS_PER_FRAMETX,因此不符合 FOCIL 条件。PQ FrameTxs 最初仍可以通过替代渠道传播,其遗漏将始终被豁免。

静态检查 (Tier 1)

1. 验证前缀排序。 VERIFY 帧必须排在所有 DEFAULT 和 SENDER 帧之前。唯一的例外是合约创建帧 (to == null),它们可能出现在 VERIFY 帧之前,以部署正在验证的合约。这确保了证明者只需要执行创建和 VERIFY 帧来确定有效性,而不需要执行常规执行帧。

2. 每笔交易的有界 VERIFY Gas。 $\text{verify_gas}(tx) \le \text{MAX_VERIFY_GAS_PER_FRAMETX}$。超过此限制的交易不受限制;遗漏它们是被允许的。

3. 每个包含列表的 VERIFY 预算。 对于每个 IL,按声明的顺序扫描交易并构建预算子集:仅当添加候选 FrameTx 使得运行中的 verify_gas 总和保持在 MAX_VERIFY_GAS_PER_INCLUSION_LIST 或以下时,才包含该交易。不在任何 IL 的预算子集中的符合条件的 FrameTx 将被豁免。

同一个 FrameTx 可能会以不同的位置出现在多个 IL 中,并且可能被某些 IL 预算化,而未被其他 IL 预算化。证明者必须评估所有 IL,只要至少有一个 IL 为其提供了预算,就将其视为已预算。这提供了一种审查抗性属性:单个诚实的委员会成员如果将 FrameTx 列入预算内,就足以使其具有强制执行力,无论其他成员如何对其排序。

4. 基础交易完整性。 Chain ID 匹配,$\text{max_priority_fee_per_gas} \le \text{max_fee_per_gas}$,$\text{max_fee_per_gas} \ge \text{block.base_fee}$,解析有效,没有 blob(blob_versioned_hashes 为空,max_fee_per_blob_gas 为零)。

运行时检查(Tier 3 不符合条件的情况)

5. 有界状态访问。 VERIFY 仅能读取发送者和支付者账户状态(余额、Nonce、代码)以及它们的前 $N$ 个存储插槽,其中 $N$ 在 2-4 的范围内(确切值待基准测试)。超出此范围的读取将使交易不符合条件。

Mempool 节点在准入时重放 VERIFY,而不执行完整的区块。将读取限制在账户状态加上少量固定的存储插槽,意味着每个节点都确切地知道要获取什么:一个小的、确定性的集合,而不会暴露在按需进行的任意存储查询中。该约束存在于符合条件层,以便 mempool 准入和 FOCIL 强制执行在同一个符合条件的集合上保持同步。

选择 $N$ 插槽限制是为了与 AA-VOPS 保持一致,AA-VOPS 通过让节点为每个账户缓存少量存储插槽来扩展 VOPS。大多数智能钱包将其 Nonce、所有者和守护者存储在插槽 0-3 中,因此 $N$ 个插槽足以涵盖常见的验证模式。当 AA-VOPS 完全规范化时,将固定 $N$ 的确切值。

推荐的 mempool 策略(非共识)

每个发送者的待处理限制: 每个发送者最多一个待处理的受限 FrameTx(或深度为 D 的有界 Nonce 链),反映了 EIP-7702。

每个支付者的风险追踪: 追踪每个支付者的累积最坏情况费用风险 ($\text{tx_gas_limit} \times \text{max_fee_per_gas}$),当其超过 $\text{state[payer].balance} \times \alpha$(对于某些安全因子 $\alpha < 1$)时,剔除优先级最低的交易。

确定性验证环境: 拒绝其 VERIFY 访问不稳定的区块环境操作码(TIMESTAMPNUMBERCOINBASEBLOCKHASH 等)的 FrameTxs。这是一个 mempool 准入规则,而不是 FOCIL 符合条件约束:证明者针对这些操作码具有确定性的固定后状态重放 VERIFY。Mempool 节点通过在准入时追踪 VERIFY 来强制执行此规则,遵循 EIP-7562 的方法。

构建 (Building)

对于符合条件的 FrameTxs,Nonce/余额代理被替换为针对后状态 $S$ 的 EIP-8141 验证前缀的有界重放。如果被排除的符合条件的 FrameTx 在 $S$ 下有效且符合 gas_left,则该区块不满足 IL 条件。

在构建 Payload 之后,构建者迭代地追加剩余的符合条件的 IL FrameTxs:

  1. 尝试追加每个剩余的符合条件的 IL FrameTx。
  2. 如果有任何成功的,使用更新后的状态从步骤 1 重复。
  3. 当一轮完整的尝试没有追加任何内容时停止。

在被排除的符合条件的 IL FrameTxs 数量上,这是 $O(k^2)$ 的。来自同一发送者的顺序 Nonce 会被自然处理:TX_A(Nonce N)首先被追加,然后 TX_B(Nonce N+1)在稍后的轮次中匹配。

该循环保证了一个不动点:在最终的后状态下,没有被遗漏的符合条件的 FrameTx 是有效的。这是正确的目标;不需要贪婪的最大化打包,不动点属性对于完全的审查抗性已经足够。

这不是一个强制性的算法。构建者可以使用任何达到相同结果的策略。

Engine API。 EIP-7805 已经提出了与 IL 相关的 newPayloadforkchoiceUpdated 更改。通过感知 FrameTx 的检查,EL 还需要完整的有序非冲突(non-equivocating)IL 视图来运行 Tier 1–3 逻辑。这是对现有依赖关系的改进,需要两个 EIP 之间进行明确的协调。

构建优化(非规范性)。 按 Nonce 预排序同一发送者的 FrameTxs。将共享支付者的 FrameTxs 分组,并根据该支付者的预算进行选择,从而在典型条件下将循环减少到少量的轮次。

验证 (Verification)

在整个验证过程中,有两个属性是独立追踪的。符合条件性由约束 1-5 确定:违反任何约束的 FrameTx 无论其是否能成功执行都会被豁免。有效性由 EIP-8141 执行语义确定:如果未触发失效条件,则 FrameTx 在给定状态下有效。FrameTx 必须在后状态 $S$ 下既符合条件又有效,并满足 Tier 2 检查,才能构成 FOCIL 违规。

每一层都在上一层的输出基础上运行。Layer1从所有 IL 中获取所有交易,并生成一组通过静态检查的被排除 FrameTxs 的候选集 $C$。Layer2获取 $C$ 并过滤出满足 Nonce 和 Gas 适应性的交易。第 3 层获取该过滤后的集合,应用运行时检查,并识别其遗漏违反 IL 条件的交易。

在后状态下有效 在后状态下无效
符合条件 如果被遗漏则属于 FOCIL 违规(假设 Tier 2 通过)。示例:结构良好的 VERIFY,调用了 APPROVE,支付者有偿付能力。 豁免。示例:执行了 VERIFY 但未调用 APPROVE,或支付者余额不足。
不符合条件 豁免。示例:VERIFY 读取了超出 $N$ 插槽限制(约束 5)的第三方存储插槽,但除此之外会成功。 豁免。示例:违反了约束 5 且未调用 APPROVE。

Tier 2(Nonce 和 Gas 适应性)是“符合条件+有效”单元格的进一步条件;那里的失败也会被豁免。

证明者扫描所有 IL 交易(不仅仅是被排除的交易),以确定哪些 FrameTxs 满足Layer1的静态检查。只有 $C$ 中被排除的 FrameTxs 进入Layer2和第 3 层。

Tier 1:静态检查(无状态访问,无执行)

对于所有 IL 中的每笔交易 $T$:

  • 如果 $T$ 已包含在区块中:跳过。
  • 如果 $T$ 不是 FrameTx:应用标准的 Nonce/余额代理并跳过。
  • 如果 $T$ 未通过约束 1-4:豁免。
  • 否则:将 $T$ 添加到候选集 $C$。

$C$ 是Layer2的输入。

约束 1-4 简述:

  • VERIFY 优先排序成立。
  • $\text{verify_gas}(tx) \le \text{MAX_VERIFY_GAS_PER_FRAMETX}$。
  • 交易在至少一个 IL 的预算子集中。
  • 交易完整性通过(包括没有 blob)。

Tier 2:Nonce + Gas 适应性(仅读取后状态)

  • $\text{tx.nonce} == S[\text{tx.sender}].\text{nonce}$
  • $\text{tx_gas_limit} \le \text{gas_left}$

其中:

  • $\text{gas_left} = \text{block_gas_limit} - \text{total_gas_used}$(包括追加的 IL FrameTxs)
  • $\text{tx_gas_limit} = \text{FRAME_TX_INTRINSIC_COST} + \text{calldata_cost} + \sum \text{frame.gas_limit}$

若任一检查失败:豁免。否则进入第 3 层。

Tier 3:有界验证前缀重放(后状态)

针对后状态 $S$ 执行 EIP-8141 验证前缀(VERIFY 帧的有序序列),重放精确的帧语义,包括 ORIGIN 行为和批准状态。应用运行时检查(约束 5);不符合条件则豁免。

验证前缀完成后,如果识别出支付者,检查其偿付能力:

$$ \text{required_balance} = \text{tx_gas_limit} \times \min(\text{tx.max_fee_per_gas}, \text{block.base_fee} + \text{tx.max_priority_fee_per_gas}) $$

无偿付能力:豁免。在后状态下有效且符合 gas_left:区块不满足 IL 条件。

Tier 3 的 FrameTx 符合条件和有效性条件

如果 FrameTx 未触及失效条件,则其在给定状态下有效。非 VERIFY 帧 revert 不会使交易无效;VERIFY 帧在没有 APPROVE 的情况下终止会使交易无效。

  • $\text{tx.chain_id} == \text{block.chain_id}$
  • $\text{tx.max_priority_fee_per_gas} \le \text{tx.max_fee_per_gas}$
  • $\text{tx.max_fee_per_gas} \ge \text{block.base_fee}$
  • $\text{tx.nonce} == \text{state[tx.sender].nonce}$
  • 所有 VERIFY 帧必须以 APPROVE 终止;revert、out-of-gas 或没有 APPROVE 的终止:无效。
  • 必须在设置 payer_approved 之前建立 sender_approved;在所有 VERIFY 帧完成后,payer_approved 必须为 true。

不符合条件的条件(约束 5)会豁免交易,无论其余有效性条件是否已满足。

安全考虑

DoS 抗性

  • 每笔交易: 通过构造满足 $\text{verify_gas}(tx) \le \text{MAX_VERIFY_GAS_PER_FRAMETX}$。
  • 每个 IL: 每个 IL 最多贡献 MAX_VERIFY_GAS_PER_INCLUSION_LIST 的 Tier 3 工作量。证明者通过交易哈希跨 IL 进行去重,每个唯一交易仅执行一次验证前缀。
  • 每个 Slot: 拥有 16 个成员的 IL 委员会的最坏情况是 $16 \times \text{MAX_VERIFY_GAS_PER_INCLUSION_LIST}$。使用建议的参数:每个 slot 4,000,000 VERIFY-Gas。控制 $m$ 个 slot 的攻击者最多强迫产生 $m \times \text{MAX_VERIFY_GAS_PER_INCLUSION_LIST}$ 的工作量。

这些数字仅限制证明者的工作量。构建者端的重放成本更高;见“待解决问题”中的构建者复杂性。

大规模失效

约束 5 排除了基于存储的共享验证依赖,这涵盖了主要的大规模失效向量。共享支付者余额仍然可能被耗尽以使多个 FrameTxs 失效,但这受区块资源成本限制。

审查抗性

在后状态 $S$ 下有效且符合 gas_left 的符合条件的 FrameTx 必须被包含。构建者无法对此类交易声明豁免。

替代方案:基于索引的验证

如果追加循环证明是不切实际的,构建者可以通过证明交易在声明的索引处无效来豁免排除。构建者提供交易哈希和声称的索引;证明者使用 BAL (EIP-7928) 或类似的区块级访问数据重建该索引处的状态,并重新执行验证前缀。无论如何,仍然需要 VERIFY Gas 限制。

这消除了 $O(k^2)$ 的追加循环,但引入了一个新的网络对象(构建者的索引声明),并将证明责任转移给了构建者,构建者对他们声明哪个索引具有完全控制权。

待解决问题

构建者复杂性。 EL 客户端在实践中的迭代重试成本有多高,它会增加多少 slot 时间延迟?作为一个参考点:在 16 个 IL 委员会成员中有 4 个是恶意的情况下,证明者面临最多 1,000,000 VERIFY-Gas 的重放工作,约占 60M 区块 Gas 限制的 1.7%。但构建者面临的压力显著更高:$O(k^2)$ 追加循环在最坏情况下运行 $k(k+1)/2$ 次重放。如果 $k=16$ 个唯一被排除的符合条件的 FrameTxs,即 $16 \times 17 / 2 \times \text{MAX_VERIFY_GAS_PER_FRAMETX} = 13.6\text{M VERIFY-gas}$,约占 60M 区块 Gas 限制的 22.7%。

AA-VOPS 缓存大小。 约束 5 中的前 $N$ 个存储插槽限制需要根据 AA-VOPS 缓存设计进行校准。$N$ 的精确值 (2–4) 需要针对真实的智能钱包验证模式进行基准测试。

扩展读取的见证(Witnesses)。 除了 AA-VOPS 缓存之外,如果受限 FrameTxs 可以附加见证(值 + Merkle 证明)用于额外的验证读取,那么适用什么样的时效性和根规则,以及谁随着 head 的变化而刷新证明?

参数变更。 MAX_VERIFY_GAS_PER_FRAMETXMAX_VERIFY_GAS_PER_INCLUSION_LIST 需要进行基准测试。

Engine API 细节。 需要具体规范来确定 newPayload / forkchoiceUpdated 如何将有序的 IL 集合传递给 EL。

  • 原文链接: ethereum-magicians.org/t...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
以太坊中文
以太坊中文
以太坊中文, 用中文传播以太坊的最新进展