第2回 SolidityのUpgradeabilityとOpenZeppelinSDKとは

第2回 SolidityのUpgradeabilityとOpenZeppelinSDKとは

2.スマートコントラクトのアップグレードついて

はじめに


本連載では、スマートコントラクトのUpgradeabilityに焦点を当てています。スマートコントラクトは、普通のアプリケーションとは違い、一度デプロイしたコントラクトのコードは修正できないという不変性を持っています。この不変性を特殊な方法を用いて、回避することで、Developer Experienceの向上を図ることができる、「Upgradeability」のコンセプトをわかりやすく解説するのが本連載の目的です。

今回は、「2.スマートコントラクトのアップグレードついて」です。Proxy Contractのより細かい3つのデザインパターンとアップグレードを行える2つツールについて紹介していきます。

関連する記事


第1回 SolidityのUpgradeabilityとOpenZeppelinSDKとは
第3回 SolidityのUpgradeabilityとOpenZeppelinSDKとは
第4回 SolidityのUpgradeabilityとOpenZeppelinSDKとは

三つのアップグレードパターン


Proxy Contractの実装には以下の有力なパターンが存在します。OpenZeppelinSDKではUnstructured Storageが採用されており、一番有力なパターンであると言えるでしょう。
  1. Inherited Storage
  2. Eternal Storage
  3. Unstructured Storage

1.Inherited Storage Pattern



出典 : proxy pattern
Proxy Patterns

UpgradeabilityProxyコントラクトとLogic Contractが同じUpgradeabilityStorageコントラクトを継承しています。UpgradeabilityStorageコントラクトは、共通の状態(slot)を2つのコントラクトに提供します。このコントラクトは、主にProxy Contractのadminアドレス(Proxy Contractの関数の実行権限を唯一持つアドレス)とLogic Contractのアドレスを保存することになります。これによりLogic Contract内で定義されるslotとStorage Contractで定義が必要だったslotの衝突を回避することができます。以下より具体的な実装を確認することが可能です。

upgradeability_using_inherited_storage
https://github.com/OpenZeppelin/openzeppelin-labs/tree/master/upgradeability_using_inherited_storage

2.Eternal Storage Pattern


出典 : proxy pattern
Proxy Patterns

このパターンで大事なのは、まずEternalStorageコントラクトです。このコントラクトではLogicに必要な全ての変数タイプをmappingを利用して事前に定義しています。mappingによって定義された変数を利用するためには、Logic Contract側でsetter関数とgetter関数を用意する必要があります。UpgradeablityStorageコントラクトには、Logic Contractのアドレスが、UpgradeabilityOwnerStorageコントラクトには、EternalStorageProxyコントラクトのadminアドレスを保存する変数が定義されています。この3つのStorage Contractを継承することでEternalStorageProxyコントラクト(Storage Contract)はslotを衝突させずにすみます。名前の通り(直訳すると永久ストレージ)このパターンでは、状態変数を変更することはできず、EternalStorageコントラクトに脆弱性があった場合、アップグレードを行うことはできません。

実装は以下より確認することが可能です。

upgradeability_using_eternal_storage
https://github.com/OpenZeppelin/openzeppelin-labs/tree/master/upgradeability_using_eternal_storage

3.Unstructured Storage Pattern


このパターンではストレージの衝突の回避します。

出典 : OpenZeppelin SDK Upgrades Pattern
https://docs.openzeppelin.com/sdk/2.5/pattern#transparent-proxies-and-function-clashes

ストレージの衝突とは上記のように、まず利用者がProxy Contractからdelegatecallを介して、Logic Contractの関数を利用した時に、Proxy Contract(上記の図ではProxyの列) のslot 1の部分に格納されている「address _implementation」が、Logic Contract(上記の図ではImplementationの列)のslot 1 の部分に格納されている「address _owner」と重複していることによって起こる問題です。利用者が呼び出した関数の処理が「address _owner」を利用することを意図していても、実際には、Storage Contractの役目を担っているProxy Contractの「address _implementation」を使ってしまうからです。

出典 : OpenZeppelin SDK Upgrades Pattern
https://docs.openzeppelin.com/sdk/2.5/pattern#transparent-proxies-and-function-clashes

そこで、Proxy Contractが保持する状態のslotの場所をランダムに決めることで、Logic Contractの状態との衝突を回避します。これがUnstructured Storage Pattern(非構造化ストレージパターン)です。1つのコントラクトが持つslotの数は、2の256乗個あるため、ランダムに決めても衝突は起きません。

実装例
bytes32 private constant implementationPosition = keccak256("org.zeppelinos.proxy.implementation");

function setImplementation(address newImplementation) internal {
  bytes32 position = implementationPosition;
    assembly {
      sstore(position, newImplementation)
    }
}   

まずメモリ位置をハッシュ関数を使ってランダムに決めます。変数implementationPositionはconstantを使っているため、slotを使用しません。assembly内で、sstoreを利用してLogic Contractをランダムなメモリ位置(positionで指定している)に保存します。


出典 : proxy pattern
Proxy Patterns

このパターンでは、UpgradeablityProxyコントラクトにLogic Contractのアドレスを格納する変数が、OwnedUpgradeablityStorageコントラクトにOwnedUpgradeabilityコントラクトのadminアドレスを格納する変数がそれぞれ定義されています。この2つのコントラクトを継承するOwnedUpgradeablityProxyコントラクトは2つのslotをランダムな場所(2の256乗個のうちから)で、保持しています。これによりLogic Contractに安全に新規の状態変数を追加することができます。

upgradeability_using_unstructured_storage
https://github.com/OpenZeppelin/openzeppelin-labs/tree/master/upgradeability_using_unstructured_storage

OpenZeppelin SDK Upgrades Pattern
https://docs.openzeppelin.com/sdk/2.5/pattern#transparent-proxies-and-function-clashes

関連するEIPの紹介


現在3つのUpgradeabilityに関するEIPが提案されていてどれもdraft状態です。

EIP 897: ERC DelegateProxy
Proxy Contractの基本メソッドのインターフェースの標準化を目指しています。

EIP 1822: Universal Upgradeable Proxy Standard (UUPS)
Proxy Contractの具体的な実装の標準化を目指しています。

EIP 1967: Standard Proxy Storage Slots
unstructured proxy patternに関する実装方法の標準化を目指しています。

アップグレードツールの紹介


アップグレーダブルなコントラクトの設計は、高度なSolidityやEVMの知識を必要とするため、簡単には行えません。そこでコントラクトのアップグレードをサポートしてくれるツールを以下で簡単に紹介します。

OpenZeppelinSDKとは


OpenZeppelinSDKは、OpenZeppelinが提供するSmart Contract開発ツールです。Truffleを利用せずにSmart Contractのcompile、upgrade、deployが簡単に行えます。またCLIが充実しており、関数の実行も簡単に行えます。またアップグレード可能なコントラクトのパッケージであるopenzeppelin-contracts-ethereum-packageを利用することで、簡単にアップグレーダブルなコントラクトを作成できます。本連載の次回より使い方を扱っていきます。

OpenZeppelin SDK
https://openzeppelin.com/sdk/

OpenZeppelin SDK document v2.5
https://docs.openzeppelin.com/sdk/2.5/

AragonOSとは


AragonOSは、DAO、DApps、プロトコルを構築するためのSmart Contractのフレームワークです。OSである理由は、アプリやユーザーがDAOやプロトコルのリソースにアクセスする権限を管理するからです。アップグレードが可能な分散型アプリケーションとプロトコルを作成することが可能です。

Aragon ホームページ
https://aragon.org/discover/

Aragon Developer Portal
https://hack.aragon.org/

Aragon OS
https://hack.aragon.org/docs/aragonos-intro.html

まとめ


『第2回 UpgradeabilityとOpenZeppelinSDKとは』では、3つのアップグレードパターンを掘り下げて解説し、アップグレードを簡単に行うことが可能になる2つのツールについて、紹介しました。次回は、「3.openzeppelinSDKの基本」です。コントラクトのアップグレードツールであるopenzeppelinSDKを利用していくための、環境構築・利用の仕方・注意点について解説していきます。
     

免責事項

本記事に掲載されている記事の内容につきましては、正しい情報を提供することに務めてはおりますが、提供している記事の内容及び参考資料からいかなる損失や損害などの被害が発生したとしても、弊社では責任を負いかねます。実施される際には、法律事務所にご相談ください。

技術・サービス・実装方法等のレビュー、その他解説・分析・意見につきましてはblock-chani.jp運営者の個人的見解です。正確性・正当性を保証するものではありません。本記事掲載の記事内容のご利用は読者様個人の判断により自己責任でお願いいたします。

     

コンセンサス・ベイス(株)とブロックチェーン事業を行なってみませんか?

当サイトを運営するコンセンサス・ベイス株式会社は、2015年設立の国内で最も古いブロックチェーン専門企業です。これまでに、大手企業の顧客を中心に、日本トップクラスのブロックチェーンの開発・コンサルティング実績があります。

ブロックチェーンに関わるビジネスコンサル・システム開発・教育・講演などご希望でしたら、お気軽にお問い合わせください。

     
     

ブロックチェーン学習に最適の書籍の紹介

図解即戦力 ブロックチェーンのしくみと開発がこれ1冊でしっかりわかる教科書

ブロックチェーン イーサリアムへの入り口 第二版 (ブロックチェーン技術書籍)

本書は、ブロックチェーン技術に興味を持ったエンジニアや、その仕組みを学び、自分の仕事に活かしたいビジネスパーソンを対象にして、ブロックチェーンのコア技術とネットワーク維持の仕組みを平易な言葉で解説しています。この本を読んだうえで、実際にコードを書くような専門書、ブロックチェーンビジネスの解説書を読むことで、理解度が飛躍的に高まるでしょう。(はじめにより)

イーサリアム(Ethereum)カテゴリの最新記事