账户抽象第 4 部分:聚合签名
聚合签名
我们目前的实现是对 bundle 中的每个 user op 分别进行验证。这是一种非常直接的验证思路,但可能存在浪费。校验签名在 gas 上的开销可能偏高,因为这需要相当多的密码学运算。
如果能用一个签名同时验证多个 op,而不是逐一验证,岂不是更好?
要做到这一点,需要依赖密码学中的一个概念——聚合签名(aggregate signatures)。
支持聚合的签名方案提供了这样一种方式:给定多条用不同密钥签名的消息,可以生成一个合并后的签名,使得对该合并签名的验证能够蕴含所有组成签名均有效。
支持聚合的签名方案的一个常见例子是 BLS。
这项优化对实现 rollup 尤为有用,因为 rollup 的主要目标就是数据压缩,而签名聚合让我们能够压缩签名部分。
关于签名聚合带来的空间节省,可参见 Vitalik 关于此话题的推文。
引入 aggregator
我们马上会发现,并非 bundle 中所有 user op 的签名都可以聚合在一起。请记住,钱包可以使用任意逻辑来验证收到的签名,因此同一个 bundle 中可能存在多种不同的签名方案。
由于我们通常无法把不同方案的签名聚合在一起,最终的 bundle 会由若干组 op 构成,每一组使用某一种特定的聚合方案,或者不使用任何聚合方案。
由于链上需要表示多种聚合方案,且每种方案都有自己的逻辑,我们让每种聚合方案由一个合约来表示,我们称之为 aggregator。
一种聚合方案由两部分定义:如何将多个签名合并为一个,以及如何验证合并后的签名。因此,aggregator 会以方法的形式暴露这两个功能:

由于每个钱包都定义了自己的签名方案,因此是否兼容某个 aggregator(如果有的话)由每个钱包自行决定。
如果一个钱包想要参与聚合,它会暴露一个方法来选择自己的 aggregator:
借助这个新的 getAggregator 方法,bundler 可以把使用相同 aggregator 的 op 分为一组,并使用该 aggregator 的 aggregateSignatures 方法为它们计算出一个合并签名。
一个分组大致如下:
💡 如果 bundler 对某个特定 aggregator 有链下的了解,它可以进行优化:直接硬编码该签名聚合算法的原生版本,而不是将 aggregateSignatures 作为 EVM 代码来运行。
接下来,我们需要更新入口点合约,以便使用这些新的 aggregator。
回想一下,入口点有一个 handleOps 方法,接收一个 op 列表。
我们给它添加一个新方法, handleAggregatedOps,它做的事情基本相同,但接收的是按 aggregator 分组的 op:
新方法 handleAggregatedOps 的工作方式与 handleOps 基本相同,唯一的区别在于验证步骤。
handleOps 是通过调用每个钱包的 validateOp 方法来完成验证的,而 handleAggregatedOps 则会改为对每一组的合并签名,使用该组的 aggregator 调用其 validateSignatures 方法。

我们快完成了!
但这里还有一个到目前为止已经很熟悉的问题。
bundler 希望通过模拟验证来确认 aggregator 会验证通过一组 op,之后才将它们纳入 bundle,因为一旦验证失败,bundler 就得自己支付 gas。但一个具有任意逻辑的 aggregator,完全可能在模拟阶段成功,却在实际执行阶段失败。
我们会用和处理 paymaster、factory 时完全相同的方法来解决这个问题:限制 aggregator 能访问的存储以及能使用的操作码,并要求它在入口点中质押 ETH,除非它不访问存储。
聚合签名的部分到此结束!
总结
我们在这里构建出来的东西,基本上就是 ERC-4337 的完整架构!在一些细节上会有所不同,比如某些方法的名称和参数,但在架构层面,我认为已经没有任何差异了。如果我做得还不错,你现在应该已经能够阅读真正的 ERC-4337 并理解其中的内容。
如果你读到了这里,非常感谢你阅读我的讲解!希望这篇文章对你的帮助,能和它在写作过程中对我的帮助一样多。
附录:与 ERC-4337 的差异
尽管我们已经理清了账户抽象的整体架构,但 ERC-4337 背后的开发者们还考虑到了一些与上文描述略有不同的地方。
我们来逐一了解一下!
1. 验证时间范围
上文中,关于钱包的 validateOp 和 paymaster 的 validatePaymasterOp 的返回类型,我说得比较含糊。ERC-4337 找到了一种很好的方式来利用这一点。
钱包很希望能够做到的一件事,是只允许 user op 在一段特定的时间内有效。否则,恶意的 bundler 可能会把这个 op 扣留很长时间,然后在对自己更有利的时机才把它纳入某个 bundle。
钱包可能想通过在验证阶段检查 TIMESTAMP 来防范这一点,以确保它不会离当前时间太远,但它做不到,因为我们已经禁止在验证阶段使用 TIMESTAMP,以免模拟结果不准确。这意味着钱包需要另一种方式来表明该操作在哪个时间范围内有效。
因此,ERC-4337 给 validateOp 增加了一个返回值,供钱包用来选择时间范围:
这个返回值用两个先后排列的 8 字节整数,表示该操作有效的时间范围。
关于 ERC-4337 还有一点:钱包在验证失败时应当从 validateOp 返回一个哨兵值,而不是 revert,这样有助于 gas 估算,因为 eth_estimateGas 无法告诉你一笔 revert 的交易实际消耗了多少 gas。
2. 钱包和 factory 的任意 call data
我们之前说过,钱包的接口是:
在 ERC-4337 中,钱包实际上并没有一个叫做 executeOp 的方法。
取而代之的是,user operation 上有一个 callData 字段:
这个字段会作为 call data 传给钱包。
对于一般的智能合约来说,这段数据的前四个字节会被解释为函数选择器,其余部分则是函数参数。
这意味着,除了必需的 validateOp 方法之外,钱包可以自行定义接口,user operation 也可以被用来调用钱包上的任意方法。
同理,在 ERC-4337 中,factory 合约实际上也没有 deployContract 方法。它们同样接收任意的 call data,此处来自 op 的 initCode 字段。
3. paymaster 和 factory 的紧凑数据
上文中我们说过,user operation 包含用于指定 paymaster 以及传给它的数据的字段:
在 ERC-4337 中,作为一种优化,这些字段被合并成了一个字段,其中该字段的前 20 个字节是 paymaster 地址,其余部分是数据:
factory 及传给它的数据也是同样的道理:虽然我们之前用了 factory 和 factoryData 两个字段,但 ERC-4337 把它们合并成了一个字段 initCode。
好了,你做到了!
希望你从中学到了很多关于账户抽象的知识。
你本可以自己发明账户抽象
错过了这个四部分系列的开头?回去从头读起吧!
相关概览
钱包2026年9月2日
智能体钱包:AI 智能体的会话与权限模型
AI 智能体如何在不持有私钥的情况下获得受限且可撤销的钱包访问权限:会话、委托签名与即时撤销。
钱包2026年7月29日
别再把私钥粘贴进 Cursor 了:如何给你的编码 agent 配一个钱包
给你的编码 agent 配一个钱包,而不必把私钥交给它。了解 Alchemy CLI agent 钱包如何使用限定范围的会话,让 agent 无需在 .env 中存放私钥即可完成交易。
钱包2026年6月24日
什么是 crypto bundler?
crypto bundler 将多笔交易或操作合并为一次链上提交,应用于 batching、MEV、rollup、代币发行和账户抽象等场景。

构建区块链应用
Alchemy 将最强大的 Web3 开发者产品和工具与资源、社区及专业支持结合在一起。