ダイヤモンド代理店契約のセキュリティのベストプラクティス

プロキシ コントラクトは、スマート コントラクト開発者にとって重要なツールです。現在、契約システムには多くのプロキシ モードとそれに対応する使用ルールがあります。以前に、アップグレード可能なプロキシ契約のセキュリティのベスト プラクティスについて概説しました。

この記事では、開発者コミュニティで人気のある別のプロキシ モデル、ダイヤモンド プロキシ モデルを紹介します。

「ダイヤモンド」としても知られるダイヤモンド プロキシ コントラクトは、イーサリアム改善提案 (EIP) 2535 によって導入されたイーサリアム スマート コントラクトの設計パターンです。

ダイヤモンド モードでは、コントラクトの機能をより小さなコントラクト (「アスペクト」とも呼ばれます) に分割することで、コントラクトに無制限の機能を持たせることができます。 Diamond はプロキシとして機能し、関数呼び出しを適切なアスペクトにルーティングします。

ダイヤモンドモデルの設計により、イーサリアムネットワークの最大契約サイズ制限の問題を解決できます。ダイヤモンド パターンにより、大規模なコントラクトを小さな側面に分割することで、開発者はサイズの制約に影響されることなく、より複雑で機能豊富なスマート コントラクトを構築できます。

Diamond Brokerage は、従来のアップグレード可能な契約と比較して、非常に高い柔軟性を提供します。これらにより、他の部分に触れることなく、コントラクト部分をアップグレードし、機能の選択した部分を追加、置換、または削除できます。

この記事では、広く使用されている透過プロキシ モードおよび UUPS プロキシ モードとの比較を含む EIP-2535 の概要と、開発者コミュニティ向けのセキュリティ上の考慮事項について説明します。

EIP-2535 のコンテキストでは、「ダイヤモンド」はプロキシ コントラクトであり、その機能実装は「アスペクト」と呼ばれるさまざまな論理コントラクトによって提供されます。

本物のダイヤモンドにはファセットと呼ばれるさまざまな側面があり、対応するイーサリアム ダイヤモンド コントラクトにもさまざまなファセットがあると想像してください。ダイヤモンド借入機能の各契約は、異なる側面または側面を持っています。

ダイヤモンド規格は、「ダイヤモンド カット」の機能を拡張するためのアナロジーを使用して、ファセットやフィーチャーを追加、置換、または削除します。

さらに、Diamond Standard は、ダイヤモンドのファセットと存在に関する情報を返す「ダイヤモンド ルーペ」と呼ばれる機能を提供します。

従来の代理モデルと比較すると、「ダイヤモンド」が代理契約に相当し、異なる「側面」が契約の実現に対応します。ダイヤモンド エージェントのさまざまな側面は、内部関数、ライブラリ、状態変数を共有できます。ダイヤモンドの主な成分は次のとおりです。

プロキシとして機能し、関数呼び出しを適切なアスペクトにルーティングする中央コントラクト。これには、「アスペクト」アドレスへの関数セレクターのマッピングが含まれています。

特定の機能を実装する単一のコントラクト。各ファセットには、ダイヤモンドによって呼び出すことができる一連の関数が含まれています。

は、EIP-2535 で定義されている標準関数のセットで、ダイヤモンドで使用されるファセットおよび関数セレクターに関する情報を提供します。ダイヤモンド ルーペを使用すると、開発者とユーザーはダイヤモンドの構造を検査して理解することができます。

ダイヤモンドのファセットを追加、置換、または削除する関数と、それに対応するフィーチャ セレクター。許可された住所 (ダイヤモンドの所有者または複数署名の契約書など) のみがダイヤモンドのカットを実行できます。

従来のエージェントと同様に、ダイヤモンド エージェントで関数呼び出しが行われると、エージェントのフォールバック関数 (フォールバック関数) がトリガーされます。ダイヤモンド プロキシとの主な違いは、フォールバック関数に selectorToFacet マッピングがあり、どの論理コントラクト アドレスに呼び出された関数が実装されているかを保存および決定することです。次に、従来のプロキシと同様に、デリゲートコールを使用して関数を実行します。

すべてのプロキシは、fallback() 関数を使用して関数呼び出しを外部アドレスに委任します。以下は、ダイヤモンド プロキシの実装と従来のプロキシの実装です。

これらのアセンブリ コード ブロックは非常に似ているため、唯一の違いはダイヤモンド プロキシ デリゲート呼び出しのアスペクト アドレスと従来のプロキシ デリゲート呼び出しの impl アドレスであることに注意してください。

主な違いは、ダイヤモンド プロキシではアスペクトのアドレスが呼び出し元の msg.sig (関数セレクター) からアスペクトのアドレスまでのハッシュマップによって決定されるのに対し、従来のプロキシでは impl アドレスが依存しないことです。発信者が入力します。

ダイヤモンドエージェントフォールバック機能

従来のプロキシフォールバック機能

SelectorToFacet マッピングによって、どのコントラクトに各関数セレクターの実装が含まれるかが決まります。プロジェクト作業者は、多くの場合、この関数セレクターと実装コントラクトのマッピングを追加、置換、または削除する必要があります。 EIP-2535 では、次のように規定されています。この目的を達成するには、diamondCut() 関数が必要です。以下はインターフェイスの例です。

各 FacetCut 構造には、ダイヤモンド プロキシ コントラクトで更新されるファセット アドレスと 4 バイトの特徴セレクター配列が含まれています。 FaceCutAction を使用すると、機能セレクターを追加、置換、削除できます。 DiamondCut() 関数の実装には、適切なアクセス制御、スロット衝突の防止、障害時の回復などが含まれている必要があります。

ダイヤモンドエージェントがどのような機能や側面を持っているかを調べるために、「ダイヤモンドルーペ」を使用します。 「ダイヤモンド ルーペ」は、EIP-2535 で定義されている次のインターフェイスを実装する特別なアスペクトです。

facets() 関数は、すべてのファセットのアドレスとその 4 バイトの関数セレクターを返す必要があります。 facetFunctionSelectors() 関数は、特定のアスペクトでサポートされているすべての関数セレクターを返す必要があります。 facetAddresses() 関数は、ダイヤモンドで使用されるすべてのファセット アドレスを返す必要があります。

facetAddress() 関数は、指定されたセレクターをサポートするアスペクトを返す必要があります。見つからない場合は address(0) を返します。同じ機能セレクターを持つ複数のアスペクト アドレスがあってはいけないことに注意してください。

ダイヤモンド プロキシがさまざまな関数呼び出しをさまざまな実装コントラクトに委任することを考えると、競合を防ぐためにストレージ スロットを適切に管理することが重要です。 EIP-2535 では、いくつかのストレージ スロット管理方法について言及しています。

このアスペクトでは、構造体内で状態変数を宣言できます。この側面では、それぞれが異なる保管場所を持つ任意の数の構造を使用できます。各構造には、契約保管場所内の特定の場所があります。アスペクトは独自の状態変数を宣言できますが、他のアスペクトによって宣言された状態変数の格納場所と競合することはできません。次の図に示すように、サンプル ライブラリとダイヤモンド ストレージ コントラクトが EIP-2535 で提供されます。

アプリ ストレージは、ダイヤモンド ストレージのより特殊なバージョンです。このパターンは、アスペクトの状態変数をより便利かつ簡単に共有するために使用されます。 App Store の構造は、アプリケーションに必要な任意の数とタイプの状態変数を含むように定義されます。アスペクトは常に、ストレージ スロットの位置 0 で、最初で唯一の状態変数として AppStorage 構造体を宣言します。その後、さまざまなアスペクトがこの構造体の変数にアクセスできるようになります。

Diamond Storage と AppStorage のハイブリッドなど、他のストレージ スロット管理戦略もあります。たとえば、一部の構造は異なるアスペクト間で共有され、一部の構造は特定のアスペクトに固有です。いずれの場合も、偶発的なスロットの衝突を防ぐことが非常に重要です。

透過プロキシおよび UUPS プロキシとの比較

Web3 開発者コミュニティによって現在使用されている 2 つの主なプロキシ モードは、透過プロキシ モードと UUPS プロキシ モードです。このセクションでは、ダイヤモンド プロキシ モードとトランスペアレント プロキシ モードおよび UUPS プロキシ モードを簡単に比較します。

1.EPI-2535:

2.EPI-1967:

3.Diamond プロキシのリファレンス実装:

4.OpenZeppelin 実装:

プロキシおよびスケーラブルなソリューションはより複雑なシステムであり、OpenZeppelin は、UUPS、透過的およびビーコンのスケーラブル プロキシのコード ベースと包括的なドキュメントを提供します。ただし、ダイヤモンド プロキシ モードについては、OpenZeppelin はその利点を認めましたが、ライブラリに EIP-2535 ダイヤモンド実装を含めないことを決定しました。

したがって、既存のサードパーティ ライブラリを使用する開発者、またはこのソリューションを自分で実装する開発者は、細心の注意を払って実装する必要があります。ここでは、開発者コミュニティが考慮すべきセキュリティのベスト プラクティスのチェックリストをまとめました。

コントラクト ロジックをより小さく管理しやすいモジュールに分割することで、開発者はコードのテストと監査をより簡単に行うことができます。

さらに、このアプローチにより、開発者は複雑でモノリシックなコード ベースを管理するのではなく、コントラクトの構築と維持の特定の側面に集中できるようになります。最終的には、コントラクトの他の部分に影響を与えることなく、簡単に更新および変更できる、より柔軟でモジュール化されたコード ベースが得られます。

出典: Aavegotchi Github

ダイヤモンド プロキシ コントラクトをデプロイするときは、DiamondCutFacet コントラクトのアドレスをダイヤモンド プロキシ コントラクトに追加し、diamondCut() 関数を実装する必要があります。 DiamondCut() 関数は、ファセットと関数を追加、削除、または置換するために使用されます。DiamondCutFacet と DiamondCut() がないと、ダイヤモンド エージェントは適切に動作できません。

出典: ムゲンのダイヤモンド-3-ヘルメット

スマート コントラクトのストレージ構造に新しい状態変数を追加する場合は、構造の最後に追加する必要があります。新しい状態変数を構造体の先頭または途中に追加すると、新しい状態変数によって既存の状態変数データが上書きされ、新しい状態変数の後の状態変数が間違ったメモリ位置を参照する可能性があります。

AppStorage パターンでは、ダイヤモンド プロキシに対して 1 つの構造を宣言し、この構造をすべての側面で共有する必要があります。複数の構造が必要な場合は、DiamondStorage パターンを使用する必要があります。

内部構造体にさらに状態変数を追加するつもりがない場合を除き、構造体を別の構造体内に直接配置しないでください。構造体の後に宣言された変数ストレージ スロットを上書きせずに、アップグレードで内部構造体に新しい状態変数を追加することはできません。

回避策は、「構造体」を「構造体」に直接配置するのではなく、メモリマップされた構造体に新しい状態変数を追加することです。マップ内の変数ストレージ スロットは別の方法で計算され、ストレージ内で連続していません。

配列のサイズは構造体のサイズに影響されます。新しい状態変数が構造に追加されると、その構造のサイズとレイアウトが変更されます。

これにより、構造体が配列内の要素として使用される場合に問題が発生する可能性があります。構造体のサイズとレイアウトが変更されると、配列のサイズとレイアウトも変更されるため、構造体のサイズとレイアウトの一貫性に依存するインデックス付けやその他の操作で問題が発生する可能性があります。

他のプロキシ パターンと同様に、各変数には一意のストレージ スロットが必要です。そうしないと、同じ場所にある 2 つの異なる構造が互いに上書きされてしまいます。

通常、initialize() 関数は、特権ロールのアドレスなどの重要な変数を設定するために使用されます。コントラクトのデプロイ時に初期化されていない場合、悪意のある攻撃者がコントラクトを呼び出して制御する可能性があります。

初期化/設定関数に適切なアクセス制御を追加するか、コントラクトのデプロイ時に関数が呼び出され、再度呼び出すことができないようにすることをお勧めします。

コントラクトのいずれかの側面で selfdestruct() 関数を呼び出すことができる場合、コントラクト全体が破壊され、資金やデータが失われる可能性があります。ダイヤモンド プロキシ モードでは、複数の側面がプロキシ コントラクトのストレージとデータにアクセスできるため、これは非常に危険です。

現在、スマートコントラクトにダイヤモンドプロキシモデルを採用するプロジェクトがますます増えています。従来のプロキシに比べて柔軟性やその他の利点が得られます。

ただし、柔軟性が高まるということは、攻撃者にとって攻撃対象領域が広がることも意味します。この記事が、開発者コミュニティがダイヤモンド プロキシ モデルの仕組みとそのセキュリティに関する考慮事項を理解するのに役立つことを願っています。

同時に、プロジェクト チームは、ダイヤモンド代理店契約の履行に関連する脆弱性のリスクを軽減するために、厳格なテストと第三者監査を実施する必要があります。

原文表示
内容は参考用であり、勧誘やオファーではありません。 投資、税務、または法律に関するアドバイスは提供されません。 リスク開示の詳細については、免責事項 を参照してください。
  • 報酬
  • コメント
  • 共有
コメント
0/400
コメントなし
  • ピン
いつでもどこでも暗号資産取引
qrCode
スキャンしてGate.ioアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • ไทย
  • Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)