はじめに

初めまして。 CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です! スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

代表的なゲームはクリプトスペルズというブロックチェーンゲームです。

今回は、すでに存在するコントラクトアドレスと同じアドレスのコントラクトのデプロイを防ぐ仕組みを提案している規格であるERC684についてまとめていきます!

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

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

概要

このEIP(イーサリアム改善提案)は、イーサリアムのブロックチェーンにおいて、すでに何かしらのコードが存在するアドレスで新たなコントラクトを作成しようとすると、エラーを発生させるものです。 この提案の目的は、特定のアドレスにコントラクトをデプロイし、その後そのアドレスに新しいコントラクトを「作成する」ことで、元のコードを不正に変更する攻撃を防ぐことにあります。

イーサリアムでは、コントラクトは特定のアドレスに紐づいており、そのアドレスにはコントラクトのコードが保存されています。 しかし、これまでは、すでにコードが存在するアドレスに新しいコントラクトを「作成」することで、既存のコードを上書きし、変更することが可能でした。 このEIPにより、既にコードが存在するアドレスで新しいコントラクトを作成しようとするとエラーが発生し、このような不正なコードの変更を防ぐことができます。 これにより、イーサリアムのセキュリティが強化されます。

「コードの上書き = コントラクトのアップデート」と考えることもできます。 コントラクトは通常アップデートできないものなのでこの変更は必要なものです。 ただ、コントラクトを様々な理由からアップデートしたい場面があると思います。 その時に役立つ仕組みが「アップグレーダブルなコントラクト」です。 詳しくは以下の記事にまとめています。

仕様

コントラクトの作成については、作成トランザクションやCREATE、CREATE2などのオペコード、それ以外の方法により行われた場合でも、生成されたアドレスが非ゼロのノンス(一意の識別子)や非ゼロのコード長を持っている場合は、エラーを発生させる必要があります。

生成されたアドレスのノンスとコード長

スマートコントラクトは、ブロックチェーン上の特定のアドレスにデプロイされます。 このアドレスには「ノンス」と呼ばれる一意の識別子があり、それが非ゼロ(すなわち、そのアドレスで以前に何らかのアクティビティがあったことを示す)である場合、または既に実行可能なコードが存在する場合(コード長が非ゼロ)、新しいコントラクトの作成はエラーを引き起こすべきです。

エラーの発生

もしCREATEやCREATE2などのオペコードを使用してコントラクトの作成を試み、上記の条件(非ゼロのノンスまたはコード長)に該当する場合、システムはコントラクト作成を拒否し、エラーを返すべきです。 これは、ブロックチェーン上での不正行為やセキュリティ問題を防ぐための重要な措置です。

イーサリアムでは、既に使用されているか、何らかのコードが存在するアドレスに新しいコントラクトを作成しようとするとエラーが発生します。 これにより、同じアドレスに複数のコントラクトが存在したり、既存のコントラクトが不正に上書きされたりするのを防ぐことができます

CREATEとCREATE2は、イーサリアムのスマートコントラクトにおいて、新しいコントラクトをブロックチェーン上に作成するために使用されるオペコード(操作コード)です。 これらは、コントラクトの作成方法を定義していますが、それぞれ異なる特性を持っています。

CREATE

CREATEは、イーサリアムの最初のバージョンから存在するオペコードです。 このオペコードは、新しいコントラクトを生成する時に使用されます。 CREATEを使用して生成されるコントラクトのアドレスは、作成元のコントラクトのアドレスと、作成元コントラクトのトランザクション数(ノンス)に基づいて計算されます。 CREATEは、コントラクトの作成時に初期化コードを実行し、その結果得られたバイトコードを新しいコントラクトアドレスに関連付けます。

CREATEの計算例

CREATEは、コントラクトのアドレスを生成する際に、以下の要素を使用します。

  • 作成者コントラクトのアドレス
    • コントラクトを作成するコントラクトのアドレス。
  • ノンス
    • 作成者コントラクトがこれまでに発行したトランザクションの数。

アドレスは次のように計算されます。

javascript
address = keccak256(作成者アドレス + ノンス)

ここでkeccak256は、イーサリアムで使われるハッシュ関数です。

例えば、作成者コントラクトのアドレスが0x1234...で、ノンスが3の場合、計算は次のようになります。

javascript
address = keccak256(0x1234... + 3)

CREATE2

CREATE2は、イーサリアムの後期バージョンで導入されたオペコードで、より複雑な機能を提供します。 CREATE2も新しいコントラクトを生成するために使用されますが、生成されるコントラクトアドレスの計算方法が異なります。 このオペコードでは、コントラクトアドレスは、作成元のコントラクトアドレス、初期化コード、および追加のデータ(ソルトと呼ばれる)に基づいて計算されます。 CREATE2の利点は、生成されるコントラクトアドレスを事前に予測できる点にあります。 これにより、より高度なプログラミングパターンが可能となります。

CREATE2の計算例

CREATE2では、以下の要素が使用されます。

  • 作成者コントラクトのアドレス
  • ソルト
    • ユーザーが指定する任意の32バイトデータ。
  • 初期化コードのハッシュ値
    • コントラクトの初期化コードをハッシュ化したもの。

アドレスは次のように計算されます。

javascript
address = keccak256(0xff + 作成者アドレス + ソルト + keccak256(初期化コード)) の最後の20バイト

ここでもkeccak256は、イーサリアムのハッシュ関数です。

例えば、作成者コントラクトのアドレスが0x1234...、ソルトが0xabcd...、初期化コードのハッシュが0x5678... の場合、計算は次のようになります。

text
address = keccak256(0xff + 0x1234... + 0xabcd... + keccak256(0x5678...)) の最後の20バイト

まとめ

  • CREATEとCREATE2はどちらもコントラクトを生成するためのオペコードですが、アドレスの計算方法と使用するシナリオが異なります。
  • CREATEはよりシンプルで基本的なコントラクト作成を行い、CREATE2はより予測可能で複雑なコントラクト作成が可能です。
  • CREATE2の導入により、開発者はより制御された方法でコントラクトをデプロイし、アプリケーションの設計に柔軟性を持たせることができます。

具体的には、そのアドレスでコントラクトを作成しようとした時に、初期化コードの最初のバイトが無効なオペコードであるかのようにエラーを投げる必要があります。 この規則は、過去に作成されたすべてのブロックに対しても遡及的に適用されるべきです。

イーサリアムのブロックチェーン上で新しいコントラクトを作成しようとした時、そのアドレスがすでに何かしらのデータ(ノンスやコード)を持っている場合、その作成は許されず、エラーが発生します。 これは、イーサリアム上で不正なコントラクトの作成を防ぎ、安全性を確保するための重要な規則です。

補足

スマートコントラクトの重要な特徴の一つは、一度ブロックチェーンにデプロイされた後、そのコードは変更されないということです。 これにより、コントラクトの動作が予測可能で安全であると考えられています。 それに加え、もし攻撃者が非常に高い計算能力を持っている場合、彼らはブロックチェーン上の特定のアドレスにあるコントラクトのコードを別のコードに変えることができる可能性があります。 このような変更が行われると、攻撃者はそのコントラクトを悪用して資金を盗んだり、他の不正な行為を行うことが可能になります。

スマートコントラクトは本来変更できないはずのコードが、高い計算力を持つ攻撃者によって変更されるリスクがあります。 このようにコードが変更されると、コントラクトが不正な方法で利用され、ブロックチェーンの安全性が損なわれる恐れがあります。 これは、スマートコントラクトのセキュリティにとって大きな課題です。

後方互換性

これは実行レイヤーのアップグレードなので、ハードフォークが必要です。

テスト

指定されたジェネシス(初期値)割り当てに基づいて説明します。

text
Address : 0xd0bBEc6D2c628b7e2E6D5556daA14a5181b604C5,
Balance : 1000000000000000000, // 1 ether
Nonce   : 0,
code    : "",

Address : 0x7658771dc6Af74a3d2F8499D349FF9c1a0DF8826,
Balance : 0,
Nonce   : 1,
Code    : "0xB0B0FACE",

この状況では、最初のトランザクションで外部所有アカウント(EOA)から、アドレス 0xd0bBEc6...によってコントラクトが作成されます。 このトランザクションのハッシュは 227bcc6959669226360814723ed739f1214201584b6a27409dfb8228b8be5f59です。 ここで重要なのは、このコントラクト作成時に「ソルト」(追加データ)が使用されないという点です。

このシナリオでは、コントラクトの作成は失敗し、取り消されるべきです。 これは、イーサリアムのルールに基づき、既存のアドレスに新たなコントラクトを作成しようとするとエラーが発生するためです。 特に、既存のアドレスが非ゼロのノンスまたは非ゼロのコード長を持っている場合には、このようなエラーが発生します。 上記の例では、アドレス0x7658771dc6Af74a3d2F8499D349FF9c1a0DF8826がノンス1を持っているため、新しいコントラクトの作成は許されず、エラーが発生し、トランザクションは取り消されます。

セキュリティ考慮事項

このEIP(イーサリアム改善提案)は、セキュリティの強化を目的としたアップグレードです。 具体的には、デプロイされたコントラクトコードの不変性を強制する内容となっています。

この改善提案により、一度イーサリアムのブロックチェーン上にデプロイされたコントラクトのコードは、変更することができなくなります。 これは、ブロックチェーンの基本原則である「不変性」をより厳密に守るための措置です。 コントラクトのコードが変更されると、セキュリティリスクが高まるため、この改善提案はイーサリアムの全体的な安全性を向上させることに寄与します。

引用

Vitalik Buterin (@vbuterin), Renan Rodrigues de Souza (@RenanSouza2), "EIP-684: Revert creation in case of collision," Ethereum Improvement Proposals, no. 684, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-684.

最後に

今回は「すでに存在するコントラクトアドレスと同じアドレスのコントラクトのデプロイを防ぐ仕組みを提案している規格であるERC684」についてまとめてきました! いかがだったでしょうか?

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

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