抽象帐户(Account Abstraction ):EIP-3074 与EIP-4337 简介

ChiHaoLu热度: 17918

以太坊的社群其实讨论了好一阵子究竟要如何设计新一代的帐户,不同的思路也对应了不同的提案,本文主要介绍AA 在以下这两种方向的相关内容。

原文作者:ChiHaoLu

原文来源:Mirror

以太坊的社群其实讨论了好一阵子究竟要如何设计新一代的帐户,不同的思路也对应了不同的提案,本文主要介绍AA 在以下这两种方向的相关内容:

  1. 让现行的EOA 有智能合约的功能(EIP-3074)
  2. 让现行的智能合约有EOA 的功能(EIP-4337)

合约Table of Contents

  • EIP-3074
  • EIP-4337
  • Closing

Background

本文主要继承自前篇:Account Abstraction 抽象帐户:EIP-2938 简介,因此会希望读者已经阅读完前篇,以及具备相关的背景知识。

▎EIP-3074

EIP-3074: AUTH and AUTHCALL opcodes打算在EVM 中加入两个新的OpCodes,分别是 AUTH 和AUTHCALL,让EOA 能透过这两个opcode 授权合约代替EOA 的身份去呼叫其他合约。

此提案仍在review 阶段,请大家谨慎服用。

EIP-3074 的主要目的并非设计一个崭新的protocol 来扩展EOA 的functionality,因为随着protocol 与相关的介面标准越来越复杂,能被攻击的地方也会越来越多。

它倾向让User(EOA)可以以合约(Invoker Contract)代理自己执行各种动作,同时让开发者能以一个更具弹性的框架来设计交易物件和验证机制(签章演算法),使任何的EOA 可以像一个合约帐户(Contract Account)一样运作,却不用自己布署任何合约。

Overview

合约Image Source: Ethereum wallets today and tomorrow — EIP-3074 vs. ERC-4337

概括来说一个EOA 能将一则已签的讯息(交易)送至自己信任的合约(称作Invoker)上,合约可以利用 AUTH 和 AUTHCALL 代替这个EOA 送出这笔交易。

由于EOA / User 提交给Invoker 的形式是合约自订的,搭配新的OpCodes 之后能让各种需求变得很好实现,例如批次交易、包装交易、手续费缴交方式、多签、签章验证方式等。EOA 也能透过他喜欢的方式(ERC-20、法币等)给予Invoker 手续费。

特别注意:
  • EIP-3074 可以视为是EOA 的扩充而非必要。
  • Invoker 是不可升级的,因为可升级合约的新逻辑可能会让Invoker 无法适当地验证commit,导致造成非常严重的问题,例如让不该通过的交易签章通过,或该通过的无法通过。

合约此外,commit可以利用平行的call 和在其之中的nonce,达到multi-call 的「包装交易」效果。例如我们在面对ERC-20 的交易时,就可以把approve-transfer包在一个动作里面。

关于这个部分每一个call frame 里面的角色及运作,可以见下文。

EIP-3074 相关的缺点与改进建议的部分可以看:A case for a simpler alternative to EIP 3074 EIP-3074 Threat Models和Reference 处的内容。

authorized

  • authorized是一个型态为 address 的变数(合约除了 tx.origin 和 msg.sender 之外现在还能读取authorized),表示当今合约是被哪个帐户授权的。被授权的合约能够使用 AUTHCALL 代表此帐户(authorized的address)执行各种行为。
  • authorized和其他以太坊中的变数不同,它没有预设值,每次合约开始一个执行前就会将其初始化为unset,代表当前没有EOA 授权此合约执行。
  • authorized是 AUTH 及 AUTHCALL 这两个新OpCodes 会去查看的变数,存在当前合约执行时的EVM 中,用于确认是否已经正确设置授权帐户(看 authorized 是否不是unset),如果已经被设置且所有签章合法则 authorized 的值会被 AUTH 及 AUTHCALL 取用(下一节会说明)。
  • 合约每一次只能有一个authorized,也就是说合约不能同时代替两个EOA 执行动作。
  • 每次执行(Call)时(separate execution frames),每次的 authorized 是独立的,不能监听到别人的authorized。即便是利用DELEGATECALL,或同样 address 授权加上同样一笔交易,当前 authorized 都不能离开作用域影响别人。
不能跨出execution frame(call frame)的原因是同一笔交易里面可能有多个call frame,而每一个call frame 都有一个经过 AUTH 授权的authorized,这个授权只停留在自己的call frames 里面,也就是 authorized 不能影响他人及被影响的原因。

AUTH 和AUTHCALL

AUTH(0xf6):会基于ECDSA 签章演算法去设定 authorized 的值

  • AUTH会从Stack 中取出三个元素:authority、offset、length,首项代表signer address,后两者代表memory 的range,会接收EOA 的(v, r, s) 以及commit。
  • 由于是接收dynamic memory range,因此 AUTH 未来是有机会升级来支援与Contract Account 互动或使用其他验证方法的。
  • 此处EOA 送来的签章仍然是使用 secp256k1 这个演算法,签章结果为:(v, r, s)。
  • 如果签章合法且签章recover 后 authority == signer 或authority == tx.origin(允许简单的Batch 交易,例如ERC-20 中的approve-transfer),则将 authorized 设为authority。
  • 如果 authorized 被成功设定成 authority 也就是signer,那 AUTH 会回传1,否则回传0。
  • commit是EOA 提交的交易资讯,Invoker Contract 会验证这里面的内容,包含nonce(replay protection)、to、gas、calldata。

合约AUTHCALL(0xf7):会代理 authorized 这个帐户发送call

  • AUTHCALL会从Stack 中取出八个元素,包含:gas、addr、value等,用于发送call(建置一笔交易物件)。
  • 与 CALL(0xF1) 的行为很像,差别主要在于一些参数的逻辑判断,例如:authorized如果是unset 的状态,则这次执行动作就不合法。

在EIP-3074 中还有 dynamic_gas 的设计,这个部份因为比较琐碎我就先略过,如果有兴趣或是想知道其他参数的Spec. 可以详阅此处

▎EIP-4337

EIP-4337: Account Abstraction via Entry Point Contract specification则希望可以把原本交易在底层运作的逻辑拉到合约中:

  1. 当User 签核完一笔交易(这里我们将EOA 签送一笔交易的行为改称为UserOperation)后
  2. 将其送到UserOperation mempool 之中(类似当今的Tx Mempool)
  3. 而Bundler 会从中挑选交易,捆绑成一笔Bundle Transaction
  4. 呼叫Entry Point Smart Contract 的handleOps
  5. 完成相关执行与验证之后,把交易推到链上。

在这里我们有许多名词是第一次碰到,下文我会慢慢解释!

此提案仍在draft 阶段,请大家谨慎服用。

合约Source: ERC 4337: account abstraction without Ethereum protocol changes

首先,这个提案最大的特点就如同上图来源, Vitalik 文章的标题叙述一样,不用去更改Ethereum 底层的Protocol 就能完成AA 的实作。

严谨来说是不用去修改或增加共识层的Protocol。

EIP-4337 可以达到以下目标,某些点可能与我们之前介绍过的EIP-2938 和EIP-3074 稍微不同:

  1. 以Contract Account 作为真正的主要帐户:不再需要任何EOA 作为呼叫的源头(当今的Contract Account 和EIP-3074 都无法达到)
  2. 去中心化:不需要对bundler 这个角色的信任假设
  3. 不需要修改共识层的Protocol:所以不会有新的OpCodes 也不会有新的Transaction Type。
  4. 拥有过往我们提到的其他特性,例如:Atomic multi-operations、Privacy-Solution、不同支付手续费的方式(ERC-20)

Contract Specification

我们可以把EIP-4337 的AA 实作当成是一个Contract 的Spec.,它的目的是要把底层的交易与帐户运作拉到合约层面执行。这边我会边解释名词,边顺过整个交易在AA 被执行的过程。

1. UserOperation & 2. UserOperation mempool

在合约里面,用户送上来的交易物件是一个在合约中名为 UserOperation 的struct。这个 struct 的members 和我们认识的交易很像,包含sender、nonce、callData、callGas、signature等,细节可见原提案

为了避免Replay Attack(跨链或跨不同的EntryPoint),Signature 的制作必须要包含 chainid 和 EntryPoint address 等元素。

3. Bundler & 4. Bundle Transaction

Bundler 有可能是矿工,或是能作为User 和Miner 之间的中介人。会去聆听UserOperation mempool 中新加入的UserOperation,并且将从这些交易中挑选一部分捆绑成Bundle Transactions。

这边我们可以假设UserOperation 一定会被打包处理,因为可能会有类似Flash Bot 的Bundler 去快速过滤出有利润(手续费)可图的交易。

首先Bundler 会在Local 使用RPC Call 呼叫Entry Point Smart Contract 中的simulateValidation(),以此先确保这些UserOperation 的签章没问题和Gas Fee 被正常支付。关于模拟交易结果的部分可见此处

最后Bundle Transactions 会呼叫Entry Point Smart Contract 中的函式handleOps。

5. handleOps & 6. Entry Point Smart Contract

Entry Point Smart Contract(EntryPoint)是一个早就被布署的合约,将在未来被相关的AA Transaction 呼叫使用,例如某一个Dapp 有它想要的AA 交易模式,它就需要布署一个它的EntryPoint。

EntryPoint会处理UserOperations 的内容和替Bundle Trandactions 布署一个Wallets Contract(使用标准EIP-2470: Singleton Factory以及CREATE2,initCode来自于UserOperation.initCode,salt来自于UserOperation.nonce)。

Wallet Contract 会用来处理nonce 与signature 的验证并且执行交易。

Entry Point Smart Contract

在进到 EntryPoint 与 handleOps 的解释之前,我们先回忆一下之前在EIP-2938 提到的,节点需要负责验证一笔AA 交易是否合法的两个阶段:PAYGAS以前的验证阶段(verification phase),与 PAYGAS 以后的执行阶段(execution phase)。

  • 前者限制交易只能阅读合约的storage(eg public keys, anti-replay nonces, Merkle roots) 以及不能更改任何状态,如果交易在这个阶段失败,矿工会拒绝这笔交易。
  • 后者因为已经支付了fee,如果交易在这个阶段失败,矿工仍然可以选择要不要加入这笔交易。

合约Source: Implementing account abstraction as part of eth1.x

在 handleOps 中有很类似的举动,面对每一个UserOperation,handleOps会用两个For Loop 来实作上述两个phases,一个是verification loop,另一个是execution loop。

Verification Loop

  1. 如果这个 UserOperation 还没有一个对应的wallet contract,就用 UserOperation 中的其中一个field:initCode,来布署一个合约。
  2. 如果 initCode 是空的,或者布署之后的Wallet Contract Address 和 UserOperation.sender 不同,这个call 就视为失败。
  3. 将 UserOperation 作为参数并且附上手续费,以呼叫wallet contract 中的validateUserOp
  4. validateUserOp首先会用 require(msg.sender == ENTRY_POINT) 确认 EntryPoint 是自己认可的。接着验证交易是否合法,包含我们上述提到的那些AA 特性的验证(multi-sig、social recovery、不同的Sig. Algorithms 等)以及nonce 是否正确。
  5. 若是都合法则Wallet 支付手续费(对应到我们当初说的PAYGAS)。以上过程中有任何失败都会revert。
补充说明:
  • 用户在送上 UserOperation 这个物件时,必须先用EIP-1014自行计算UserOperation.sender,也就是 CREATE2 创建的Wallet Contract 的地址。
  • validateUserOp()和我们之前提到Bundler 会预先呼叫 EntryPoint 的 simulateValidation() 要做相同的检查。
  • 需要特别注意Verification Loop 中,如果再用call 呼叫其他合约时(depth > 2)有禁止执行的OpCodes,这个部份对应到之前EIP-2938 的「限制交易在 PAYGAS 之前只能阅读合约自己的storage 以及不能更改任何状态」。

Execution Loop

handleOps中的第二个步骤(回圈)会以 UserOperation 作为calldata,去呼叫Verification Loop 布署的Wallet Contract。并且执行交易本身该执行的内容。(可想而知Wallet Contract 要有办法去parse 这个calldata。)

执行完以后,会将剩余的gas fee 给予Wallet Contract。

Paymasters

在EIP-4337 还有特别重要的一个Features 叫做Paymasters

大家还记得在之前的文章中有介绍过的其他支付手续费的方式,以及Tornado Cash 的AA Example 吗。Paymasters 可以做到第三方代替别人支付一笔交易的手续费的行为,此时就可以去接收其他种的Fee(eg 信用卡、ERC-20 等)。

合约要如何判断这笔交易的手续费是Wallet Contract 还是Paymasters 支付,得看 validateUserOp 中的参数 requiredPrefund 是否为0。如果我们已经确定要用Paymaster 支付的话,可以对应着看上方示意图。

EntryPoint中要特别去实做一些属于Paymaster 的函式,例如:

  1. addStake、unlockStake、withdrawStake:这些函式可以让paymasters 管理他们在 EntryPoint 中的资金,Paymaster 必须要抵押资金以此代表同意(保证)成为第三方支付者。
  2. balanceOf、depositTo、withdrawTo:这些函式能够让Paymaster 去管理用户资产在 EntryPoint 这个Contract 中的状态。例如 depositTo 可以让Paymaster 存款到用户身上(EntryPoint中一个储存用户状态的资料结构),之后就可以这里扣除该用户交易(UserOperation)需要用到的手续费。

在以上的示意图中,对应的步骤如下:

  1. Bundler 会呼叫 EntryPoint 的handleOps。
  2. EntryPoint将 UserOperation 作为参数呼叫wallet contract 中的validateUserOp,验证所有交易该验证的事情,和上文介绍两回圈时不同的是:这边不会支付手续费。先不付的原因就是为了等第三方的角色(Paymaster)支付手续费。
  3. handleOps除了 validateUserOp 以外,还需要确认Paymaster 的状况,例如拥有足够的ETH 可以支付这笔交易的手续费。
  4. EntryPoint呼叫Paymaster Contract 中的validatePaymasterUserOp,确认paymaster 愿意支付这笔交易的手续费。愿意则支付,如果不愿意这笔交易就会failed。
  5. 呼叫Wallet Contract 并执行交易本身该执行的内容。
  6. 做完第五步之后,必须紧接着呼叫Paymaster Contract 的postOp。需要注意这里除了跳出去找paymaster 之外,这一到六步都是不可分割的!

合约Image Source: Ethereum wallets today and tomorrow — EIP-3074 vs. ERC-4337

上面这张图也蛮漂亮的,大家可以参考一下:

补充说明:
  • 第一到第四步为Verification Loop,第五与第六步为Execution Loop。
  • 为了防止Paymasters 可能DoS 系统的风险,我们需要一个Paymaster 的声望机制(reputation system) ,详细可见:reputation, throttling and banning section
  • 可以有多个Paymasters 来分担一笔交易的手续费。

Security

整个系统的安全假设有一个前提是Node(miner / bundler)必须在包装这笔UserOperation 时就先利用上文提到的模拟行为确保交易会成功、手续费会被支付(细节可见 此处)。如果这件事情没有做到,那我们可以假设有恶意人士会提交很多个operations,并且被包装抵达 EntryPoint 但在最后一刻(执行了很久之后),才被revert。但如果有在每次提交到EntryPoint 前确实模拟,那系统就可以预设是DoS Safe 的。

虽然无论是使用Wallet Contract 还是Paymaster 支付手续费,都可以利用模拟行为避免交易在最后一步才被revert,但Paymaster 是被第三方制造出来的,因此我们可以想像有一种恶意情况是模拟行为中 paymaster.validatePaymasterUserOp 会成功,但之后的 postOp 等真正要执行时会失败。

Closing

和前一篇介绍AA 的文章相同,由于是简介所以非常多设计细节还有实作的设计想法我都没有提到,如果想要了解的话可以细细品尝该EIP 本身还有下方Reference 提到的资料。

由于以上介绍的两个提案都还不是定案,在研究时也会找到许多旧版提案的内容,因此如果大家发现认知与资料不一的情况,可以先去确认EIP 内文,那里肯定是最准确的!

本文要感谢

NIC Lin老师的Review(这篇超级长的😣)!Reference: EIP-3074

Reference:EIP-4337

Link Tree



责编:Lynn

声明:本文为入驻“MarsBit 专栏”作者作品,不代表MarsBit官方立场。
转载请联系网页底部:内容合作栏目,邮件进行授权。授权后转载时请注明出处、作者和本文链接。未经许可擅自转载本站文章,将追究相关法律责任,侵权必究。
提示:投资有风险,入市须谨慎,本资讯不作为投资理财建议。
免责声明:本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况,及遵守所在国家和地区的相关法律法规。