はじめに
初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
代表的なゲームはクリプトスペルズというブロックチェーンゲームです。
今回は、EOAアカウントからコントラクトアカウントに複数の資産の移行の手間とコストを削減し、EOAからコントラクトウォレットへの移行を効率的に行う仕組みを提案しているEIP7377についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
EIP2718(Ethereum Improvement Proposal 2718)は、Ethereumのトランザクション構造を拡張するための提案で、新しいトランザクションタイプを導入することで、さまざまな機能や拡張性の向上を図るものです。
ここで紹介されている新しいトランザクションタイプ「0x04
」は、その具体的な実装例の一つです。
このトランザクションタイプは、特にスマートコントラクトのデプロイとそのストレージの設定に関連しています。
トランザクションフォーマットの概要
新しいトランザクションタイプは以下のフォーマットで構成されます。
0x04 || rlp([chainId, nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, codeAddr, storage, data, value, accessList, yParity, r, s])
-
chainId
- トランザクションが実行されるブロックチェーンのID。
-
nonce
- 送信者アカウントのトランザクションカウント。
-
maxFeePerGas
- トランザクションにおける最大ガス料金。
-
maxPriorityFeePerGas
- マイナーに支払う優先度手数料の最大値。
-
gasLimit
- トランザクションで消費されるガスの最大量。
-
codeAddr
- コードが格納されているアドレス。
-
storage
- ストレージのキーと値のペアのリスト。
-
data
- トランザクションに含めるデータ。
-
value
- 送信するEtherの量。
-
accessList
- ガスコストを削減するために事前にアクセスするアドレスとストレージキーのリスト。
-
yParity, r, s
- ECDSA署名のパラメータ。
主な機能
このトランザクションタイプの主な機能は、スマートコントラクトのコードを更新し、そのストレージを設定することです。
以下のステップで行われます。
-
コードの更新
-
codeAddr
で指定されたアドレスに格納されているコードを取得し、送信者アカウントのコードフィールドに設定します。 - これにより、コントラクトのロジックを変更することができます。
-
-
ストレージの適用
-
storage
に含まれるキーと値のペアを使用して、送信者のストレージトライを更新します。 - これにより、コントラクトの内部状態をカスタマイズすることが可能です。
-
意義と利用シナリオ
このタイプのトランザクションは、特にアップグレーダブルなスマートコントラクトや、動的にコードを変更する必要があるアプリケーションで有用です。
デプロイ後もコントラクトを柔軟に管理できるため、長期にわたるプロジェクトや、進化し続けるデジタルサービスに適しています。
動機
提案されている内容は、Ethereumのアカウントアブストラクション(account abstraction)を進めるための重要なステップです。
アカウントアブストラクションは、ユーザーエクスペリエンスを向上させ、スマートコントラクトウォレット(smart contract wallets)の採用を促進するために、Ethereumコミュニティが追求している目標の一つです。
アカウントアブストラクションとは何か?
アカウントアブストラクションは、ユーザーインタフェースの改善とシンプルさを提供することを目的としています。
これにより、通常のアドレス(外部所有アカウント、EOA)とスマートコントラクトの違いを抽象化し、どちらも同じように取り扱えるようにすることを意味します。
これは特に、新規ユーザーがEthereumを使いやすく感じるようにするために重要です。
アカウントアブストラクションについては以下の記事を参考にしてください。
現在の問題
現在、多くのEthereumユーザーはEOAを使用しており、これにはいくつかの欠点があります。
EOAは秘密鍵によって直接管理され、ユーザーは秘密鍵の管理に責任を持たなければならないため、セキュリティリスクが高まります。
さらに、スマートコントラクトウォレットへの移行には、高額な手数料がかかり、多くのトランザクションを個別に署名し検証する必要があります。
これは特に、資産が多いユーザーにとっては大きな障壁となっています。
提案されている解決策
この提案は、EOAからスマートコントラクトウォレットへの移行を容易にするメカニズムをプロトコルに組み込むことを目指しています。
具体的には、EOAの全資産をスマートコントラクトウォレットに効率的かつ安全に移行するためのプロセスがプロトコルレベルでサポートされることになります。
これにより、手数料の負担が減り、移行プロセスが自動化されるため、ユーザーはスムーズに新しいウォレットシステムに適応することができるようになります。
期待される効果
このメカニズムが導入されれば、スマートコントラクトウォレットへの移行が加速され、これによってスマートコントラクトウォレットがより広範囲にわたってサポートされ、統合されるようになります。
これはスマートコントラクトウォレットが単なるニッチな使用例から主流のソリューションへと変わることを意味し、Ethereumの全体的なセキュリティとユーザビリティが向上します。
この提案は、Ethereumプラットフォームの将来にとって非常に重要なステップであり、多くのユーザーにとっての大きな進歩をもたらす可能性があります。
仕様
提案されている「マイグレーショントランザクションタイプ」は、ブロックX(フォークブロック)で導入されます。
フォークとは、ブロックチェーンのプロトコルに大きな変更を加え、既存のルールから新しいルールへの遷移を行うプロセスです。
フォークブロックXについて
フォークブロックXは、この新しいトランザクションタイプがネットワークに実装される具体的なブロック番号を指します。
このブロック番号に達した時点で、新しいルールが有効になります。
マイグレーショントランザクション
この仕組みはEthereum Improvement Proposal (EIP) 2718に基づいており、特定のトランザクションタイプを定義するものです。
トランザクションのフィールド定義
まず、移行トランザクションの具体的なフィールドとそのデータタイプは以下になります。
Field | Type |
---|---|
chainId | uint256 |
nonce | uint64 |
maxFeePerGas | uint256 |
maxPriorityFeePerGas | uint256 |
gasLimit | uint64 |
codeAddr | address |
storage | List[Tuple[uint256, uint256]] |
data | bytes |
value | uint256 |
accessList | List[Tuple[address, List[uint256]]] |
yParity | uint8 |
r | uint256 |
s | uint256 |
トランザクションペイロード
このトランザクションは 0x04
というタイプで、RLP (Recursive Length Prefix) 形式でエンコードされたデータセットを含みます。
このデータセットは上記のフィールドの順に並べられています。
RLP(Recursive Length Prefix)は、Ethereumネットワークでデータの符号化(エンコード)および復号化(デコード)に使用されるデータ構造とアルゴリズムです。
RLPの主な目的は、任意のネスト構造を持つデータ(例えば、リスト、文字列、整数など)をバイト列に変換することです。
Ethereumでは、トランザクション、ウォレットアドレス、ブロックなどのデータをブロックチェーン上で効率的に保存しやすくするためにRLPが使用されます。
RLPの動作原理
RLPはとてもシンプルなルールに基づいています。
基本的には、単一のデータアイテムとリストをエンコードするためのルールがあります。
単一のデータアイテム(バイト列)のエンコード
データアイテムが単一のバイト(0x00
から0x7f
)の場合、そのバイトはそのまま出力されます。
データアイテムがそれより長い場合(例:文字列や整数)、エンコードは以下のように行われます。
- データの長さを表すバイトに
0x80
を加えた値を先頭に置きます。 - それに続いて元のデータが来ます。
リストのエンコード
リスト内の各アイテムを個別にRLPエンコードします。
エンコードされたアイテム全体の長さを計算し、この長さに0xc0
を加えた値をリストの先頭に置きます。
それに続いてエンコードされた各アイテムが順に来ます。
例
文字列 "dog" をRLPエンコードする場合。
- 文字列 "dog" はバイト列で表されると
0x646f67
です。 - このバイト列の長さは
3
なので、長さに0x80
を加えた0x83
を先頭に置きます。 - エンコード結果は
0x83646f67
となります。
RLPの利点
-
シンプルさ
- RLPは非常にシンプルで、実装が簡単です。
-
効率性
- データのオーバーヘッドが少なく、格納と送信が効率的です。
-
汎用性
- 任意のデータ構造をエンコードでき、Ethereumで広く利用されています。
RLPはEthereumの基本的なコンポーネントの一つであり、ブロックチェーン技術におけるデータ処理の効率性を高める重要な役割を果たしています。
署名ハッシュ
トランザクションの署名ハッシュは keccak256
アルゴリズムを使用して計算され、これによりトランザクションの整合性と認証が保証されます。
トランザクションのバリデーション
トランザクションが有効とみなされるためには、以下の条件を満たす必要があります。
- EIP1559に基づく全プロパティ(特に指定がない限り)
-
codeAddr
にあるコードのサイズがEIP170の上限(24,576
バイト)以下 -
codeAddr
のコードサイズが0でない
EIP170については以下の記事を参考にしてください。
ガス計算
トランザクションの実行に必要なガスは、EIP1559から修正された計算式により決定されます。
具体的には、以下の要素に基づいてガスが計算されます。
- 固定のベースガス (
21000
) - 非ゼロの
calldata
バイトごとに16
ガス - ゼロの
calldata
バイトごとに4
ガス - アクセスリストのストレージキーごとに
1900
ガス - アクセスリストのアドレスごとに
2400
ガス - ストレージリストの長さごとに
20000
ガス
トランザクションの処理プロセス
-
コントラクトデプロイメント
- 送信者のアカウントのコードを
state[tx.codeAddr].code
に設定します。 - トランザクションの
storage
配列内の各タプルに基づき、送信者のストレージトライを更新します。
- 送信者のアカウントのコードを
-
トランザクション実行
-
EIP1559のルールに従って送信者のアカウントに対してEVMコールを実行し、トランザクションの起源を
keccak256(sender)[0..20]
に設定します。
-
EIP1559のルールに従って送信者のアカウントに対してEVMコールを実行し、トランザクションの起源を
この移行トランザクションタイプは、EOAからスマートコントラクトウォレットへの移行を大幅に簡略化し、効率化するためのものです。
これにより、Ethereumの利用がさらに広まり、ユーザーエクスペリエンスが向上することが期待されます。
補足
"No to address field"
このマイグレーショントランザクションは、特定のアドレスに対してではなく、送信者(sender)のアドレスにデプロイされるコントラクトを指しています。
つまり、送信者のアカウント自体がスマートコントラクトに変換されるため、「to
」アドレスフィールドは不要です。
このトランザクションは一回限りの使用を想定しており、移行後すぐにデプロイされたコントラクトを呼び出して、さらなる処理を行うことが可能です。
"Code pointer for deployment"
マイグレーショントランザクションでは、codeAddr
フィールドを使用してコードのポインターを指定します。
これは多くのユーザーが同一のコントラクト(多くの場合ウォレット)をデプロイしたい場合、コードの重複を避けるための最適化です。
直接コードをbytes
型でフィールドに持つのではなく、既に存在するコードへの参照を使うことで、データの重複とそれに伴うコストを削減します。
"Cheaper storage"
新しく設定されるスマートコントラクトのストレージは初期状態で空であるため、書き込み前に読み出しを行う必要がありません。
これにより、通常のコスト(22,100
ガス)から削減された20,000
ガス(EIP2200のSSTORE_SET_GAS
)のみが必要です。
読み出し操作が発生しないため、EIP2929のCOLD_SLOAD_COST
(2,100
ガス)を含まない形で計算されます。
EIP2929については以下の記事を参考にしてください。
"Intrinsic does not account for contract deployment"
このトランザクションタイプでは、コードのデプロイメントコストをカウントしません。
これは、クライアントが単一のユニークなコードコピーを保存し、デプロイメントの数にかかわらずそのコードへのポインターのみを変更するためです。
つまり、既存のコードへの参照を変更するだけなので、新たなコードをデプロイするコストは発生しません。
"Manipulating transaction origin"
多くのアプリケーションでは、呼び出し元がEOAであることを確認するためにcaller == origin
のチェックが行われます。
このトランザクションタイプでは、移行されるアカウントがスマートコントラクトとして機能するようになりますが、セキュリティチェックが正常に機能するようにトランザクションのオリジンを操作します。
"One-time migration"
技術的には、EOAがいつでもコードを変更できるようにすることは可能ですが、EIP3607により、既にコードがデプロイされているアカウントからの移行トランザクションは無効とされるため、この機能は制限されています。
これは、コントラクトのアップグレード可能性についての理解を簡単にするためでもあります。
EIP3607については以下の記事を参考にしてください。
このような設計は、EOAからスマートコントラクトウォレットへの移行を効率的かつ経済的に行うための革新的なアプローチを提供します。
セキュリティ
盲目的な署名(Blind Signing)
スマートコントラクトの設計が複雑になると、ユーザーが任意のメッセージに署名させられる危険性が増します。
具体的には、ユーザーが意図せずに悪意のあるアクターが所有する移行トランザクションに署名してしまうことが考えられます。
これを避けるために、ウォレットはこの種のトランザクションに対して十分な注意を払い、署名を完了する前にできるだけ多くの検証と摩擦を生じさせるべきです。
ecrecover
の使用
ecrecover
は、署名されたメッセージから署名者のアドレスを回復するEthereumの関数です。
ERC2612などのアプリケーション標準は、EOAアドレスとそれらの秘密鍵の暗号学的関係を利用しています。
ERC2612については以下の記事を参考にしてください。
多くのトークンがこの拡張機能をサポートしており、EOAが署名だけで資金の移動を承認できるようにしています。
このEIPにより、コントラクトアカウントでも秘密鍵が存在するようになるため、新たなセキュリティ上の検討が必要です。
特に、DeFiプロトコルがこのEIPを使用してコントラクトをデプロイし、後にERC2612メッセージに署名してコントラクトに蓄積された資金を盗む可能性があります。
この攻撃は、ウォレットがこの方法でデプロイされたプロトコルとのやり取りを許可しないことで回避可能です。
チェーン間の体験への影響
EOAの完全な移行は、すべてのチェーンで同時に行うことは実際的に不可能です。
ユーザーの秘密鍵は他のEVM互換チェーンで使用するために保持する必要があるため、アカウントが移行されたからといって秘密鍵を公開して安全であるというわけではありません。
この点をユーザーに教育することが重要です。
提案された解決策
ecrecover
に EXTCODEHASH
チェックを追加することが提案されています。
これにより、リカバリーされたアカウントにコードが存在する場合、プリコンパイルはrevert
されます。
これは、ERC2612のような標準を使用して移行されたEOAを無効にする効果があります。
引用
lightclient (@lightclient), Sam Wilson (@samwilsn), Ansgar Dietrichs (@adietrichs), "EIP-7377: Migration Transaction [DRAFT]," Ethereum Improvement Proposals, no. 7377, July 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7377.
最後に
今回は「EOAアカウントからコントラクトアカウントに複数の資産の移行の手間とコストを削減し、EOAからコントラクトウォレットへの移行を効率的に行う仕組みを提案しているEIP7377」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!