はじめに
初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
代表的なゲームはクリプトスペルズというブロックチェーンゲームです。
今回は、アカウント抽象化により、取引検証プロセスを拡張してEVMバイトコードの任意の実行を可能にし、マルチシグやソーシャルリカバリー機能を含むスマートコントラクト、ETH以外のトークンで手数料を支払うなどの機能を提案しているEIP2938についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
アカウント抽象化(Account Abstraction, AA)は、イーサリアムネットワークの取引とアカウントの管理方法を革新的に改善する提案です。
この提案では、スマートコントラクトが通常のユーザーアカウントとして機能し、取引の実行と手数料の支払いを直接管理できるようになります。
アカウント抽象化の概要と動機
従来のイーサリアムでは、取引の有効性はECDSA署名、シンプルなnonce
(取引回数を表すカウンター)、そしてアカウントの残高によって厳格に定義されています。
これに対してアカウント抽象化は、任意のEVM(イーサリアム仮想マシン)バイトコードの実行を取引の有効性の条件に追加します。
これにより、より柔軟な取引条件が可能になり、異なる種類のアプリケーションやウォレットのサポートが向上します。
アカウント抽象化については以下の記事を参考にしてください。
PAYGASの提案
アカウント抽象化の実現のために、新しいEVMオペコード「PAYGAS
」が提案されています。
このオペコードを用いることで、コントラクトは自身が支払い可能なガス価格とガスリミットを指定し、これによって取引の有効性を示すことができます。
これはコントラクトが自分自身の取引を開始し管理できるようにするための重要な機能です。
アカウント抽象化の二層構造
アカウント抽象化は、二つの層に分けて実装されます。
-
シングルテナントAA
- これは主に個人のウォレットや参加者が少ない用途を対象としています。
- ここでのアカウントは特定のユーザーまたは少数のユーザーによってのみ使用されることが想定されています。
-
マルチテナントAA
- この層は、多数の参加者を持つアプリケーション(例:tornado.cash, Uniswapなどの分散型金融プラットフォーム)をサポートするために設計されています。
- ここでは、多様な取引やインタラクションが同一のコントラクトアカウントを介して効率的に処理されることが目指されています。
アカウント抽象化によって、イーサリアムの柔軟性と拡張性が大きく向上し、新たな形のデジタルアイデンティティや様々な金融取引が実現可能になることが期待されています。
動機
ここではアカウント抽象化(AA)を推進する主な動機として、イーサリアム上でのイノベーションを制限する既存の制約に対処することが挙げられています。
ここで特に注目されているのは、スマートコントラクトウォレット、プライバシー保護システム、DeFiプロトコルのガス効率の改善、トランザクション手数料の支払いにETH以外のトークンを使用する能力などです。
主な動機とイノベーション領域
異なる署名検証方式を使用するスマートコントラクトウォレット
現在のECDSA以外に、SchnorrやBLS、ポスト量子署名方式など、より進んだ署名検証技術を利用したウォレットをサポートします。
マルチシグやソーシャルリカバリー機能を含むウォレット
資金が失われたり盗まれたりするリスクを減らすために、複数の署名や社会的な信頼に基づくリカバリー方法を含むウォレットのサポート。
プライバシーを保護するシステム
例えば、tornado.cashのようなプライバシーを重視した取引が可能なシステム。
高レベル条件を満たさないトランザクションの阻止によるDeFiプロトコルのガス効率改善
取引が特定の条件(例えば、適合する注文の存在)を満たさない場合にブロックチェーン上に含まれないようにすることで、ガスの使用を効率化します。
ETH以外のトークンでのトランザクション手数料支払い
トランザクション内でリアルタイムにそのトークンをETHに変換して手数料を支払うことができるようになります。
シングルテナントとマルチテナントAAの支援範囲
シングルテナントAAは主に1番と2番のケース、つまり個々のユーザーや少数のユーザーが利用する機能をサポートするために設計されています。
マルチテナントAAは、3番と4番のケース、つまり多数の参加者が関与するアプリケーションやプラットフォームをサポートするために設計されています。
現行の代替手段とその問題点
現在、Gas Station Network(GSN)やその他のアプリケーション固有の代替手段を用いてこれらのケースを部分的に実現していますが、これらは技術的にも経済的にも非効率であり、中間者が介在することによるリスクや依存性が生じています。
アカウント抽象化によるこれらの改善は、イーサリアムの基盤となるインフラストラクチャをより直接的に利用し、将来的にも持続可能なソリューションを提供することを目指しています。
仕様
シングルテナント
定数の定義
まず、新しいトランザクションタイプとアカウント抽象化に必要ないくつかの定数が導入されます。
Constant | Value |
---|---|
AA_ENTRY_POINT |
0xffffffffffffffffffffffffffffffffffffffff |
AA_TX_TYPE |
2 |
FORK_BLOCK |
TBD |
AA_BASE_GAS_COST |
15000 |
-
AA_ENTRY_POINT
- これはAAトランザクションが呼び出されるエントリーポイントを示すアドレスです。
-
AA_TX_TYPE
- 新しいトランザクションタイプの識別子です。
-
FORK_BLOCK
- この変更が有効になるブロック番号で、現時点では未定です。
-
AA_BASE_GAS_COST
- AAトランザクションの基本ガスコストで、通常のトランザクションの
21000
ガスより減少しています。
- AAトランザクションの基本ガスコストで、通常のトランザクションの
新しいトランザクションタイプ
新しいトランザクションタイプはEIP2718に基づいて導入され、そのタイプはAA_TX_TYPE
として定義されています。
このトランザクションのペイロードは、RLP(Recursive Length Prefix)エンコードされた配列[nonce, target, data]
として解釈されます。
これにより、従来のトランザクションにおけるECDSA署名とその検証の必要がなくなるため、基本ガスコストが減少します。
RLP(Recursive Length Prefix)エンコードは、イーサリアムで使用されるデータのシリアライズ(直列化)形式で、トランザクションデータやブロックヘッダー、アカウントの状態などを効率的にエンコードするために設計されています。
RLPはデータの長さと内容をエンコードするために使用され、特に可変長のデータ構造を扱う際にその構造を維持することができます。
RLPの基本的なルール
RLPエンコードは、単一のバイトまたはバイト配列をエンコードするためのルールを持っています。
-
単一のバイトデータ
- バイト値が
0x00
から0x7F
(127
)の範囲内であれば、そのバイト自体がRLPエンコーディングの結果です。
- バイト値が
-
文字列(バイト配列)
- 長さが1バイト以上で、最大55バイトのバイト配列は、長さに
0x80
を加えたバイトが先頭に来るようにエンコードされます。 - 例えば、
[0x01, 0x02, 0x03]
の配列は、0x83
(0x80 + 3)に続いてオリジナルのデータ0x01, 0x02, 0x03
が続きます。
- 長さが1バイト以上で、最大55バイトのバイト配列は、長さに
-
長い文字列
-
55
バイトを超える長さのバイト配列は、長さを表すバイト配列を先に置き、そのバイト配列の長さに0xB7
を加えたバイトが前に来ます。 - 例えば、
256
バイトのデータは、長さを表す0x0100
に0xB7を加えた0xB9, 0x01, 0x00
という形でエンコードされます。
-
RLPエンコードの具体例
例として、以下のデータ構造をRLPエンコードしてみます。
["cat", "dog"]
これは文字列のリストで、各文字列を個別にエンコードした後、リスト全体をエンコードします。
- 文字列 "cat" はバイト配列として
[0x63, 0x61, 0x74]
です。- この長さは3なので、先頭に
0x83
を付けます。 - エンコードされた形式は
[0x83, 0x63, 0x61, 0x74]
になります。
- この長さは3なので、先頭に
- 文字列 "dog" はバイト配列として
[0x64, 0x6F, 0x67]
です。- 同様に、長さ3なので先頭に
0x83
を付けます。 - エンコードされた形式は
[0x83, 0x64, 0x6F, 0x67]
になります。
- 同様に、長さ3なので先頭に
- これら二つのエンコードされた文字列を含むリストをエンコードすると、リスト全体の長さは
6+6=12
なので、先頭に0xC0 + 12 = 0xCC
を付けます。- したがって、全体のエンコードは
[0xCC, 0x83, 0x63, 0x61, 0x74, 0x83, 0x64, 0x6F, 0x67]
となります。
- したがって、全体のエンコードは
このようにRLPエンコードは、データの階層構造を保ちながら効率的にシリアライズするための非常に有効な方法です。
ノンスの処理
ノンスは既存のトランザクションと同様に処理されます。
トランザクションのノンスがターゲットアドレスのノンスと一致することが確認され、一致しない場合はトランザクションは無効とされます。
一致する場合は、トランザクションが進行し、ノンスが即座に1増加します。
ガスリミット
このトランザクションタイプには本来のガスリミットが設定されていません。
実行開始時のガスリミットは、ブロックの残りガス(block.gas_limit
から既に使われたガスを引いたもの)として設定されます。
そして、PAYGAS
オペコードを使用して、実行中にガスリミットを下方修正することが可能です。
これらの変更により、アカウント抽象化がサポートされることで、より柔軟なトランザクション処理や新しいタイプのスマートコントラクトアプリケーションの開発が可能になります。
トランザクション全体にわたるグローバル変数
以下の表に示すように、新たなグローバル変数が導入され、AAトランザクションに特有のロジックに基づいて初期値が設定されます。
Variable | Type | Initial Value |
---|---|---|
globals.transaction_fee_paid |
bool | False if type(tx) == AA_TX_TYPE else True |
globals.gas_price |
int | 0 if type(tx) == AA_TX_TYPE else tx.gas_price |
globals.gas_limit |
int | 0 if type(tx) == AA_TX_TYPE else tx.gas_limit |
これらの変数は、トランザクションがAAトランザクションタイプかどうかに基づいて異なる初期値を持ちます。
AAトランザクションでは、手数料の支払いやガス価格、ガスリミットがトランザクション開始時には未定義(0またはFalse)であり、後述のPAYGAS
オペコードによって定義されます。
NONCE (0x48) オペコード
NONCE
オペコードは、呼び出し対象のアカウントのノンスをスタックにプッシュする新しいオペコードです。
このオペコードのガスコストはG_base
と定義されています。
PAYGAS (0x49) オペコード
PAYGAS
オペコードは、トランザクションのガス価格とガスリミットを設定し、これらの値に基づいてトランザクションの手数料を前払いする機能を持つオペコードです。
このオペコードは、スタックから2つの引数を取り出し(トップのバージョン番号とその下のメモリ開始位置)、初期実装ではバージョン番号が0
であることを要求します。
次に、指定されたメモリ位置からガス価格とガスリミットを読み取ります。
条件を満たす場合(アカウント残高が十分であり、手数料が未払いであり、トップレベルのAA実行フレームである場合)、指定されたガス価格とガスリミットに基づいて手数料が差し引かれ、トランザクションが実行されます。
条件を満たさない場合は例外が投げられます。
また、トランザクションの終了時にはglobals.transaction_fee_paid
がTrue
であることが必要であり、そうでない場合トランザクションは無効です。
また、PAYGAS
は実行のチェックポイントとして機能し、PAYGAS
呼び出し後にトップレベルの実行フレームがrevert
した場合、その時点で実行は終了します。
この新しい設計は、アカウント抽象化の文脈でのトランザクション手数料の支払いやガス管理をより細かく制御し、より柔軟なスマートコントラクトの実装を可能にします。
リプレイ攻撃保護
リプレイ攻撃は、有効なデータ伝送が悪意のある第三者によって再送され、不正な効果をもたらす可能性がある攻撃です。
これを防ぐために以下の2つの方法が提案されています。
SET_INDESTRUCTIBLEの要求
このアプローチでは、AAトランザクションがターゲットとするコントラクトがEIP2937のSET_INDESTRUCTIBLE
オペコードで始まることを要求します。
このオペコードが設定されているコントラクトは、SELFDESTRUCT
を無効にし、コントラクトが破壊されることを防ぎます。
そのため、AAトランザクションがこのオペコードで始まらないコントラクトをターゲットとする場合、そのトランザクションは無効とされ、ブロックに含めることはできません。
AA_PREFIX
はこのオペコードを含むように変更する必要があります。
SELFDESTRUCTでのNonceの保存
もう一つのオプションは、コントラクトがSELFDESTRUCT
を呼び出した時にノンスをゼロにリセットするのではなく、ノンスを保存することです。
これにより、同じアドレスが再利用された場合でも、ノンスが維持され、以前のトランザクションが再び実行されるのを防ぎます。
その他
CALLER (0x33)
AAトランザクションによって開始されたコールの最初のフレームでこのオペコードが呼び出された場合、それはAA_ENTRY_POINT
を返さなければなりません。
これはAAトランザクションが始まった元のエントリポイントを示します。
ORIGIN (0x32)
AAトランザクションの任意の実行フレームでこのオペコードが呼び出されると、それもAA_ENTRY_POINT
を返さなければなりません。
これはトランザクションの起源がAAトランザクションであることを示しています。
GASPRICE (0x3A)
このオペコードは、globals.gas_price
の値をスタックにプッシュします。
AAトランザクションでは、PAYGAS
オペコードを通じてこの値が設定されるため、ガス価格が動的に定義されます。
非AAトランザクションでは、このオペコードの動作に変更はありません。
なぜなら、globals.gas_price
はトランザクションのgas_price
で初期化され、PAYGAS
が呼び出されないため、変更されないからです。
これらの措置は、アカウント抽象化を利用したトランザクションが、ネットワーク上でより安全に行われることを確保するために設計されています。
特にリプレイ攻撃の防止は、セキュリティの強化において重要な要素です。
トランザクションの検証と再放送
アカウント抽象化(AA)に関連するトランザクションをマイニングや再送信する時の戦略について説明しています。
これらの戦略は、マイナーや検証ノードがDoS攻撃を避けるために、トランザクションが実際に手数料を支払うかどうかを効率的に判断する方法に関するものです。
マイナーや検証ノードは、AAトランザクションを受信すると、現在のチェーンheaderのポスト状態に対して実行を試み、そのトランザクションの有効性を判断します。
以下のいずれかの条件を満たすと、実行は失敗として終了します。
- ターゲットのコードがAA_PREFIXで始まらない場合。
- 次のいずれかのオペコードを実行した場合。
- 環境に関連するオペコード(
BLOCKHASH
,COINBASE
,TIMESTAMP
,NUMBER
,DIFFICULTY
,GASLIMIT
) - 任意のアカウント(ターゲット自身を含む)の
BALANCE
- ターゲット以外の何かに変更する外部コール/作成(
CALL
,CALLCODE
,STATICCALL
,CREATE
,CREATE2
) - ターゲット以外のアドレスのコードを読み込む外部状態アクセス(
EXTCODESIZE
,EXTCODEHASH
,EXTCODECOPY
, そしてCALLCODE
とDELEGATECALL
)
- 環境に関連するオペコード(
- 実行が指定された
VERIFICATION_GAS_CAP
を超えたり、ブロック内の利用可能なガスを超えたりした場合 -
PAYGAS
に達し、残高が十分かどうかによって成功または失敗として終了する(例:balance >= gas_price * gas_limit
)
トランザクションのメンプール管理
ノードは、現在有効なノンスより高いノンスのトランザクションをメンプールに保持しません。
同じコントラクトと同じノンスに対する別のトランザクションが入ってきた場合、そのガス価格が十分に高い場合は既存のものを置き換え、そうでなければ破棄されます。
新しいブロックの処理
新しいブロックを処理する時、AAトランザクションのターゲットとなったアカウントに注意を払い、そのアカウントに対する保留中のトランザクションをすべて破棄します。
その他のトランザクションはメンプールに残ります。
Constant | Value |
---|---|
VERIFICATION_GAS_MULTIPLIER | 6 |
VERIFICATION_GAS_CAP | VERIFICATION_GAS_MULTIPLIER * AA_BASE_GAS_COST = 90000 |
AA_PREFIX | if(msg.sender != shr(-1, 12)) { LOG1(msg.sender, msg.value); return }; compilation to EVM TBD |
この戦略により、AAトランザクションの導入が段階的に行われ、初期段階ではシンプルなシングルテナントのユースケースが、後の段階ではより複雑なマルチテナントのユースケースが可能になることを目指しています。
シングルテナント+
アカウント抽象化(AA)におけるシングルテナントの実装がどのように進化する可能性があるかを示しています。
これには新しいEIP(イーサリアム改善提案)の導入が含まれ、特定の制限を緩和し、より多様なケースでの使用を可能にするものです。
Indestructible Contracts EIPの導入
Indestructible Contracts EIPが導入されると、DELEGATECALL
を含む外部コードアクセス(EXTCODESIZE
, EXTCODEHASH
, EXTCODECOPY
, CALLCODE
, DELEGATECALL
)が、特定の条件下で許可されるようになります。
具体的には、コントラクトの最初のバイトがSET_INDESTRUCTIBLE
オペコードである場合、これらの操作が禁止されなくなります。
ただし、ターゲットまたはプリコンパイル以外への呼び出しで呼び出し先が変更される操作(CALLCODE
やDELEGATECALL
以外)は引き続き許可されません。
IS_STATIC EIPの追加
IS_STATIC EIPが追加されると、静的コール(状態を変更しないコール)は許可されるが、状態を変更するコールは許可されない、というようなプレフィックスを許可リストに追加することが可能になります。
許可されるプレフィックスの拡張
他の良性のユースケース(例えば、受け取った支払いのログ取り)を可能にするプレフィックスを許可リストに追加することも可能です。
AAアカウントへの外部コールの許可
新しいオペコードRESERVE_GAS
を導入することで、AAアカウントへの外部コールを許可する方法が提案されています。
このオペコードは引数Nを取り、すぐにNガスを消費し、Nガスを返金プールに追加するというシンプルな挙動をします。
このようにして、少なくともAA_BASE_GAS_COST
の2倍のガスを予約するプレフィックスが許可されると、アカウントにコールするために少なくともAA_BASE_GAS_COST
ガスが消費されることが保証されます(返金は消費ガスの最大50%までなので)。
これにより、そのアカウントをターゲットとするメンプール内のトランザクションが無効になり、この不変条件が保持されます。
RESERVE_GASの値の設定
アカウントは、安全により高いVERIFICATION_GAS_CAP
を持つために、より高いRESERVE_GAS
値を設定することを選択するかもしれません。
その目的は、アカウントを編集する最小ガスコスト(つまり、そのRESERVE_GAS
の半分)とそのアカウントに許可されたVERIFICATION_GAS_CAP
との間にVERIFICATION_GAS_MULTIPLIER
から1の比率を保持することです。
これにより、前のセクションで示唆された最大再検証ガス消費に関する不変条件も保持されます。
これらの変更は、AAの枠組みの柔軟性を大きく向上させ、多様なアプリケーションのサポートを可能にすることを目指しています。
マルチテナント
マルチテナントのアカウント抽象化(AA)の環境において、メンプール(未確認トランザクションプール)で複数の保留中トランザクションをアカウントごとに管理するためのサポートを追加することについて検討しています。
ここでの主な課題は、単一のトランザクションが他の全てのトランザクションを無効にする可能性がある状態変更を引き起こす可能性がある点です。
また、単純にガス価格に基づいてトランザクションを優先する場合、最も高いガス価格を支払う意志があるユーザーが多くの(相互に排他的な)トランザクションバージョンを発行し、他のユーザーのトランザクションをメンプールから押し出すという攻撃ベクトルが存在します。
戦略の概要
提案された戦略では、受信トランザクションがEIP2930スタイルのアクセスリストを含むことを要求します。
このアクセスリストにはトランザクションが読み取りまたは変更するストレージスロットが詳細に記載されており、リスト外のアクセスは無効とされます。
トランザクションがメンプールに含まれるためには、そのアクセスリストがメンプール内の他のトランザクションのアクセスリストと重複しないこと、またはそのガス価格がより高い場合に限られます。
EIP2930については以下の記事を参考にしてください。
メンプールの改善提案
このアプローチのもう1つの考え方は、単にアカウントごとのメンプールではなく、ストレージスロットごとのメンプールを持つことです。
ただし、トランザクションは複数のストレージスロットごとのメンプールの一部となる可能性があります(必要に応じて例えば5つのストレージスロットに制限することも可能です)。
マルチテナントAAの課題
マルチテナントAAでは、マイナーが受信トランザクションのノンスを編集し、それらを順序付けて最終的なトランザクションのハッシュが公開時に予測不可能となることを許可する必要がほぼ確実にあります。
クライアントはこの問題を明確に回避するための作業が必要とされます。
研究と開発の必要性
これらのアイディアを洗練するためにはさらなる研究が必要であり、それは将来の作業で行われることとされています。
このような進展は、イーサリアムのトランザクション処理とネットワークの効率性を大幅に向上させる可能性がありますが、多くの技術的な挑戦と調整が必要とされるでしょう。
この提案が実装されれば、より複雑でインタラクティブなデータのやり取りが可能となり、イーサリアムの使用ケースがさらに
広がることになります。
補足
アカウント抽象化(AA)における議論の核心は、マイナーやネットワークノードが取り込むか再送信するトランザクションが実際に手数料を支払うことを確認できる必要がある点にあります。
通常のトランザクション設定では、署名とノンスが有効であり、残高とガス価格が十分である限り、トランザクションは確実に含まれ、手数料が支払われるため、これらのチェックは迅速に行うことができます。
アカウント抽象化の目標
アカウント抽象化の目標は、アカウントがトランザクションの有効性に対してより柔軟な条件を設定できるようにEVMコードを指定することを許可することですが、このEVMコードは既存の設定と同じ安全性を持ちつつ迅速に検証可能でなければなりません。
トランザクションの実行フェーズ
通常のトランザクションでは、トップレベルのコールがtx.sender
からtx.to
へ行われ、tx.value
を伴っています。
AAトランザクションでは、トップレベルのコールがエントリーポイントアドレス(0xFFFF...FF
)からtx.target
へ行われます。
トップレベルのコード実行は、短い検証フェーズ(PAYGAS
前)と長い実行フェーズ(PAYGAS
後)の2つのフェーズに分かれることが想定されています。
検証フェーズ中に実行が例外を投げた場合、そのトランザクションは現在のシステムでの無効な署名を持つトランザクションと同様に無効とみなされます。
検証フェーズ後に例外が投げられた場合でも、トランザクションは手数料を支払うため、マイナーはそれを含めることができます。
AAの異なる段階の遷移
AAの異なる段階への遷移は、マイナー戦略の変化によって完全に行われます。
最初の段階はシングルテナントAAをサポートし、ここではtx.target
がユーザーアカウント(例えば、マルチシグなどのスマートコントラクトウォレット)を表すコントラクトのみが容易に実装可能なケースが主に対象です。
後の段階では、ログやライブラリのサポートが向上し、マルチテナントAAのサポートに向けて進展します。
ここでは、tx.target
が複数のユーザーからのcall
を処理するアプリケーションを表す場合など、より広範なケースをサポートしようとするのが目標です。
シングルテナントAAにおけるノンスの役割
シングルテナントAAでは、ノンスは引き続き厳格に適用されます。
これは、シングルターゲットAAがトランザクションのハッシュが一度だけチェーンに含まれるという不変条件を破ることがないようにするためです。
シングルテナントAAにおいては、任意の順序でトランザクションを含めることには限定的な価値があるものの、その不変条件を破ることに十分な価値はないとされています。
ノンスはAAアカウントでは二重の目的を持っています。
リプレイ攻撃の防止と、CREATE
オペコードを使用した時のコントラクトアドレス生成のために使用されます。
これは、単一のトランザクションがノンスを1以上増加させる可能性があることを意味します。
しかし、AAによって導入された他のメカニズムが、1つ以上のトランザクションを含むチェーンを容易に検証する能力を既に損なっているため、これは許容されています。
ただし、CREATE2
を使用することがAAコントラクトには強く推奨されています。
マルチテナントAAにおけるノンス
マルチテナントAAでは、ノンスは可塑性を持つようになると予想されます。
このシステムを使用するアプリケーションは、この変更を管理する必要があります。
マルチテナント環境では、異なるユーザーまたはプロセスからの複数のトランザクションが同時に処理されるため、ノンスの厳格な連続性を維持することが困難または不要になる可能性があります。
リプレイ保護
リプレイ保護には、SET_INDESTRUCTIBLE
を要求するか、SELFDESTRUCT
の挙動を変更するという二つのアプローチのいずれかが必要です。
これらはコンセンサス変更として実装される必要があり、単にAA_PREFIX
の一部としてではなく、トランザクションハッシュの一意性が維持されるようにするためです。
外部データへのアクセス制限
伝統的なトランザクションでは、あるアカウントXから発信されていないトランザクションが実行される時に、Xの送信者であるトランザクションを無効にすることはできません。
外部のトランザクションによってXに課される唯一の状態変更は、その残高を増加させることであり、これによってトランザクションが無効になることはありません。
しかし、AAコントラクトがPAYGAS
を呼び出す前(検証フェーズ中)に外部データ(他のアカウントやGASPRICE
、DIFFICULTY
などの環境変数)にアクセスすることを許可すると、この不変条件が破られます。
例えば、ある人が数千のAAトランザクションを送信し、それらのトランザクションがFOO.get_number() != 5
の場合に外部コールを実行して例外を投げるとします。
送信時にFOO.number
が5
に設定されているかもしれませんが、単一のトランザクションがFOO.number
を他の値に設定することで、それに依存する数千のAAトランザクションがすべて無効になる可能性があります。
これは深刻なDoS攻撃のリスクです。
この例外として許可されているのは、破壊不可能(その最初のバイトがこのEIPで定義されたSET_INDESTRUCTIBLE
オペコードである)コントラクトです。
これは安全な例外です。
なぜなら、読み取られるデータは変更されないからです。
BALANCEの読み取り禁止
BALANCE
の読み取りを禁止することは、緩やかに攻撃ベクトルをブロックします。
攻撃者が最悪の場合、6700
ガス(15000
や21000
ガスではなく)のわずかなコストでトランザクションを再処理させることができるためです。
AAトランザクションが特定のプレフィックスを持つコントラクトを呼び出す必要がある
プレリュード(プレフィックス)は、AAトランザクションのみがそのコントラクトを呼び出すことを保証するために使用されます。
これは上記の不変条件を保持するために取られた別の措置です。
このチェックが行われなければ、AAアカウントX外部から発生したトランザクションがXに呼び出され、ストレージ変更を強制し、たった5000
ガスのコストでそのアカウントをターゲットとするトランザクションが再処理される可能性があります。
このように、AA環境でのトランザクション処理においては、外部データアクセスの制限と特定のコントラクト呼び出し規則を設けることが、システムの安全性と正確な動作を保証するために重要です。
マルチテナント
マルチテナント アカウント抽象化(AA)について詳しく説明しており、異なるユーザーが同じアカウントに対して取引を行う場合の複雑さをどのように解決するかに焦点を当てています。
これを理解するために、Tornado CashとUniswapの二つのユースケースを例に挙げています。
Tornado Cashの利用例
Tornado Cashは、プライバシーを重視したETH送金を可能にするプラットフォームです。
以下の手順で動作します。
-
預金
- ユーザーがTC(Tornado Cash)コントラクトに標準数量のコイン(例:
1ETH
)を預ける。 - ユーザーが知る秘密のハッシュを含む預金記録がTCコントラクトに保存されるマークルツリーに追加されます。
- ユーザーがTC(Tornado Cash)コントラクトに標準数量のコイン(例:
-
引き出し
- 引き出し時、ユーザーは自分が知っている秘密のハッシュがマークルツリーのどこかの葉にあることを証明するZK-SNARKを生成して送信します。
- TCコントラクトはZK-SNARKを検証し、
nullifier
値(秘密から導出される)がまだ使用されていないことを確認します。 - コントラクトはユーザーが指定したアドレスに
1ETH
を送信し、そのユーザーのnullifier
が使用済みであることを記録します。
AAを利用すると、中継者(relayer)を介さずにユーザーが直接TCコントラクトをターゲットにしたAAトランザクションを送信でき、ZK-SNARKの検証とnullifier
のチェックを検証ステップで行い、その直後にPAYGAS
を呼び出すことが可能になります。
これにより、引き出し手が自分の引き出しアドレスへのコインから直接ガス代を支払うことができ、中継者の必要性や預金アドレスとのオンチェーンリンクを回避できます。
Uniswapの利用例
Uniswapの新バージョンでは、トランザクションが直接Uniswapコントラクトをターゲットにできるようにすることが考えられます。ユーザーは事前にトークンをUniswapに預け、Uniswapはそれらの残高と、それらの残高を使って取引を検証できる公開鍵を保存します。AAによって開始されたUniswapトレードは、これらの内部残高のみを使って支出することができます。
これは通常のトレーダーには役立ちませんが、裁定取引を行う者にとっては大きな利点です。裁定取引者はUniswapにコインを預け、市場条件が変わるたびに裁定取引を行うトランザクションを送信できます。そして、価格制限などのロジックが検証ステップ中に強制されます。これにより、裁定取引が最初に行われた場合にのみチェーンに含まれ、裁定取引者がガス代を支払わずに済み、チェーンに含まれる「ジャンク」トランザクションの数が
減少します。これはブロックチェーンの実質的なスケーラビリティと市場効率の両方を大幅に向上させる可能性があります。
#互換性
アカウント抽象化(AA)の実装に関する説明文ですが、主に後方互換性、トランザクションの不可変性、およびリプレイ保護について触れています。これらの側面は、AAをイーサリアムネットワークに導入する際の重要な考慮事項です。
後方互換性
このAAの実装は、既存のトランザクションタイプを維持しています。EOA(Externally Owned Account、外部所有アカウント)であることを確認するために使われるorigin == caller
の検証方法は依然として有効ですが、AAアカウントには拡張できません。AAトランザクションでは、常にorigin
がAA_ENTRY_POINT
(AAのエントリーポイントアドレス)と等しくなります。
トランザクションの不可変性の破壊
シングルテナントAAでは、設計が不十分なAAコントラクトがトランザクションの不可変性(トランザクションが飛行中に変更されても有効な状態で残ることを避ける性質)を破る可能性があります。つまり、AAトランザクションを途中で修正し、修正されたバージョンが依然として有効になることが可能です。AAアカウントのコントラクトは、このようなことが不可能になるように設計することができますが、それはコントラクト設計者の責任です。マルチテナントAAでは、トランザクションの不可変性がさらに徹底的に破壊され、マルチテナントAAの機能を使用する正当なアプリケーションでもトランザクションハッシュが予測不可能になります(ただし、以前から存在するアプリケーションではこの不変性はさらに破壊されません)。
リプレイ保護の欠如
AAコントラクトは、明示的に組み込まれない限りリプレイ保護を持ちません。これは、EIP 1344で導入されたCHAINID
(0x46)オペコードを使用して実装することができます。リプレイ攻撃とは、有効なトランザクションデータが悪意を持って再送されることによって発生するセキュリティリスクであり、異なるブロックチェーンネットワーク間でトランザクションが重複して実行されることを防ぎます。
これらの点から、AAの導入はイーサリアムのセキュリティモデルと互換性を保ちつつ、より柔軟で高度なトランザクション検証メカニズムを提供することを目指していますが、適切な設計とセキュリティ対策の実装が必要であることが強調されています。
互換性
後方互換性
このAAの実装は、既存のトランザクションタイプを維持しています。
EOA(Externally Owned Account、外部所有アカウント)であることを確認するために使われるorigin == caller
の検証方法は依然として有効ですが、AAアカウントには拡張できません。
AAトランザクションでは、常にorigin
がAA_ENTRY_POINT
(AAのエントリーポイントアドレス)と等しくなります。
トランザクションの不可変性の破壊
シングルテナントAAでは、設計が不十分なAAコントラクトがトランザクションの不可変性(トランザクションが飛行中に変更されても有効な状態で残ることを避ける性質)を破る可能性があります。
つまり、AAトランザクションを途中で修正し、修正されたバージョンが依然として有効になることが可能です。
AAアカウントのコントラクトは、このようなことが不可能になるように設計することができますが、それはコントラクト設計者の責任です。
マルチテナントAAでは、トランザクションの不可変性がさらに徹底的に破壊され、マルチテナントAAの機能を使用する正当なアプリケーションでもトランザクションハッシュが予測不可能になります(ただし、以前から存在するアプリケーションではこの不変性はさらに破壊されません)。
リプレイ保護の欠如
AAコントラクトは、明示的に組み込まれない限りリプレイ保護を持ちません。
これは、EIP1344で導入されたCHAINID
(0x46
)オペコードを使用して実装することができます。
リプレイ攻撃とは、有効なトランザクションデータが悪意を持って再送されることによって発生するセキュリティリスクであり、異なるブロックチェーンネットワーク間でトランザクションが重複して実行されることを防ぎます。
EIP1344については以下の記事を参考にしてください。
これらの点から、AAの導入はイーサリアムのセキュリティモデルと互換性を保ちつつ、より柔軟で高度なトランザクション検証メカニズムを提供することを目指していますが、適切な設計とセキュリティ対策の実装が必要であることが強調されています。
テスト
テストコードは以下に格納されています。
実装
実装コードは以下に格納されています。
セキュリティ
再検証
トランザクションがメンプールに入るとき、クライアントはそのトランザクションが有効かどうかを迅速に判断することができます。
トランザクションが有効であると判断された場合、そのトランザクションが無効になる可能性があるのは、同じアカウントからの他のトランザクションによってのみです。
しかし、攻撃者が既存のトランザクションを無効にするトランザクションを公開し、ネットワークにトランザクション自体の計算よりも多くの再計算を強いるケースが存在します。
このEIPは、再計算が単一のブロック内でブロックガスリミットの理論上の最大6倍に制限されるという不変条件を維持しています。
これは以前よりも多少コストがかかるものの、それほど高価ではありません。
ピアによるDoS攻撃
DoS攻撃を防御することは困難です。
特にピアリスト内のシビル(偽装アカウント)を識別することは難しいため、いつでも攻撃が開始されるか、賄賂を受けて開始されるかもしれません。
この問題はAAが導入するものではなく、現在のクライアントに対しても無効な署名を持つトランザクションでターゲットを埋め尽くすことによって達成することができます。
しかし、AAにより許可される検証作業の増加により、無効なトランザクションでクライアントが費やす計算量に上限を設けることが重要になります。
この理由から、マイナーが推奨されるマイニング戦略に従うことが最善です。
引用
Vitalik Buterin (@vbuterin), Ansgar Dietrichs (@adietrichs), Matt Garnett (@lightclient), Will Villanueva (@villanuevawill), Sam Wilson (@SamWilsn), "EIP-2938: Account Abstraction [DRAFT]," Ethereum Improvement Proposals, no. 2938, September 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2938.
最後に
今回は「アカウント抽象化により、取引検証プロセスを拡張してEVMバイトコードの任意の実行を可能にし、マルチシグやソーシャルリカバリー機能を含むスマートコントラクト、ETH以外のトークンで手数料を支払うなどの機能を提案しているEIP2938」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!