はじめに
『DApps開発入門』という本や色々記事を書いているかるでねです。
今回は、Account Abstractionのトランザクション検証ルールを定めて、コントラクトアカウントの柔軟性を活かしつつ、従来のEOA同様にネットワークの安定性を維持する仕組みを提案しているERC7562についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
ERC7562では、Account Abstractionのトランザクションの検証フェーズで守るべきルールについて提案しています。
対象となるのは、ERC4337のUserOperationやRIP7560(ネイティブ・Account Abstraction)などのプロトコルで、これらのルールはオフチェーンでブロックビルダーやバンドラーによって強制されます。
ERC4337については以下の記事を参考にしてください。
動機
従来のEOAでは、トランザクションの処理(検証、ガスの支払い、実行)はハードコードされています。
一方、Account Abstractionでは、これらの処理をEVM上のコントラクトによって行います。
この仕組みによって、以下のようなメリットがあります。
-
検証の柔軟性
- 異なる署名方式の利用
- マルチシグ設定
- 独自のアカウント復元機能
-
ガスの支払い方法の拡張
- サードパーティによるガス代の肩代わり
- トークンを使ったガス代支払い
- クロスチェーンでのガス支払い
-
トランザクション実行の強化
- バッチトランザクション(複数の処理をまとめて実行)
こうした機能は、従来のEOAでは実現できませんでした。
ネットワークを維持するための重要なルール
Account Abstractionを導入する時に最も重要なのは、「ネットワークにトランザクションを送信した時点で、確実にガスを支払うことを保証する」ルールです。
このルールを守らなければ、ネットワークがDoS(サービス拒否)攻撃に弱くなります。
EOAが自動で守っているルール
EOAでは、以下のような理由でガス代の支払いが保証されています。
- 一度有効なトランザクションが、後から無効になることはない
例えば、アカウントの残高が急に減ることはありません(より高い手数料のトランザクションが送信されるケースを除く)。
- 攻撃者にとって、ネットワークを詰まらせるコストが高い
トランザクションを大量に送る攻撃を仕掛けても、その分のガス代を支払わなければならなりません。
そのため、攻撃者はネットワークを詰まらせるためには徐々に上がっていくガス代を払う必要があります。
ネットワークが混雑時にはガス代を上げて優先度を高めることができます。
この仕組みのおかげで、攻撃者は簡単にはネットワークを麻痺させることができません。
Account Abstractionにおける検証ルール
EOAと同じようなインセンティブ構造を維持するために、Account Abstractionにも厳格な検証ルールが必要です。
具体的には、検証フェーズで確実にガス代が支払われることを保証するルールを設けるべきです。
このルールは、あくまで「トランザクションの検証フェーズ」に適用され、実際のトランザクションの実行フェーズ全体には適用されません。
仕様
検証ルールの種類
Account Abstractionのトランザクション(UserOperation)には、ネットワーク全体で適用されるルールと各バンドラーごとに適用されるローカルルールの2種類の検証ルールがあります。
ネットワーク全体のルール
これらのルールに違反したUserOperationは、mempoolから削除されてバンドルに含められません。
さらに、この違反を起こしたUserOperationをP2Pネットワークに送信したバンドラーには、評判(reputation)ペナルティが発生します。
バンドラーの評判が極端に低くなると、ネットワークから悪質なスパム業者として認識される可能性があります。
その結果、トランザクションの取り扱いが制限されるなどの影響を受けます。
ローカルルール
ローカルルールは、各バンドラーの内部の状態に基づいて適用されるルールです。このため、バンドラーごとにルールの解釈が異なる場合があります。
ローカルルールに違反したUserOperationは、mempoolから削除されますが、P2Pネットワークで評判を下げることはありません。
つまり、そのバンドラーが他のバンドラーからスパム扱いされることはありません。
検証ルールに関する定数
検証ルールを決める時に、以下のような定数が設定されています。
項目 | 値 | 説明 |
---|---|---|
MIN_UNSTAKE_DELAY | 86400 | 最低1日間はステークを解除できない(秒単位) |
MIN_STAKE_VALUE | チェーンごとに調整可能 | ネイティブトークンで約1000ドル相当のステークが必要 |
SAME_SENDER_MEMPOOL_COUNT | 4 | 同じ送信者のUserOperationをメモリプールに4つまで保持可能 |
SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT | 10 | ステークしていない同じエンティティのUserOperationを10個までメモリプールに保持可能 |
THROTTLED_ENTITY_MEMPOOL_COUNT | 4 | 制限対象のエンティティは4つのUserOperationまでメモリプールに保持可能 |
THROTTLED_ENTITY_LIVE_BLOCKS | 10 | 制限対象のUserOperationがメモリプールに留まれるブロック数 |
THROTTLED_ENTITY_BUNDLE_COUNT | 4 | 制限対象のエンティティが1つのバンドルに含められる数 |
MIN_INCLUSION_RATE_DENOMINATOR | 100(クライアント)/ 10(バンドラー) | トランザクションが含まれる際の最低レート |
THROTTLING_SLACK | 10 | 制限を緩和する余地 |
BAN_SLACK | 50 | バン対象となる時の余地 |
BAN_OPS_SEEN_PENALTY | 10000 | バン対象のUserOperationが検出された時のペナルティ値 |
MAX_OPS_ALLOWED_UNSTAKED_ENTITY | 10000 | ステークしていないエンティティが処理できる最大UserOperation数 |
これらの制限を設けることで、ネットワークの安定性を確保しながらスパム攻撃を防ぐ仕組みになっています。
特に一定のステークを要求することで、悪意のあるバンドラーが簡単にネットワークを支配できないようになっています。
定義
検証フェーズと実行フェーズ
Account Abstractionのトランザクション(UserOperation)は、検証フェーズ(Validation Phase)と実行フェーズ(Execution Phase)の2つの段階を持ちます。
検証フェーズ(Validation Phase)
検証フェーズでは、UserOperationがネットワークに受け入れられるかどうかを判断します。
具体的には、以下の3つのフレームが関係します。
- 送信者デプロイフレーム(Sender Deployment Frame)
アカウントがまだ作成されていない場合にのみ実行される(1回だけ)。
- 送信者検証フレーム(Sender Validation Frame)
必須の検証プロセス。
トランザクションが有効かどうかをチェックする。
- ペイマスター検証フレーム(Paymaster Validation Frame)
オプションのフレーム。
ガス代を肩代わりするペイマスターの検証を行う。
この検証フェーズが終われば、UserOperationは確実にガスを支払うことが保証される。
つまり、実行フェーズではUserOperationがガス不足で失敗することはない。
実行フェーズ(Execution Phase)
実行フェーズでは、実際にトランザクションが処理されます。
検証フェーズを通過したUserOperationには実行に関する制限は設けられません。
以下の2つのフレームが存在する。
- 送信者実行フレーム(Sender Execution Frame)
必須のフレーム。
送信者が指定したコールデータ(callData
)を実行する。
- ペイマスター後処理フレーム(Paymaster Post-Transaction Frame)
オプションのフレーム。
ペイマスターがトランザクション後の処理を行う。
Entity
UserOperationで明示的に指定されるコントラクト。
ファクトリーコントラクト(Factory)、ペイマスター(Paymaster)、アグリゲーター(Aggregator)、ステークされたアカウントなど 各検証フレームは1つのエンティティに紐づきます。
エンティティのコントラクトは、必ずオンチェーンにコードが存在していることが条件です。
Canonical Mempool
この規格で定義されるルールは、ネットワーク全体で共有されるmempoolに適用されます。
ステーク済みエンティティ
最低 MIN_STAKE_VALUE 分のステークを持つ必要があり、MIN_UNSTAKE_DELAY の期間(最低1日)はステークを解除できないという条件の情報。
アドレスの使用
特定のアドレスのコードを参照する場合、以下の方法があります。
-
CALL
命令 -
EXTCODE
系の命令
評判(Reputation)に関するルール
ネットワークにとって悪質なエンティティを特定するために、評判システムが導入されています。
評判の指標
opsSeen
そのエンティティを参照する有効なUserOperationが受信された回数。
RPC経由またはP2Pメモリプール経由で受信したものがカウントされます。
opsIncluded
実際にブロックに含まれたUserOperationの回数。
UserOperationEvent
に基づいてカウントされ、過去にopsSeenとしてカウントされたものだけが対象になります。
更新ルール
毎時間、値を value = value * 23 // 24
に更新(4日後には約1%になる)します。
inclusionRate
opsIncluded / opsSeen
で計算します。
評判の分類
- BANNED(禁止)
max_seen > opsIncluded + BAN_SLACK
の場合、悪質なエンティティとして扱われます。
- THROTTLED(制限)
max_seen > opsIncluded + THROTTLING_SLACK
の場合、一部の処理が制限されます。
- OK(正常)
BANNEDとTHROTTLEDの条件を満たさない場合正常とみなされます。
検証ルールの実行手順
ブロックビルダー/バンドラーの対応
バンドラーやブロックビルダーは、UserOperationを受け入れる前に必ず完全な検証を行います。
- メモリプールに追加する前に検証
- バンドル/ブロックに含める前に再検証
- バンドル全体を再検証し、違反したUserOperationを削除
特に、ステークされていないエンティティがシミュレーション時と異なる動作をしないようにするために以下の追加チェックを行います。
- バンドル全体の追加シミュレーション
- 検証に失敗したUserOperationは除外
違反したステーク済みエンティティの評判を更新し、THROTTLEDまたはBANNEDとして扱います。
Mempoolの検証ルール
P2PネットワークでのUserOperationの送付
UserOperationがP2Pネットワークで配信される時に以下の情報が含まれます。
- UserOperation本体
- 最初に検証された時のブロックハッシュ
バンドラーがUserOperationを受信したらローカルで検証を行います。
無効なUserOperationの処理
- 形式不正(フォーマットエラー、不適切な値、古いブロックハッシュなど)
mempoolから削除するがP2P接続は維持します。
- 最近ブロックに含まれたnonceのUserOperation
ネットワークの競合による影響の可能性があるため、評判は下げずに削除します。
ブロックの不一致による対処
- 受信したUserOperationが現在のブロックと合わない場合
最初に検証されたブロックで再チェックし以下の処理に分けられます。
-
成功した場合
- 評判は下げずに削除(P2P接続維持)
-
失敗した場合
- 送信元を「スパマー」としてマークして接続を切断&永久にブロック
Opcodeのルール
Account Abstractionのトランザクションを安全に処理するために、特定のOpcodeの使用を制限しています。
これは、外部環境の情報へのアクセスを防ぎ、予測不可能な動作を避けるためです。
使用が禁止されるOpecode
以下のOpecodeは、ストレージやコード以外の外部環境にアクセスするため使用禁止とされています。
[OP-011] 完全にブロックされるオペコード
-
ORIGIN (0x32)
- EOAのアドレスを取得する。
-
GASPRICE (0x3A)
- ガス価格を取得する。
-
BLOCKHASH (0x40)
- 過去のブロックハッシュを取得する。
-
COINBASE (0x41)
- ブロックのマイナー/バリデータのアドレスを取得する。
-
TIMESTAMP (0x42)
- ブロックのタイムスタンプを取得する。
-
NUMBER (0x43)
- ブロックの番号を取得する。
-
PREVRANDAO/DIFFICULTY (0x44)
- Ethereumのランダム値/難易度を取得する。
-
GASLIMIT (0x45)
- ブロックのガスリミットを取得する。
-
BASEFEE (0x48)
- ブロックの基本ガス料金を取得する。
-
BLOBHASH (0x49)
- ブロブトランザクションのハッシュを取得する。
-
BLOBBASEFEE (0x4A)
- ブロブトランザクションの基本手数料を取得する。
-
CREATE (0xF0)
- 新しいコントラクトを作成(ただし、特定のケースでは許可)。
-
INVALID (0xFE)
- 無効なオペコード。
-
SELFDESTRUCT (0xFF)
- コントラクトの削除。
[OP-012] GAS (0x5A)
は条件付きで許可
CALL
系のオペコードの直前でのみ使用可能です。
これは、残りのガスを外部コールに渡すための一般的な方法です。
スタック上のガス値を他のオペコードで取得できないようにするために使用されます。
[OP-013] 未定義のオペコードは禁止
EthereumのEVMに未割り当てのオペコードは使用不可です。
[OP-020] ガス切れによるリバートを禁止
ガスリミットやコールスタックの深さを「リーク」させる可能性があるため、out of gas
によるリバートは禁止です。
コントラクト作成のルール
[OP-031] CREATE2
は1回のみ許可
送信者(UserOperationの送信元)のデプロイ時のみ使用可能です。
コードをデプロイするのは、ファクトリーやユーティリティコントラクトです。
[OP-032] CREATE
は送信者のコントラクトでのみ許可
**ファクトリーが存在する場合のみ許可(ステーク済みでなくてもOK)です。
送信者コントラクト自体でのみ使用可能(ユーティリティコントラクト経由は不可)。
コードのないアドレスへのアクセス禁止
[OP-041] EXTCODE*
や *CALL
の制限
コードがデプロイされていないアドレスへのアクセスは禁止です。
[OP-042] 例外
デプロイフェーズのファクトリーコード内での送信者アドレスへのアクセスは許可されています。
EntryPoint コントラクトへのアクセス制限
許可される操作
- [OP-051]
EXTCODESIZE ISZERO
を使用してコードの有無を確認 -
[OP-052]
depositTo(sender)
の呼び出し(送信者やファクトリーから資金をデポジットできる) - [OP-053] 送信者からのフォールバック関数の呼び出し
- [OP-055]
incrementNonce()
の呼び出し
禁止される操作
-
[OP-054]
*CALL
やEXT*
を使ってEntryPointにアクセス。
CALL オペコードの制限
[OP-061] CALL
に値を送ることは禁止
例外として、EntryPoint へのコールは許可されています。
[OP-062] 事前コンパイルコントラクト(Precompiles)の制限
-
許可されるもの
- EVMの標準プレコンパイル(0x1 ~ 0x11)
- RIP7212(secp256r1)プレコンパイル(対応ネットワークのみ)
これらのプレコンパイルは、ブロックチェーンの状態や環境を参照しないものに限定されます。
[OP-070] 一時ストレージ(EIP-1153)の扱い
TLOAD (0x5c)
と TSTORE (0x5d)
は通常の SLOAD/SSTORE
と同じ扱いです。
[OP-080] BALANCE (0x31)
と SELFBALANCE (0x47)
の制限
ステーク済みエンティティのみ使用可能で、ステークされていない場合は使用禁止です。
コードのルール
[COD-010] コードの改変は禁止
検証フェーズの間に、EXTCODEHASH
が変更されたらUserOperationは無効です。
これは、コントラクトのコードが予測可能であることを保証するためです。
ストレージのルール
- [STO-010] 送信者のストレージへのアクセスは常に許可
- [STO-021] すでに存在するアカウントのストレージはアクセス可能
- [STO-022] 初期化コード(initCode)があり、ファクトリーがステーク済みならアクセス可能
ステーク済みエンティティの場合
- [STO-031] 自身のストレージには自由にアクセス可能
- [STO-032] 非エンティティのコントラクトのストレージを読み書き可能(関連スロットのみ)
- [STO-033] 非エンティティのコントラクトのストレージは読み取り専用でアクセス可能
ローカルルール
ローカルルールは、バンドラーがバンドル作成時にDoS攻撃を受けないようにするためのルールです。
これらのルールは、mempoolの伝播には影響せず、違反してもバンドラーが「スパマー」としてマークされることはありません。
ローカルストレージのルール
[STO-040]
UserOperationでは、すでにmempool内で「アカウント」として使われているエンティティ(Factory / Paymaster / Aggregator)を使用できません。
これにより、PaymasterやFactory、Aggregatorを「アカウント」として同時に使うことはできません。
[STO-041]
UserOperationは、mempool内の他のUserOperationの送信者(Sender)として使われているアカウントに関連するストレージを使用できません。
これは、複数のUserOperationが同じストレージを使うことで、バンドルの競合が発生するのを防ぐためです。
一般的な評判ルール
ステーク済みのエンティティと、ステークなしのペイマスターには以下の評判ルールが適用されます。
[GREP-010]
BANNED
(禁止)されたアドレスはmempoolに追加できず、既存のUserOperationもすべて削除されます。
[GREP-020]
THROTTLED
(制限)されたアドレスは以下の制約を受けます。
- mempool内のUserOperation数が
THROTTLED_ENTITY_MEMPOOL_COUNT
以下に制限される。 - 1つのバンドル内のUserOperation数が
THROTTLED_ENTITY_BUNDLE_COUNT
以下に制限される。 -
THROTTLED_ENTITY_LIVE_BLOCKS
の間のみmempoolに残れる。
[GREP-040]
バンドル作成後の2回目の検証に失敗した場合、そのエンティティは即座にBANNED
されます。
opsSeen
は BAN_OPS_SEEN_PENALTY
に設定され、opsIncluded
はゼロになります。
[GREP-050]
UserOperationが置き換えられた場合(ガス料金を上げて新しいUserOperationを送信)、以前のUserOperationに関連付けられていたエンティティ(Paymasterなど)のopsSeen
カウントが1減少します。
ステーク済みエンティティの評判ルール
[SREP-010]
エンティティが「ステーク済み」とみなされるのは、MIN_STAKE_VALUE
以上のステークを持ち、MIN_UNSTAKE_DELAY
以上のロック期間が設定されている場合です。
[SREP-040]
ステーク済みのエンティティは、評判ルールによる制限を受けません。
- メモリプールに無制限に含めることができる。
- バンドル内にも無制限に含めることができる。
エンティティごとのルール
[EREP-010]
各ペイマスターの最大ガス使用量をバンドラーが管理する必要があります。
新しいUserOperationを追加することで、この上限を超える場合にそのUserOperationはmempoolに追加できません。
[EREP-015]
Factoryやアカウントの失敗によりUserOperationが無効になった場合、PaymasterのopsSeen
は増えません。
[EREP-016]
Factory、アカウント、Paymasterの失敗によりUserOperationが無効になった場合、AggregatorのopsSeen
は増えません。
2回目の検証時に、FactoryまたはアカウントのエラーでUserOperationが失敗した場合、PaymasterのopsSeen
は1減少します。
[EREP-020]
ステーク済みのFactoryが使用されている場合、そのFactoryはUserOperationのバリデーション違反の影響を受けます。
validateUserOp()
が拒否された場合、その失敗はFactoryの責任とみなされて評判が下がります。
[EREP-030]
ステーク済みアカウントを使用した場合、他のエンティティ(PaymasterやAggregator)が失敗しても影響を受けます。
[EREP-040]
Aggregatorは必ずステーク済みである必要があります。
[EREP-050]
ステークされていないPaymasterはコンテキストを返すことができません。
ステーク済みファクトリーのルール
[EREP-060]
ステーク済みのFactoryを使用する場合、FactoryまたはSenderが CREATE2
または CREATE
を使えます。
Factoryがステークされていない場合でも、Senderは CREATE
を使えます。([OP-032] に準拠)。**
[EREP-06]
ステーク済みFactoryは、ユーティリティコントラクトを使用して CREATE
を呼び出すことができます。
ステークされていないエンティティの評判ルール
ステークされていないエンティティの評判は、mempool内で扱えるUserOperationの数に影響します。
評判の計算
opsSeen
(受信したUserOperationの数)opsIncluded
(実際にブロックに含まれたUserOperationの数)
opsAllowed
(許可されるUserOperation数)は、上記の値を元に計算されます。
ルール
[UREP-010]
ステークされていない送信者(Sender)は、mempool内に SAME_SENDER_MEMPOOL_COUNT
個までUserOperationを保持できます。
ただし、THROTTLED
またはBANNED
の状態になった場合は、それ以下に制限されます。
[UREP-020]
ステークされていないPaymasterは、以下の式で許可されるUserOperation数が決まります。
opsAllowed = SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT + inclusionRate * min(opsIncluded, MAX_OPS_ALLOWED_UNSTAKED_ENTITY)
新しいエンティティの場合、デフォルトでは SAME_UNSTAKED_ENTITY_MEMPOOL_COUNT
のみ許可されます。
代替mempoolのルール
代替mempoolは、バンドラーがオプトイン(任意参加)できる追加のmempoolです。
これは、標準のmempoolのルールとは異なる基準でUserOperationを処理できるようにするものです。
代替mempoolは一意の識別子を持ちます。
この識別子は、IPFS上にあるYAML形式のルール定義ドキュメントのハッシュを使うのが一般的です。
代替mempoolの基本ルール
[ALT-010]
バンドラーは、P2Pプロトコル経由で代替mempoolの「トピック」をリッスンします。
[ALT-020]
代替mempoolのルールは、標準ルールに違反した場合のみ適用されます。
つまり、標準ルールに合致するUserOperationは代替mempoolには含まれません。
[ALT-021]
標準ルールに違反したUserOperationは、全ての代替mempoolで検証されて該当するものに追加されます。
[ALT-030]
バンドラーは、UserOperationを他のバンドラーに1回だけ転送します。
受信したバンドラーが、そのUserOperationをどの代替mempoolに適用するか判断します。
[ALT-040]
opsSeen
(受信した回数)と opsIncluded
(実際にブロックに含めた回数)はmempoolごとに個別管理されます。
つまり、あるmempoolでTHROTTLED
(制限)またはBANNED
(禁止)になったエンティティでも、別のmempoolでは通常どおり動作できます。
代替mempoolの評判管理
代替mempoolは、標準mempoolと同じバンドラーによって処理されますが、異なるルールを採用するためDoS攻撃のリスクが高まる可能性があります。
そのため、各代替mempoolの評判を管理し、不正なmempoolが標準mempoolや他のmempoolに悪影響を与えないように制限を設けています。
[AREP-010]
各代替mempoolは、opsSeen
と opsIncluded
を管理します。
opsSeen
は、UserOperationの最初の検証が完了し、そのmempoolに登録された時点でカウントされます。
opsIncluded
は、そのUserOperationがブロックに含まれたときにカウントされます(自身のバンドラーまたは他のバンドラーのいずれか)。
[AREP-020]
代替mempoolの評判計算に基づき、一定の違反が発生するとTHROTTLED
(制限)またはBANNED
(禁止)となります。
認証(Authorization)
[AUTH-010]
UserOperationには、EIP7702 の認証情報は1つだけ含めることができます。
EIP7702については以下の記事を参考にしてください。
[AUTH-020]
EIP7702の委任アカウントは、UserOperationのSenderとしてのみ使用できます。
その他のエンティティ(PaymasterやFactory)として使うことは禁止されています。
[AUTH-030]
EIP7702の委任アカウントは、UserOperationのSenderとして使用されている場合のみ、CALL
や EXTCODE
でアクセスできます。
背景
なぜ検証ルールが必要なのか?
通常のEOAから送信されるトランザクションでは、Ethereumノードは残高・nonce・署名の検証を行って有効性を確認します。
この仕組みでは、同じEOAからの新しいトランザクション以外が以前のトランザクションを無効化することはできません。
しかし、Account Abstractionでは、検証がEVMコードに依存するため、ストレージの状態が変化するとUserOperationの有効性が変わる可能性があります。
これに対処しないと、有効なUserOperationをmempoolに維持し続けるのが困難になり、DoS攻撃のリスクが高まります。
この問題を防ぐために、この提案での仕様ではバンドラーがUserOperationを受け入れる前に適用するルールを定義しています。
高レベルな目的
この仕様の目的は、バンドラーやブロックビルダーがUserOperationを処理する時の共通ルールを定義することです。
UserOperationの送信元(エンドユーザーのノードやP2Pネットワーク)には、以下のようなケースがあります。
- RPC(ERC7769経由)で直接送信されたもの
- 他のバンドラー(P2Pネットワーク経由)から受信したもの
このプロトコルは、スパム(ブロックに含められず、ガスを支払えない大量のUserOperation)を検出し、スパムノードからのリクエストを制限する仕組みを提供します。
スパム対策の重要性
ネットワーク内の全てのノードは、スパムの定義を統一する必要があります。
もし、あるノードが特定のUserOperationを受け入れ、それをP2Pネットワークで拡散させた場合に他のノードがそれをスパムとして扱えば、そのノード自体がスパマーとしてマークされてしまう可能性があります。
これにより、ネットワークが分裂するリスクがあるため、一貫したスパム検出ルールが求められます。
UserOperationの処理フロー
-
UserOperationの受信
- RPC経由で送信されたもの、またはP2Pネットワーク経由で受信。
-
UserOperationの検証
- 受信したノードが検証し、有効であればmempoolに追加してP2Pネットワークに転送。
-
ブロック作成時の再検証
- mempool内のUserOperationを収集してバンドルとして検証。
- バンドル全体が有効であれば、次のブロックに含める。
なぜブロック提出前に再検証が必要なのか?
通常のEthereumトランザクションは、nonce
の競合によってのみ無効化されるため、より高いガス価格のトランザクションが送信されれば元のトランザクションは無効になります。
しかし、Account Abstractionでは他のトランザクションによってストレージの状態が変わることでUserOperationが無効になる可能性があります。
そのため、ブロックに含める前に再度検証し、全てのUserOperationが有効であることを確認する必要があります。
オペコード制限の理由
UserOperationの検証は、ブロック作成前にオフチェーンで行われるため、一部のオペコードの使用を制限する必要があります。
なぜ一部のオペコードを制限するのか?
一部のオペコードは、ブロックが作成されるまで確定しない情報を参照するため、オフチェーン検証では問題がなくても実際にオンチェーンで実行すると失敗する可能性があります。
例えば、以下のような条件を設定した場合。
require(block.number == 12345);
オフチェーンでUserOperationを検証する時点では block.number
は 12345
なので成功。
しかし、後でブロックが作成されると block.number
は 12346
以降になり失敗してしまいます。
このように、オフチェーンでは成功するのにオンチェーンでは確実に失敗する検証ルールは、DoS攻撃を誘発する原因となるため禁止されています。
ストレージアクセス制限の理由
UserOperationが同じストレージ領域を共有すると、一つのストレージ変更で大量のUserOperationが無効になり得るため、ストレージのアクセス範囲を制限する必要があります。
なぜストレージアクセスを制限するのか?
UserOperationの有効性が他のUserOperationの影響を受けないようにするためです。
1つのアカウントに対して、少なくとも1つのUserOperationは確実にブロックに含められるようにするためです。
具体的な制限
UserOperationは、基本的に自分自身のアカウントのストレージのみアクセス可能です。
ステーク済みのエンティティ(Paymaster, Factory, Aggregator)は、アカウントに紐づかないストレージにもアクセス可能です。
バンドラーは、1つのアカウントが複数のUserOperationを送信する場合、事前にそれらをまとめて検証しなければならないというルールもあります。
ステークの必要性
ステークを求めることで、グローバルに利用されるコントラクト(Paymaster、Factory、Aggregator)に対して、一定の信頼性を確保することが目的です。
なぜステークが必要なのか?
ステーク済みのコントラクトには、ストレージ制限を緩和する特典があります。
ただし、スパムを防止のために、失敗が多い場合はmempoolで制限(THROTTLE
)されます。
Sybil攻撃(複数のアカウントを作成してスパムを繰り返す攻撃)を防ぎます。
もしステークなしで自由にPaymasterを作成できると、スパム攻撃のためのPaymasterを無限に生成できてしまいます。
ステークが必要なら、攻撃には一定のコストが発生するためスパム攻撃の継続が難しくなります。
ステークの役割
ステークは「罰則」として消滅するわけではありません(= スラッシュはされない)。
ただし、一定期間ロックされるため、攻撃コントラクトを短期間で入れ替えることができなくなります。
これにより、スパム行為を抑制しながら正当な利用者には柔軟性を持たせる仕組みになっています。
大量無効化の定義
大量無効化攻撃とは、オフチェーン検証では有効だったUserOperationが大量に無効化されることを狙った攻撃を指します。
この攻撃が成功すると、ネットワークの処理能力が圧迫されて正当なUserOperationの処理が遅れる可能性があります。
攻撃の方法
- 最初の検証には通るが、バンドル作成時の再検証で失敗するUserOperationを大量に送る。
- 個別には問題ないが、まとめると無効になるUserOperationを送る。
- 有効なUserOperationを送った後、それを無効にするトランザクションを「フロントラン」させる。
- 例えば、あるストレージの値を変更するトランザクションを、UserOperationよりも先に処理させることでそのUserOperationを無効化する。
この攻撃を防ぐ方法
- 検証コードを「サンドボックス化」する(他のUserOperationや環境情報に依存させない)。
- 外部ストレージアクセスを制限する(影響範囲を最小限に抑える)。
- ブロックの環境情報(例:
block.timestamp
)を使用しない。
大量無効化攻撃に該当しないケース
- メモリプールに入る前の段階で検証に失敗したUserOperation
これはネットワーク攻撃とはみなされず、APIキーやIP制限などの通常のWeb2セキュリティ対策で処理すべきものです。
- UserOperationの無効化にコストがかかる場合
例えば、1つのUserOperationを無効化するのに 5000 gas
以上かかるなら、大量無効化攻撃を成立させるには極めて高いコストが必要になります。
1ブロックで2000個のUserOperationを無効化するには、約1000万ガスのコストがかかります。
これを考慮すると、DoS攻撃のコストが高すぎて経済的に割に合いません。
また、さらなる対策を講じることで、この攻撃をより高コストにする仕組みになっています。
互換性
この提案は、コンセンサスを変更する仕様であるため、メインネットや他の対応ネットワークでハードフォークが必要になります。
ハードフォークが実施されると、古いクライアントは新しいブロックの処理に対応できず、ブロック同期ができなくなります。
具体的には、従来のクライアントは「ブロック内に含まれるべき」と想定している実行レイヤーのポストステートルートが新しい仕様では含まれないため、互換性が崩れてしまいます。
セキュリティ
ライトクライアントへの影響
ブロックの最終ステートルートの公開が次のブロックまで遅れます。
これにより、ライトクライアントは最大で1スロット分の遅延(例えば12秒)を許容しなければなりません。
実際、多くのライトクライアントプロトコルは、すでに多少の遅延を想定して設計されているため、大きな問題にはなりません。
他のブロックチェーンでは、すでに遅延したステートルートで運用している例があります。
Cosmosでは、マルチチェーンの相互運用において、ライトクライアントが遅延したステートルートを受け取る方式が採用されており、問題なく機能しています。
コントラクトへの影響
現在、同じブロック内でステートルートの取得を前提とした一般的なコントラクトは確認されていません。
そのため、この仕様変更がコントラクトの動作に直接影響を与えるケースは少ないと考えられます。
引用
Charlie Noyes charlie@paradigm.xyz, Dan Robinson dan@paradigm.xyz, Justin Drake justin@ethereum.org, Toni Wahrstätter (@nerolation), "EIP-7862: Delayed Execution Layer State Root [DRAFT]," Ethereum Improvement Proposals, no. 7862, December 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7862.
最後に
今回は「Account Abstractionのトランザクション検証ルールを定めて、コントラクトアカウントの柔軟性を活かしつつ、従来のEOA同様にネットワークの安定性を維持する仕組みを提案しているERC7562」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!