账户抽象第 4 部分:聚合签名
聚合签名
我们目前的实现是分别验证 bundle 中的每个 user op。这是一种很直接的验证思路,但可能造成浪费。检查签名在 gas 上可能相当昂贵,因为这需要不少密码学运算。
如果能用一个签名而不是多个签名同时验证多个 op,岂不是更好?
要做到这一点,需要用到密码学中的一个概念——聚合签名。
一种支持聚合的签名方案提供了这样一种方式:给定多条用不同密钥签名的消息,可以生成一个组合签名,使得验证这个组合签名就意味着所有构成它的签名也都有效。
支持聚合的签名方案的一个常见例子是 BLS。
这项优化对于实现 rollup 特别有用,因为 rollup 的主要目标就是数据压缩,而签名聚合让我们能够压缩签名部分。
关于签名聚合带来的空间节省,可以参考 Vitalik 关于这个话题的推文。
引入 aggregator
我们马上会发现,一个 bundle 中的 user op 并非都能把签名聚合在一起。别忘了,钱包可以使用任意逻辑来验证给定的签名,所以同一个 bundle 里可能存在多种签名方案。
由于我们大概率无法把不同方案的签名聚合在一起,我们的 bundle 最终会包含若干组 op,每组使用一种独立的聚合方案,或者根本不使用聚合方案。
由于我们需要在链上表示各种聚合方案,并各自带有自己的逻辑,我们会用一个合约来表示每种聚合方案,我们称之为 aggregator。
一种聚合方案由两部分定义:如何把多个签名合并为一个,以及如何验证合并后的签名,所以 aggregator 会把这两个功能作为方法暴露出来:

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

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

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