はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、CREATE2という新しいオペコードを導入し、コントラクトのデプロイ先アドレスを事前に予測可能にする仕組みを提案しているERC1014についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIPについてまとめています。

この提案の概要は以下を参考にしてください。

仕様

CREATE2 は、EVM(Ethereum Virtual Machine)における新しいオペコードで、0xf5 番に割り当てられています。 スタック引数として以下の4つを取ります。

  • endowment
    • 初期残高(送金するETHの量)
  • memory_start
    • メモリの開始位置(initコードの位置)
  • memory_length
    • メモリの長さ(initコードの長さ)
  • salt
    • 任意の32バイトの値(アドレスの決定に使われる)

CREATE2 の挙動は、既存の CREATE(0xf0)とほぼ同じですが、コントラクトのアドレス生成方法が異なります。

アドレスの計算には以下の式が使われます。

text
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code) )[12:]
  • 0xff は1バイトの固定値
  • address はコントラクトを生成するアドレス(20バイト)
  • salt はスタック上にある32バイトの値
  • init_code は新しいコントラクトの初期化コード(デプロイ時に実行されるコード)

このハッシュ値の最後の20バイトが、新しく生成されるコントラクトのアドレスとなります。 前処理データの長さは常に85バイトで固定されます。

また、ガス消費に関しては CREATE と同じですが、init_code に対する keccak256 のハッシュ処理のために追加で次のようなガスコストがかかります。

text
GSHA3WORD × ceil(len(init_code) / 32)

この追加コストは、メモリ拡張や CreateGas と同時に差し引かれます。 つまり、アドレスの評価や init_code の実行前に処理されます。

動機

CREATE2 の導入は、以下のようなユースケースを実現・支援するためです。

  • ステートチャネル(state channel)のように、オンチェーンにまだ存在していないコントラクトと確実にインタラクションする必要がある場合
  • コントラクトがまだデプロイされていない段階でも、将来そのコードがデプロイされたときにどのアドレスになるかを事前に確定できること

これにより、オフチェーン上での事前合意や、カウンターファクチュアル(仮想的)なインタラクションが可能になります。 実際にコードがデプロイされる前から、そのアドレスに対して安全に取引や署名ができるという特性は、Layer2やスマートウォレット、Meta-transaction などにおいて非常に有効です。

補足

アドレスの設計方針

CREATE2で使用されるアドレス生成方式は、以下の理由で設計されています。

アドレスの衝突防止

通常の keccak256(rlp([sender, nonce])) によるアドレス生成方式とは異なり、先頭に 0xff バイトを含めることで、アドレスの計算結果が従来方式と重複しないように設計されています。 0xff で始まるRLPエンコードは事実上現実的に生成不可能なサイズ(ペタバイト級)になるため、安全に区別できます。

ハッシュ対象の固定長化

ハッシュ前のデータ(preimage)は常に85バイトとなるよう設計されており、最適化やセキュリティに寄与します。

ガスコストに関する設計

CREATE2では、アドレス生成時に init_code に対して keccak256 ハッシュを計算するため、DoS(サービス拒否攻撃)を防ぐ目的で、コードサイズに応じた追加コストが課されます。

このコストは、SHA3(keccak256)オペコードと同じ「32バイトあたりのコスト(GSHA3WORD)」を適用し、メモリ拡張ガスと同様に処理の最初で差し引かれます。

説明

init_codeについての明確化

init_code とは、コントラクトをデプロイする際に最初に実行されるコードのことです。 このコードが出力するバイト列が、そのままコントラクトのランタイムコード(実行時コード)としてステートに保存されます。 Solidityなどの高級言語では、コンストラクタの処理に相当します。

アドレス衝突時の動作

CREATE2によって、同じアドレスへのコントラクト再生成が可能となるケースがありますが、EIP684により衝突時の仕様が明示されています。

EIP684については以下の記事を参考にしてください。

  • 対象アドレスに既にコードやノンスが存在している場合、CREATE2は即座に失敗します。
  • この失敗は、init_code の最初のバイトが無効なオペコードであるかのような動作になります。
  • これはEthereumの創世ブロック(genesis)から一貫して適用されます。

EIP161との関係

EIP161では、コントラクト生成時にアカウントのnonceが即座にインクリメントされます。 つまり、CREATEやCREATE2でコントラクトを作成した直後は、そのアドレスのnonceが非ゼロになるため、同一トランザクション内での再生成は常に失敗します。

さらに、SELFDESTRUCT(コントラクトの自己削除)を呼び出しても、nonceやコードがすぐにクリアされるわけではないため、同一トランザクション内での破壊と再生成は不可能です。

アドレス生成の具体例

以下の例では、異なる入力に対してCREATE2がどのようなアドレスを返すかが示されています。

  • Example 0

    text
    address: 0x000...000  
    salt:   0x000...000  
    init_code: 0x00  
    → 結果: 0x4D1A...BF38
  • Example 1

    text
    address: 0xdeadbeef...  
    salt:   0x000...000  
    init_code: 0x00  
    → 結果: 0xB928...FDA3
  • Example 2

    text
    address: 0xdeadbeef...  
    salt:   0x000...feed...  
    init_code: 0x00  
    → 結果: 0xD041...9833
  • Example 3

    text
    address: 0x000...000  
    salt:   0x000...000  
    init_code: 0xdeadbeef  
    → 結果: 0x70f2...cb5e
  • Example 4

    text
    address: 0x000...deadbeef  
    salt:   0x000...cafebabe  
    init_code: 0xdeadbeef  
    → 結果: 0x60f3...8AC7
  • Example 5

    text
    address: 0x000...deadbeef  
    salt:   0x000...cafebabe  
    init_code: 64バイト以上のdeadbeefの繰り返し  
    → 結果: 0x1d8b...854C
  • Example 6

    text
    address: 0x000...000  
    salt:   0x000...000  
    init_code: 空(0x)  
    → 結果: 0xE33C...d9e0

これらの例からも、同じinit_codeでも、saltやデプロイ元アドレスが異なると、アドレスも変化することが明確にわかります。 これは、CREATE2が意図的に衝突を避けつつ、事前にアドレスを確定できる設計であることを示しています。

引用

Vitalik Buterin (@vbuterin), "EIP-1014: Skinny CREATE2," Ethereum Improvement Proposals, no. 1014, April 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1014.

最後に

今回は「CREATE2という新しいオペコードを導入し、コントラクトのデプロイ先アドレスを事前に予測可能にする仕組みを提案しているERC1014」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!