近来,以太坊『账户抽象』的议题再次引发讨论。在 5 月份的 EthShanghai 活动上,我向 Vitalik 询问 ERC-4337 的提出是否意味着以太坊协议层的账户抽象会暂时停滞。他解释道核心开发者正忙于合并大业,一时半会顾不过来,而 ERC-4337 不是一个协议层的更新,无需硬分叉,推动的难度会小很多。
本文不会分析 ERC-4337 做了什么,可阅读提案或中文解读。本文希望在尽可能少引入专业术语的情况下把账户抽象讲明白。
什么是账户?本文不想引用会计学上的定义,而是用更直白的说法。以太坊是去中心的账本,客户在账本上的数字映射及对应的资产、交易记录共同构成了客户的账户。
以太坊的账户包含哪些要素呢?其实并不复杂——账户标识符、验证方式、状态。默认存在的账户称为外部账户(EOA),它的标识符(地址)为 0x前缀连接 40 位的十六进制数。如何计算地址呢?首先,你拥有基于椭圆曲线secp256k1的一个公私钥对,并对公钥进行 Keccak-256 哈希运算,取其最后 20 字节即可。外部账户的验证方式是什么呢?进行任何链上操作时,你需要提交与其公钥对应的签名,此外还得包含一个特定的一次性数值(nonce),以防止被别人利用(重放)。除了外部账户以外还有什么账户类型呢?这就是智能合约账户,其标识符(地址)也是同样的格式和长度,仅从标识符无法区分两种账户类型。智能合约账户是如何验证权限的?很简单,由代码决定。而对于两种账户来说,状态都是指关联该账户标识符的数据信息。
接下来这段话很重要,这是大多数讨论中容易忽视的部分,它决定你是否能真正理解『账户抽象』的动机。
『账户』抽象中的『账户』,与『外部账户』、『智能合约账户』中的『账户』并非完全重合。回到定义,『账户』意味着其对应着客户,是从需求角度出发的。而『外部账户』和『智能合约账户』则反映的则是『存在』,是从供给角度出发的。几个简单的问题或许可以帮助理解,『黑洞地址』是『账户』么?『统计选票的智能合约地址』是『账户』吗?做出否定的答案并不困难。
本文讨论的是需求角度而非供给角度的『账户』,这意味着我们只关心『客户』的需求,因此在接下来的描述中,我会使用『外部地址』和『智能合约地址』来描述非『账户』的以太坊地址。
什么是抽象?『抽象』这个词就挺『抽象』的,不得不借助专业的定义。
『维基百科』:
是指以缩减一个概念或是一个现象的资讯含量来将其广义化的过程,主要是为了只保存和一特定目的有关的资讯。
我们不妨打个比方,地址 0xb9b8981856851ca455bfbe65ed488621a9b70862 是一个外部地址,发送过 56 笔交易,内有 0.636 ETH 和其它若干资产。如何对这些描述进行抽象化呢?(账户标识符,验证方式,状态)三元组即可。账户抽象就是对这三个属性进行广义化。
以太坊的账户标识符是特化的,你无法使用任意长度的任意字符来作为账户标识符。换言之,你没法用自己的名字作为账户标识符。核心开发者并没有对账户标识符广义化的计划,将地址扩展到 32 字节的讨论是从更丰富的功能角度出发的。包括 ENS 在内的大量域名项目在应用层试图满足客户的此类需求,并没有看到想在协议层解决这个问题的方案。
以太坊的账户验证方式按照其类型是不同的,外部账户是特化的,智能合约账户则是广义化的。那是否智能合约钱包就解决了账户验证方式的抽象问题呢?这里还遗留的问题是——需要一条交易携带在 EVM 中检验智能合约账户有效性的数据,而这条交易必须由外部地址发起。以太坊上交易有效性的判定与外部账户的验证方式是一致的,简单来说,除了需要提交包含指定 nonce 的签名外,还需要提供一定数量的 Ether。在大部分语境中,『账户抽象』和『智能钱包』的区别就在于是否需要对交易有效性进行抽象,包括检验『数据有效性』和『资产有效性』的方式(这里我们把 Ether 看作一种资产,而非一般意义的数据)。
以太坊账户状态是更加复杂的问题,在这篇文章不展开。
综上所述,我们讨论的账户抽象,主要是指账户验证方式的广义化,特别需要指出的是,这里隐含了交易有效性的广义化问题。
如果外部地址不好,为什么以太坊一直沿用至今呢?显然,它有某些难以替换的优势,主要体现在以下方面。
以太坊是一个无许可的网络,交易在网络中的传播是无需支付费用的,直到它被纳入区块。这意味着攻击者可以无需花费实际的成本而消耗节点的计算资源,但只有完成交易有效性判定后才会进行转发,也才会消耗所有的全节点(e.g. 以太坊网络)的计算资源。以太坊交易有效性验证是避免无效交易消耗全网资源的重要手段,而特化则更将这种影响降到最低。第一个原因是 ECDSA 签名的验证成本相对较低,且除了读取地址 nonce 以外,所有操作都是节点本地完成的。第二个原因是交易一旦有效,永远有效。进入内存池的交易不会因为其它交易的执行成功而失效,这意味着节点总能收取交易发起方『质押』的费用(除非用相同 nonce 的交易替换原交易,但仍然需要支付费用)。这里『质押』的费用,就是该账户为此交易愿意支付的最大金额(= gasLimit * gasPrice)。有关这部分,可参考我此前的文章。
以太坊的状态爆炸问题由来已久,而特化则缓解了状态膨胀的增长速度。每个外部账户所占有的存储空间仅有标识符与 nonce,共占用 20 + 32 = 52 字节,而智能合约账户呢?以 Argent 为例,存储密钥和守护者至少需要占用 7 * 32 = 224 字节,总结占用空间为 224 + 20 = 244 字节,约为外部账户的 4.7 倍。考虑到 nonce 存在大量优化空间,一旦 EIP-2681 实施,nonce 占用的空间将降到 16 字节。则该倍数将扩大到 244/(20+16)= 6.8 倍。
影响有多大呢?假设按照 Argent 宣称的要让 10 亿客户使用以太坊,仅账户存储一项,Argent 智能合约账户至少占用 227 GB,而外部账户则只需要 48 GB。需要注意的是,修改交易有效性规则与状态数据大小关系不大,但稍有区别的是,目前的外部账户没有为存储空间显性付费,智能合约账户则支付了手续费。假设在协议层实现账户抽象,如何为存储收费呢?
『智能钱包』可以实现任意的账户权限控制逻辑,EIP-2938 的核心论点在于,智能合约账户与外部账户是不平等的,无法直接作为交易发起者,因此要给他们平等的权力。然而,在协议层做账户抽象意味着提高了交易池的风险,也增加了世界状态的计费迷思。假设如外部账户一样,不向客户收取存储费用,则世界状态会加速膨胀,而假设收取存储费用,恐怕是提高而非降低以太坊的使用门槛。
本文的核心论点是,智能钱包的运营者可以用中继者的方案来解决这个问题,正如 ENS 解决账户标识符广义化的问题一样,构建系统外的商业共识。而即使运营者不提供服务,用户永远可以使用自己的外部账户操作智能合约账户。
Flashbots 提供了一种体系外协商手续费的方式,因此让链上 0 费用的交易成为合理的选择。Vitalik 在看到 Flashbots 拯救密钥泄漏账户中的 ERC-20 代币后萌生了 ERC-4337 的雏形。本文无意评价 ERC-4337 的利弊,只想提两个问题与大家讨论。