Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7562: 账户抽象验证范围规则

一系列对验证 EVM 代码的限制,旨在保护账户抽象节点免受因未支付的计算而造成的拒绝服务攻击。

Authors Yoav Weiss (@yoavw), Dror Tirosh (@drortirosh), Alex Forshtat (@forshtat), Shahaf Nacson (@shahafn)
Created 2023-09-01
Discussion Link https://ethereum-magicians.org/t/erc-7562-account-abstraction-validation-scope-rules/16683

摘要

本文档描述了账户抽象协议在账户抽象交易的验证阶段应遵循的规则, 例如 ERC-4337 UserOperation 或 RIP-7560 (原生账户抽象),这些规则由区块构建者或独立的捆绑器在链下强制执行, 以及每个规则背后的基本原理。

动机

通过账户抽象,处理交易的逻辑(验证、gas 支付和执行)不再是硬编码的,而是由 EVM 代码执行。 这对账户的好处是数不胜数的 -

  • 抽象验证允许合约使用不同的签名方案、多重签名配置、自定义恢复等。
  • 抽象 gas 支付允许通过第三方支付轻松入门、使用代币支付、跨链 gas 支付
  • 抽象执行允许批量交易

所有这些都是 EOA 账户模型所没有的。

然而,有一条规则交易必须遵守,以维护去中心化网络:一旦提交到网络(mempool),交易必须保证支付。这是为了防止对网络的拒绝服务攻击。

EOA 模型隐式地遵循了这条规则:一个有效的交易不可能在没有账户支付的情况下变得无效:例如,账户余额不能减少(除非有支付更高的交易)

这条规则使网络可持续且受到 DoS 保护:网络不能通过大量的交易来廉价地攻击。攻击(发送大量的交易)是昂贵的,并且随着网络的拥堵而变得更加昂贵。合法的用户支付更多,并且可以延迟操作以避免成本,但攻击者支付巨额(且不断增加)的费用来保持网络的拥堵。

为了在任何账户抽象系统中模拟相同的激励结构,我们建议以下交易验证规则。 这些验证规则仅适用于账户抽象交易的验证阶段,而不是其整个执行代码路径。

有关这些基于合约的账户的实际接口,请参阅 ERC-4337 和 RIP-7560 中的定义。

本文档使用术语 “UserOperation” 来表示由智能合约账户创建的交易,并密切遵循 ERC-4337 术语。 然而,这些规则适用于任何使用 EVM 代码来执行交易验证的账户抽象框架,并在公共 mempool 中区分验证(操作是否符合协议级别的包含条件)和执行(链上执行和 gas 支付)。

规范

验证规则类型

我们定义两种类型的验证规则:网络范围规则本地规则

如果 UserOperation 违反任何验证规则,将导致该 UserOperation 从 mempool 中删除并从捆绑包中排除。

网络范围规则 是一种规则,如果 UserOperation 验证违反该规则,则应导致在 p2p mempool 中发送此 UserOperation 的对等捆绑器声誉受损。 声誉极低的对等捆绑器最终将被标记为恶意的 垃圾邮件发送者 对等端。

本地规则 是一种在每个捆绑器的本地状态上下文中强制执行的规则,每个捆绑器的本地状态可能不同,并且不同的捆绑器可能并不总是就这些规则的违规行为达成一致。 因此,发送违规 UserOperation 的捆绑器不应受到其对等方的 p2p 声誉损害。

常量

标题 注释
MIN_UNSTAKE_DELAY 86400 1 天,提供足够的提款延迟以防止大多数女巫攻击
MIN_STAKE_VALUE 每个链的可调整值 相当于本地代币中约 ~$1000,这提供了足够的资本要求以防止大多数女巫攻击
SAME_SENDER_MEMPOOL_COUNT 4 允许来自单个发送者的 mempool 中的最大 userops 数量。
SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT 10 mempool 中允许的引用相同未抵押实体的最大 UserOperations 数量
THROTTLED_ENTITY_MEMPOOL_COUNT 4 具有受限实体的 UserOperations 可以保留在 mempool 中的数量
THROTTLED_ENTITY_LIVE_BLOCKS 10 具有受限实体的 UserOperations 可以在 mempool 中保留的区块数量
THROTTLED_ENTITY_BUNDLE_COUNT 4 可以在单个捆绑包中添加的具有受限实体的 UserOperations 数量
MIN_INCLUSION_RATE_DENOMINATOR 100 (客户端) \ 10 (捆绑器) 用于实体声誉计算公式的分母
THROTTLING_SLACK 10 声誉公式的一部分,允许实体合法地拒绝一些交易而不被限制
BAN_SLACK 50 声誉公式的一部分,允许受限实体拒绝一些交易而不被限制
BAN_OPS_SEEN_PENALTY 10000 要放入实体的 opsSeen 计数器中的值,以声明为已禁止
MAX_OPS_ALLOWED_UNSTAKED_ENTITY 10000  
PRE_VERIFICATION_OVERHEAD_GAS 50000 每个 UserOpEntryPoint 使用的 gas,无法在链上跟踪
MAX_VERIFICATION_GAS 500000 验证函数可能使用的最大 gas
MAX_USEROP_SIZE 8192 以字节为单位的单个打包和 ABI 编码的 UserOperation 的最大大小
MAX_CONTEXT_SIZE 2048 以字节为单位的单个 UserOperation 中支付者返回的 context 字节数组的最大大小
MAX_BUNDLE_SIZE 262144 以字节为单位的对 handleOps 函数的 ABI 编码的捆绑调用的最大大小
MAX_BUNDLE_CONTEXT_SIZE 65536 以字节为单位的捆绑包中所有 UserOperations 中所有支付者返回的所有 context 字节数组的最大总大小
VALIDATION_GAS_SLACK 4000 必须添加到 verificationGasLimitpaymasterVerificationGasLimit 估计中的 gas 量

验证规则

定义

  1. 验证阶段:链上验证阶段最多有三个阶段
    1. sender 部署阶段(每个账户一次)
    2. sender 验证(必需)
    3. paymaster 验证阶段(可选)
  2. 执行阶段:链上执行阶段最多有两个阶段
    1. sender 执行阶段(必需)
    2. paymaster 交易后阶段(可选)

    验证规则仅在验证阶段应用。一旦 UserOperation 得到验证,它就保证支付。执行没有任何限制,无论是账户 (callData) 还是支付者 (postOp)

  3. 实体:由 UserOperation 显式指定的合约。 包括 factorypaymasteraggregator 和已抵押的 account,如下所述。
    每个“验证阶段”都归因于单个实体。
    实体合约必须在链上具有非空代码。
  4. 规范 Mempool:本文档中定义的规则适用于网络上所有捆绑器共享的主 mempool。
  5. 已抵押实体:具有至少 MIN_STAKE_VALUE 的锁定抵押和至少 MIN_UNSTAKE_DELAY 的取消抵押延迟的实体。
  6. 关联存储:如果满足以下条件,任何智能合约的存储槽都被认为是与地址 A “关联”的:
    1. 槽值为 A
    2. 槽值计算为 keccak(A||x)+n,其中 x 是一个 bytes32 值,而 n 是一个范围在 0..128 之间的值
  7. 使用地址:以任何方式访问给定地址的代码。 这可以通过执行给定地址的 *CALLEXTCODE* 操作码来完成。
  8. 垃圾邮件发送者 - 试图通过向其他对等方发送大量无效 UserOperations 来对 mempool 进行 DoS 攻击的 P2P 对等捆绑器。 捆绑器必须检测并断开与此类对等方的连接,如 Mempool 验证规则 部分所述。

声誉定义

  1. opsSeen:每个实体的计数器,用于统计此捆绑器收到的引用此实体的唯一有效 UserOperation 的次数。 这包括通过传入的 RPC 调用或通过 P2P mempool 协议接收的 UserOperation

  2. opsIncluded:每个实体的计数器,用于统计实际包含的 UserOperation 中出现引用此实体的唯一有效 UserOperation 的次数。
    此值的计算基于 UserOperationEvents,并且仅针对先前被此捆绑器计为 opsSeenUserOperations 进行计数。
  3. 刷新率:以上两个值每小时更新一次,计算公式为 value = value * 23 // 24
    实际上,该值在 4 天后会降低到 1%。
  4. inclusionRateopsIncludedopsSeen 的比率

声誉计算

我们定义一个值 max_seen = opsSeen // MIN_INCLUSION_RATE_DENOMINATOR

每个实体的声誉状态确定如下:

  1. 已禁止max_seen > opsIncluded + BAN_SLACK
  2. 已限制max_seen > opsIncluded + THROTTLING_SLACK
  3. 正常:否则

请注意,新实体的声誉从“正常”开始。

由于声誉“刷新率”,请注意,恶意支付者最多可能导致网络(仅限 p2p 网络,而非区块链)每小时处理 BAN_SLACK * MIN_INCLUSION_RATE_DENOMINATOR / 24 个未支付的 ops。

运行验证规则

  1. 区块构建器或捆绑器在接受 UserOperation 加入其 mempool 之前应执行一次完整的验证,并在将其包含在捆绑包/区块中之前再次执行。
  2. 捆绑器应跟踪 UserOperation 的验证阶段并应用本文档中定义的所有规则。
  3. 捆绑器还应在提交之前对整个捆绑包执行完整的验证。
  4. 验证规则可防止未抵押的实体在 UserOperation 的模拟和执行之间更改其行为。 但是,恶意的已抵押实体可以检测到它正在捆绑验证中运行并导致回滚。因此,在提交之前应执行整个捆绑包的第三次跟踪模拟。
  5. 失败的 UserOperation 应从捆绑包中删除。
  6. 捆绑器应更新违反规则的已抵押实体的声誉,并按照下述将其视为 THROTTLED / BANNED

Mempool 验证规则

  1. 通过 P2P 协议广播 UserOperation,并带有以下信息:
    1. UserOperation 本身
    2. 最初验证此 UserOperation 所依据的区块哈希。
  2. 一旦从另一个捆绑器收到 UserOperation,接收捆绑器应在本地对其进行验证。
  3. 收到的 UserOperation 可能会因任何合理的静态检查而失败,例如: 格式无效、值低于最小值、提交时使用的区块哈希不是最新的等等。 在这种情况下,捆绑器应删除此特定 UserOperation,但保持连接。
  4. 捆绑器应根据上次包含的捆绑包的 nonce 检查 UserOperation,并默默删除最近包含的 nonceUserOperations。 此失效可能归因于网络竞争条件,不应导致声誉变化。
  5. 如果收到的 UserOperation 针对当前区块失败:
    1. 针对最初验证 UserOperation 所依据的区块重试验证。
    2. 如果成功,则默默删除 UserOperation 并保持连接。
    3. 如果失败,则将发送者标记为“垃圾邮件发送者”(断开与该对等方的连接并永久阻止它)。

操作码规则

  • 阻止来自访问存储和代码之外的信息(又名“环境”)的操作码的访问。
    • [OP-011] 被阻止的操作码:
      • ORIGIN (0x32)
      • GASPRICE (0x3A)
      • BLOCKHASH (0x40)
      • COINBASE (0x41)
      • TIMESTAMP (0x42)
      • NUMBER (0x43)
      • PREVRANDAO/DIFFICULTY (0x44)
      • GASLIMIT (0x45)
      • BASEFEE (0x48)
      • BLOBHASH (0x49)
      • BLOBBASEFEE (0x4A)
      • CREATE (0xF0)(以下“合约创建”和“已抵押工厂创建”部分除外)
      • INVALID (0xFE)
      • SELFDESTRUCT (0xFF)
    • [OP-012] 允许使用 GAS (0x5A) 操作码,但前提是紧随其后的是 *CALL 指令,否则将被阻止。
      这是一种将所有剩余 gas 传递给外部调用的常用方法,这意味着实际值会立即从堆栈中消耗掉,并且任何其他操作码都无法访问。
    • [OP-13] 任何“未分配”的操作码。
  • [OP-020] 禁止在 “out of gas” 时回滚,因为它可能会 “泄漏” gas 限制或当前调用堆栈深度。
  • 合约创建:
    • [OP-031] 在部署阶段仅允许一次 CREATE2,并且必须为 “sender” 地址部署代码。 (无论是通过工厂本身,还是通过它调用的实用程序合约)
    • [OP-032] 如果存在 factory(即使未抵押),则允许 sender 合约使用 CREATE 操作码 (也就是说,只有 sender 合约本身,而不是通过实用程序合约)
  • 禁止访问未部署代码的地址:
    • [OP-041] 对于 EXTCODE**CALL 操作码。
    • [OP-042] 例外:允许访问 “sender” 地址。 这仅在部署阶段的 factory 代码中是可能的。
  • 允许访问 EntryPoint 地址:
    • [OP-051] 可以调用 EXTCODESIZE ISZERO
      此模式用于在调用 depositTo 函数之前检查目标是否具有代码。
    • [OP-052] 可以使用来自 senderfactory 的任何值调用 depositTo(sender)
    • [OP-053] 可以使用来自 sender 的任何值调用回退函数。
    • [OP-054] 禁止对 EntryPoint 的任何其他访问(无论是 *CALL 还是 EXT* 操作码)。
    • [OP-055] 可以从 sender 调用 incrementNonce())
  • *CALL 操作码:
    • [OP-061] 禁止使用 value 进行 CALL。唯一的例外是上述对 EntryPoint 的调用。
    • [OP-062] 预编译:
      • 仅允许网络上已知的接受的预编译,这些预编译不会访问区块链状态或环境中的任何内容。
      • 核心预编译 0x1 .. 0x11
      • RIP-7212 secp256r1 预编译,在接受它的网络上。
  • [OP-070]EIP-1153 中定义的瞬态存储槽,并使用 TLOAD (0x5c) 和 TSTORE (0x5d) 操作码访问 的处理方式与持久存储 (SLOAD/SSTORE) 完全相同。
  • [OP-080] 仅允许从已抵押实体调用 BALANCE (0x31) 和 SELFBALANCE (0x47),否则将被阻止。

代码规则

  • [COD-010] 在第一次和第二次验证之间,任何访问过的地址、实体或引用的库的 EXTCODEHASH 值都不得更改。
    如果代码被修改,则 UserOperation 被视为无效。

存储规则

每个阶段内使用 SLOADSSTORE(以及 TLOADTSTORE)指令的存储访问受到以下限制:

  • [STO-010] 始终允许访问 “account” 存储。
  • 如果满足以下任一条件,则允许访问外部(非实体)合约中与帐户关联的存储:
    • [STO-021] 帐户已存在。
    • [STO-022] 存在 initCode 并且 factory 合约已抵押。
  • 如果实体(paymasterfactory)已抵押,则也允许:
    • [STO-031] 访问实体自身的存储。
    • [STO-032] 在任何非实体合约中读取/写入访问与实体关联的存储槽。
    • [STO-033] 对非实体合约中的任何存储进行只读访问。

本地规则

本地存储规则在捆绑时保护捆绑器免受拒绝服务攻击。它们不影响 mempool 传播,也不会导致捆绑器被标记为“垃圾邮件发送者”。

  • [STO-040] UserOperation 不得使用在 mempool 中另一个 UserOperation 中用作 “account” 的实体地址(factory/paymaster/aggregator)。
    这意味着 PaymasterFactoryAggregator 合约实际上也不能是 “account” 合约。
  • [STO-041] UserOperation 不得在使用与 mempool 中另一个 UserOperation 的 “sender” 相关的合约中使用关联存储(来自其帐户或来自已抵押实体)。

一般声誉规则

以下声誉规则适用于所有已抵押实体和未抵押的支付者。除非另有说明,否则所有规则都适用于所有这些实体。

  • [GREP-010] 禁止将 BANNED 地址放入 mempool 中。
    此外,所有引用此地址的现有 UserOperations 都会从 mempool 中删除。
  • [GREP-020] THROTTLED 地址的限制为:
    • mempool 中有 THROTTLED_ENTITY_MEMPOOL_COUNT 个条目。
    • 捆绑包中有 THROTTLED_ENTITY_BUNDLE_COUNTUserOperations
    • 只能在 mempool 中保留 THROTTLED_ENTITY_LIVE_BLOCKS 个区块。
  • [GREP-040] 如果实体在通过第二次验证后无法创建捆绑包,则其 opsSeen 设置为 BAN_OPS_SEEN_PENALTYopsIncluded 设置为零,导致其被 BANNED
  • [GREP-050] 当 UserOperation 被替换时(通过提交新的、gas 费用更高的 UserOperation),并且实体(例如,支付者)被替换时,删除的实体会将其声誉(opsSeen 计数器)减 1。

已抵押实体声誉规则

  • [SREP-010] 如果已抵押实体具有 MIN_STAKE_VALUE 并且取消抵押延迟为 MIN_UNSTAKE_DELAY,则 “规范 mempool” 会将其定义为已抵押实体
  • [SREP-020] 已移动到 GREP-010
  • [SREP-030] 已移动到 GREP-020
  • [SREP-040] “OK”的已抵押实体不受声誉规则的限制。
    • 允许在 mempool 中无限数量。
    • 允许在捆绑包中无限数量。
  • [SREP-050] 已移动到 GREP-040

实体特定规则

  • [EREP-010] 对于每个 paymaster,捆绑器必须跟踪使用此 paymasterUserOperations 可能消耗的总 gas 量。
    • 如果 mempool 中所有 userops(包括此新的 UserOperation)的最大 gas 成本高于当前 gas 价格下该 paymaster 的存款,则捆绑器不应接受带有 paymaster 的新 UserOperation 加入 mempool。
  • [EREP-011] 已删除
  • [EREP-015] 如果工厂或账户出现故障,则不应增加 paymaster 的 opsSeen
    • 在运行第二次验证(在包含在捆绑包中之前)时,如果 UserOperation 由于工厂或账户错误(FailOp 回滚或验证规则)而失败,则支付者的 opsSeen valid 会减少 1。
  • [EREP-016] 如果工厂、账户或支付者出现故障,则不应增加 aggregator 的 opsSeen
    • 在运行第二次验证(在包含在捆绑包中之前)时,如果 UserOperation 由于工厂、账户或支付者错误(FailOp 回滚或验证规则)而失败,则聚合器的 opsSeen valid 会减少 1。
  • [EREP-020] 如果使用了已抵押的工厂,则会相应地更新其声誉,以反映账户违反任何验证规则的情况。
    也就是说,如果由于任何原因在具有 initCodeUserOperation 中拒绝了 validateUserOp(),则将其视为工厂导致了此失败,从而影响其声誉。
  • [EREP-030] 如果使用了已抵押的账户,则即使其他实体(paymasteraggregator)已抵押,也会更新其声誉以反映其故障。
  • [EREP-040] 无论存储使用情况如何,都必须抵押 aggregator
  • [EREP-050] 未抵押的 paymaster 可能不会返回 context
  • [EREP-055] 上下文大小不得在验证和捆绑包创建之间更改。
    如果捆绑包创建回滚,并且支付者的上下文大小被修改,则该支付者
    将被 BANNED,无论回滚的 UserOperation 是否使用了该支付者。
  • 已抵押工厂创建规则:
    • [EREP-060] 如果工厂已抵押,则工厂本身或发送者可以使用 CREATE2 和 CREATE 操作码 (允许发送者使用带有未抵押工厂的 CREATE,使用 OP-032)
    • [EREP-061] 已抵押的工厂也可以使用调用 CREATE 的实用程序合约
  • [EREP-070] 在捆绑包创建期间,如果已抵押实体将其验证 gas 减少超过 10% 与第二次验证相比,即使 UserOperation 本身没有回滚,该实体也会受到限制。 (因为它可能会影响基于 EIP-7623 的 gas 计算)

未抵押实体声誉规则

  • 定义:
    • 上面定义了 opsSeenopsIncluded 和声誉计算
    • 实体的 UnstakedReputation 决定了允许在 mempool 中使用此实体的最大条目数。
    • opsAllowed 是为未抵押实体进行的基于声誉的计算,表示允许其在 mempool 中拥有的 UserOperations 数量。
    • 规则:
      • [UREP-010] 未受限制/禁止的未抵押发送者只能在 mempool 中拥有 SAME_SENDER_MEMPOOL_COUNTUserOperation
      • [UREP-020] 对于未受限制/禁止的未抵押支付者:
        opsAllowed = SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT + inclusionRate * min(opsIncluded, MAX_OPS_ALLOWED_UNSTAKED_ENTITY)
      • 对于新实体,这是默认值 SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT
      • [UREP-030] 已删除

Alt-mempools 规则

备用 mempool 是捆绑器可以选择加入的约定规则,除了规范 mempool 之外 alt-mempool “主题”是一个唯一的标识符。按照惯例,这是描述此 alt mempool 的具体细节的文档的 IPFS 哈希值(以清晰的测试和 YAML 文件形式)。

  • [ALT-010] 捆绑器通过 P2P 协议监听 alt-mempool “主题”
  • [ALT-020] 必须仅在违反规范规则时检查 alt mempool 规则
    • 也就是说,如果验证遵循上述规范规则,则不将其视为 alt-mempool 的一部分。
  • [ALT-021] 这样的 UserOperation(违反了规范规则)会根据所有 “备用 mempools” 进行检查,并被视为所有这些 alt-mempools 的一部分
  • [ALT-030] 捆绑器应该只将 UserOperations 转发给其他捆绑器一次,无论他们有多少个(共享)alt-mempools。
    接收捆绑器验证 UserOperations,并根据上述规则(和订阅的 alt-mempools)决定将其传播到哪些 alt-mempools。
  • [ALT-040] 实体的 opsInclude 和 opsSeen 是按 alt-mempool 保存的。也就是说,一个实体在一个 mempool 中可能被认为是受限的(或被禁止的),但在另一个 mempool 中仍然处于活动状态。

Alt-mempool 声誉

Alt-mempools 由参与规范 mempool 的同一批捆绑器提供服务,但会更改规则并可能引入拒绝服务攻击向量。为了防止它们与规范 mempool 或其他 alt mempools 一起崩溃,会为每个 mempool 管理声誉。导致过多失效的 alt mempool 会受到限制。这限制了攻击的范围,并允许捆绑器继续为其他 mempools 工作。

  • [AREP-010] 每个 alt-mempool 都有 “opsSeen” 和 “opsIncluded”,就像实体一样。在 UserOperation 的初始验证之后,会增加 opsSeen,在这里它被认为是此 mempool 的一部分。 在这个 UserOperation 被链上包含后(无论是由这个捆绑器还是另一个捆绑器包含),就会增加 “opsIncluded”
  • [AREP-020] alt-mempool 基于 声誉计算 变为 THROTTLED/BANNED
  • [AREP-030] 已删除

授权

  • [AUTH-010] UserOperation 只能包含单个 EIP-7702 授权元组。
  • [AUTH-020] 具有 EIP-7702 委托的帐户只能用作 UserOperation 的发送者。 不允许将授权帐户用作任何其他类型的 UserOperation 实体。
  • [AUTH-030] 只能在它是当前 UserOperation 的发送者时访问(使用 *CALLEXTCODE* 操作码)具有 EIP-7702 委托的帐户。
  • [AUTH-040] 如果在 mempool 中有多个具有授权元组的相同发送者的 UserOperation,则它们都必须具有相同的委托地址。

限制

验证规则尝试保证各个 UserOperations 验证之间的一定程度的隔离。 为了防止在创建捆绑包时达到内存扩展限制(由以太坊 EVM 施加),UserOperations 必须满足以下限制:

  • [LIM-010] 以字节为单位的单个打包和 ABI 编码的 UserOperation 的最大大小不得超过 MAX_USEROP_SIZE
  • [LIM-020] 以字节为单位的由单个 UserOperation 中的支付者返回的 context 字节数组的最大大小不得超过 MAX_CONTEXT_SIZE
  • [LIM-030] verificationGasLimitpaymasterVerificationGasLimit 参数必须超过 UserOperation 验证期间的实际使用量 VALIDATION_GAS_SLACK
  • [LIM-040] 以字节为单位的对 handleOps 函数的 ABI 编码的捆绑调用的最大大小不应超过 MAX_BUNDLE_SIZE
  • [LIM-050] 以字节为单位的捆绑包中所有 UserOperations 中所有支付者返回的所有 context 字节数组的最大总大小不应超过 MAX_BUNDLE_CONTEXT_SIZE

基本原理

所有由 EOA 发起的交易都有一个隐式的验证阶段,在该阶段中,将检查余额、nonce 和签名对于以太坊区块链的当前状态是否有效。 一旦节点检查了交易的有效性,只有来自同一 EOA 的另一笔交易才能以使第一笔交易无效的方式修改以太坊状态。

但是,使用账户抽象,验证还可以包括任意 EVM 代码并依赖于存储,这意味着不相关的 UserOperations 或交易可能会使彼​​此失效。

如果不加以解决,这将使维护有效 UserOperations 的 mempool 和生成有效捆绑包的工作在计算上不可行,并且容易受到 DoS 攻击。

本文档描述了一组验证规则,如果捆绑器在接受 UserOperation 加入 mempool 之前应用这些规则,则可以防止此类攻击。

高级别的目标

本规范的目的是在节点(捆绑器或区块构建器)处理来自外部来源的传入 UserOperations 时定义共识。 UserOperations 的此外部来源是最终用户节点(通过 RPC ERC-7769)或 p2p 网络中的另一个节点。

该协议尝试检测 “垃圾邮件” - 即无法包含在链上(因此也无法支付)的大量 UserOperations。 通过限制来自此类垃圾邮件发送者节点的请求来保护网络。

网络中的所有节点必须对 “垃圾邮件” 具有相同的定义:否则,如果某些节点接受某些类型的 UserOperations 并传播它们,而其他节点则将它们视为垃圾邮件,那些 “宽容” 的节点将被其余节点视为 “垃圾邮件发送者”,并且网络实际上会分裂。

UserOperation 的处理流程

  • 首先,收到 UserOperation - 无论是通过 RPC(代表单个应用程序提交)还是通过 p2p 协议(来自 mempool 中的另一个节点)。
  • 节点对 UserOperation 执行验证,然后将其添加到其内存中的 mempool,并将其提交给其对等方。
  • 最后,在构建区块时,节点从 mempool 中收集 UserOperations,执行第二次验证以确保它们作为捆绑包仍然有效,并将它们提交到下一个区块中。

在提交区块之前进行第二次验证的必要性

如果在收到另一个具有相同 nonce 的交易,则 mempool 中的正常以太坊交易可能会失效。另一个交易必须提高 gas 价格才能替换第一个交易,因此它满足 “必须支付才能包含在 mempool 中” 的规则。 使用基于合约的账户,由于 UserOperation 的有效性可能取决于可变状态,因此其他交易可能会使先前有效的 UserOperation 失效,因此我们必须在包含之前对其进行检查。

限制操作码的基本原理:

  • 验证是在创建区块之前在链下执行的。某些操作码访问仅在创建区块时才知道的信息。
  • 在验证交易时使用这些操作码可以很容易地创建一个验证规则,该规则将在链下成功,但始终在链上回滚,从而导致 DoS 攻击。
  • 一个简单的例子是 require block.number==12345。在验证 UserOperation 并将其添加到 mempool 中时,它可能是有效的 但在尝试将其包含在以后的区块中时,它将无效。

限制存储访问的基本原理

  • 我们需要 UserOperation 验证不重叠,以便单个存储更改不能轻易使 mempool 中的大量 UserOperations 失效。通过限制 UserOperations 访问与账户本身关联的存储,我们知道我们可以肯定地在捆绑包中包含每个账户的单个 UserOperation
  • (捆绑器 MAY 在捆绑包中包含同一账户的多个 UserOperations,但必须首先将它们一起验证)

需要抵押的基本原理

我们希望能够允许全局使用的合约(支付者、工厂、聚合器)使用与账户无关的存储,但仍然阻止它们垃圾邮件填充 mempool。 如果一个合约导致太多 UserOperations 在第一次成功后在其第二次验证中失败,我们可以限制其在 mempool 中的使用。 通过要求此类合约具有抵押,我们可以防止 “女巫攻击”,方法是增加创建大量此类支付者以继续垃圾邮件攻击的成本。

通过遵循验证规则,我们可以检测到导致垃圾邮件 UserOperations 的合约并限制它们。 抵押是为了防止快速重新创建恶意实体。 抵押永远不会被削减(因为它仅用于链下检测),但会锁定一段时间,这使得此类攻击的成本更高。

大规模失效攻击 的定义

如果大量通过了初始验证并被节点接受并进一步传播到 网络的 mempool 到其他捆绑器的 UserOperations 变得无效且不符合包含在区块中的条件,则认为一系列可能的行动是对网络的 大规模失效攻击

有 3 种方法可以执行此类攻击:

  1. 提交通过初始验证但稍后未能通过在捆绑包创建期间执行的重新验证的 UserOperation
  2. 提交在验证期间单独有效但捆绑在一起时变得无效的 UserOperation
  3. 提交有效的 UserOperation,但通过在 网络上执行状态更改来 “抢先交易” 它们,使其变为无效。所讨论的 “抢先交易” 必须在经济上可行。

为了防止此类攻击,我们尝试 “沙盒化”- 引起失效的最小更改是存储更改(5k gas)

  • 假设一个节点可以维持每个区块处理 2000 个无效的 UserOps,那么 DoS 攻击的成本是每个区块 10M gas。
  • 上述数值很高,但我们采取进一步措施来使此类攻击的成本更高。

安全考虑

本文档描述了 bundler 为了保护自己(以及整个 mempool 网络)免受拒绝服务攻击而必须采取的安全措施。

版权

通过 CC0 放弃版权和相关权利。

Citation

Please cite this document as:

Yoav Weiss (@yoavw), Dror Tirosh (@drortirosh), Alex Forshtat (@forshtat), Shahaf Nacson (@shahafn), "ERC-7562: 账户抽象验证范围规则 [DRAFT]," Ethereum Improvement Proposals, no. 7562, September 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7562.