# 账户抽象之路#4-聚合签名 **Published by:** [0xBitFly](https://paragraph.com/@0xbitfly/) **Published on:** 2023-04-03 **URL:** https://paragraph.com/@0xbitfly/4 ## Content 聚合签名我们当前的实现方案,是分别验证捆绑包中的每个用户操作,这是一种非常直接的验证方式,但会造成gas的浪费,检查签名最终可能会在 gas-wise 方面变得昂贵,因为这样做需要运行相当多的加密算法运算。 如果我们可以只用一个签名,而不是多个签名同时验证许多操作,那不是很好吗? 这样做取决于密码学中的一个概念,聚合签名。 支持聚合的签名方案提供了一种方法,给定多个使用不同密钥签名的消息,然后生成单个组合签名,验证这个组合签名,如果组合签名验证通过,那么下面所有的单个签名也都是合法的。(译注:有点类似于merkle tree,减少链上存储体积,这里是减少签名验证步骤) 常见的支持聚合签名的方案是 BLS。 这种优化对于实现卷叠(Rollup)特别有用,因为rollup的主要目的是数据压缩,而签名聚合让我们可以压缩签名部分。 有关签名聚合节省空间的更多信息,请参阅 Vitalik 关于该主题的推文。引入聚合我们立即看到,并非捆绑包中的所有用户操作都可以将其签名汇总在一起。请记住,钱包被允许使用它想要的任何逻辑来验证其给定的签名,因此同一捆绑包中可能存在各种签名方案。 由于我们可能无法聚合来自不同方案的签名,我们的捆绑包最终将产生N组操作,每个组使用不同的聚合方案或根本没有聚合方案。 由于我们需要在链上表示各种聚合方案,每个方案都有自己的逻辑,因此我们将让每个聚合方案用一个合约表示,我们将其称为聚合器。 一个聚合方案的定义是它如何将多个签名组合成一个,以及如何验证组合签名,因此聚合器有以下两个接口:contract Aggregator { function aggregateSignatures(UserOperation[] ops) returns (bytes aggregatedSignature); function validateSignatures(UserOperation[] ops, bytes signature); } 聚合器合约将多个用户的操作合并到一个具有单个签名的组合中由于每个钱包都有定义自己的签名方案,因此由每个钱包来决定它与哪个聚合器兼容(如果有的话)。 如果钱包想要参与聚合,它会提供一种获取其聚合器的方法contract Wallet { // ... function getAggregator() returns (address); } 使用这种新的getAggregator方法,打包者可以将具有相同聚合器的操作分组在一起,并使用该聚合器的aggregatorSignatures方法为它们计算组合签名。 一个组合看起来像这样:code struct UserOpsPerAggregator { UserOperation[] ops; address aggregator; bytes combinedSignature; } 如果打包者具有某一特定聚合器的链下知识(译注:源码?),则可以通过硬编码本机版本的签名聚合算法,来优化这一操作,而不是运行aggregateSignatures的EVM代码。接下来,我们需要更新入口点合约,才能使用新的聚合器。 回想一下,入口点有一个handleOps方法,它接收一个ops的列表作为输入参数。 我们将给它一个新方法,handleAggregatedOps,它做同样的事情,但接受的是按聚合器分组后的操作:contract EntryPoint { function handleOps(UserOperation[] ops); function handleAggregatedOps(UserOpsPerAggregator[] ops); // ... } 新方法handleAggregatedOps的工作原理与handleOps基本相同。唯一的区别在于它的验证步骤。 虽然handleOps通过调用每个钱包的validateOp方法来执行验证,但handleAggregatedOps将使用聚合器在每个组的组合签名上 调用聚合器的validateSignatures方法。执行者使用聚合器将用户操作分组,然后再将它们发送到入口点,因此它们都可以同时进行验证我们快完成了! 但这里有一个已经很熟悉的问题。 打包者希望模拟验证,并在打包之前验证这些聚合器的签名是合法的,因为如果验证失败,打包者将被迫支付gas费用。但具有任意逻辑的聚合器在模拟过程中很容易成功,但在执行过程中失败。 我们用之前代付者和工厂合约完全相同的方式解决这个问题:我们会限制聚合器可以访问哪些存储以及它可以使用哪些操作码,并要求它在入口点合约质押ETH,除非它不访问存储。 这就是聚合签名!热身我们在这里创建账户抽象是与ERC-4337的完整架构近乎一样的!只是细节上有一些差异,例如一些方法的名称和参数,但架构上几乎没什么大的差异了。如果我这篇文章解释的很好,你现在应该能够理解ERC-4337具体是什么样了。 如果你已经读到了这里了,非常感谢你阅读我这一版本的解释!我希望它能帮助你,就像它能帮助我一样。附录:与ERC-4337的差异虽然我们已经了解了帐户抽象的整体架构,但ERC-4337背后的聪明人想到了一些与我们上面描述略有不同的事情。 让我们来看看其中的一些!1. 验证时间范围上图,我对钱包的validateOp和代付者的validatePaymasterOp的返回类型非常困惑。ERC-4337找到了利用这一点的好方法。 钱包非常想做的事情是,只允许用户操作在一定时间内有效。否则,恶意的打包者可以让用户操作停留很长时间,然后在更长时间后将其包含在对打包者有利的捆绑包中。 钱包可以通过在验证期间检查TIMESTAMP来防止这种情况,以确保这个操作不是停留了太长时间,但它行不通,因为我们在验证期间禁止了TIMESTAMP,以防止线下模拟不准确的情况,这意味着钱包需要另一种方式来指示操作在什么时间有效。 因此,ERC-4337给了validateOp一个返回值,钱包可以使用该值来选择有效的时间范围:contract Wallet { function validateOp(UserOperation op, uint256 requiredPayment) returns (uint256 sigTimeRange); // ... } 此返回值表示验证有效的时间范围,用两个8字节整数表示。 ERC-4337的另一个注意事项:在验证失败的情况下,钱包应该从validateOp返回标识值(sentinel value),而不是回滚,这有助于估算gas费,因为eth_estimateGas不会告诉你在回滚的交易中使用了多少gas。2. 钱包合约和工厂合约任意数据调用我们的钱包接口是:contract Wallet { function validateOp(UserOperation op, uint256 requiredPayment); function executeOp(UserOperation op); } 在ERC-4337中,智能钱包实际上没有名为executeOp的方法。 相反,用户操作有一个callData字段:struct UserOperation { // ... bytes callData; } 这作为调用数据传递给钱包。 对于典型的智能合约,此数据的前四字节将被解释为函数标识符,其余字节将被解释为函数参数。 这意味着除了所需的validateOp方法外,钱包可以定义自己的接口,并且用户操作可用于调用钱包上的任意方法。 同样,在ERC-4337中,工厂合约实际上没有deployContract的方法,他们也接收任意的call数据,在这种情况下,是从操作的initCode字段接收。3. 代付者和工厂合约的压缩数据上面我们说过,用户操作包含指定代付者的字段,以及要传递给它的数据:struct UserOperation { // ... address paymaster; bytes paymasterData; } 在ERC-4337中,这些被合并到一个字段中作为优化,其中字段的前20个字节是代付者地址,其余是数据:struct UserOperation { // ... bytes paymasterAndData; } 工厂合约也是如此,虽然我们使用两个字段factory和factoryData,但ERC-4337将它们组合成一个字段initCode。 好的,你做到了! 我们希望您学到了很多关于帐户抽象的知识。更多内容https://mirror.xyz/0xbitfly.eth/ikaBggQNSvuiotOcdufHFST3Q8eiHujuKWrgeoeLL_0 https://mirror.xyz/0xbitfly.eth/pJGxqKDtogHVdULLhsw8iA0FTl-XbeeXD42ZSdsxdRc 原文链接: https://www.alchemy.com/blog/account-abstraction-aggregate-signatures ## Publication Information - [0xBitFly](https://paragraph.com/@0xbitfly/): Publication homepage - [All Posts](https://paragraph.com/@0xbitfly/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0xbitfly): Subscribe to updates