スマートコントラクトのアップグレード可能性はどのように実現されますか?
友よ!その質問は非常に良いですね。スマートコントラクト開発を始めたばかりの多くの人が最も戸惑う点の一つです。例え話を使って、完全に理解できるようお手伝いしましょう。
核心的な矛盾点:ブロックチェーンの「不変性」
まず、ブロックチェーンの最大の特徴の一つが改ざん不可能であることです。一度スマートコントラクトがイーサリアムにデプロイされると、そのコードは石に刻まれたように、誰にも修正できません。これは利点(安全、信頼性)であると同時に、大きな欠点でもあります。
考えてみてください。もしコードにバグがあったり、将来的に製品に新機能を追加したくなったりしたら、どうしますか?古いコントラクトを放棄し、すべてのユーザーに新しいコントラクトへ移行してもらうのでしょうか?それはあまりにも手間がかかります。ユーザーの資産やデータはすべて古いコントラクトにあり、移行は困難かつ高価です。
そこで、コミュニティの識者たちはこの問題を解決するための素晴らしい方法を考案しました。それが**プロキシパターン(Proxy Pattern)**です。
核心となる考え方:アドレスとロジックの分離
「プロキシパターン」という言葉に怖がらないでください。その考え方は実は非常にシンプルで、身近な例を使って説明します。
あなたがネットショップを開いていると想像してください。あなたのウェブサイトのアドレスは
www.my-awesome-shop.com
です。すべての顧客はこのURLだけを認識しています。最初、このURLはあなたのサーバーAを指していました。サーバーAではあなたのネットショップのV1.0バージョンコードが実行されています。
その後、ネットショップをアップグレードして、タイムセール機能を追加したいと考え、V2.0バージョンを開発し、新しいサーバーBにデプロイしました。
このとき、すべての顧客に「新しいURLに変わりました!」と通知する必要はありません。 ドメイン管理画面で、
www.my-awesome-shop.com
のドメインの指し先をサーバーAからサーバーBに変更するだけで良いのです。顧客にとっては、アクセスするアドレスは常に変わらないURLですが、彼らが体験するのはすでに最新の機能です。
この例で言うと:
- 変わらないURL (
www.my-awesome-shop.com
) -> これがプロキシコントラクト (Proxy Contract) です。 - 交換可能なサーバー (サーバーA, サーバーB) -> これがロジックコントラクト (Logic/Implementation Contract) です。
スマートコントラクトのアップグレード可能性は、この考え方をブロックチェーン上に持ち込んだものです。
2つの主要な役割とそれらの連携
アップグレード可能なコントラクトのアーキテクチャでは、通常少なくとも2つのコントラクトをデプロイします。
-
プロキシコントラクト (Proxy)
- これはユーザーが実際にやり取りする入り口であり、そのアドレスは永久不変です。
- それ自体にはほとんどビジネスロジックがなく、非常にシンプルです。
- それはすべてのデータと状態を保存する役割を担います(例:ユーザーの残高、NFTの所有権など)。
- その最も重要な機能は、「伝言役」のように、受け取ったすべてのリクエスト(ユーザーが関数を呼び出すなど)を「ロジックコントラクト」に転送して処理させることです。
-
ロジックコントラクト (Implementation)
- ここには、私たちのプロジェクトのすべての実際のビジネスロジックコード(例:送金、NFTのミントなど)が含まれています。
- それはいかなる状態データも保存せず、「ステートレス」なツール役です。
- このコントラクトは置き換えることができます。V2、V3バージョンのロジックコントラクトをデプロイできます。
神秘的な delegatecall
プロキシコントラクトはどのようにしてリクエストをロジックコントラクトに転送するのでしょうか?それは delegatecall
と呼ばれる非常に特殊なオペコードを使用します。
delegatecall
の魔法のような点は次のとおりです。
プロキシコントラクトがロジックコントラクトのコードを「借りて」実行することを可能にしますが、コード実行のコンテキスト(
context
)は依然としてプロキシコントラクト自身の環境です。
簡単に言うと: プロキシコントラクトはロジックコントラクトにこう言います。「おい、お前の頭脳(ロジックコントラクトのコード)を使って、俺の家の机の上にある書類(プロキシコントラクトのデータと状態)を処理してくれ。」
このようにして、すべての状態変更(例えばユーザー残高の増減)は、ロジックコントラクトではなくプロキシコントラクトのストレージスペースで発生します。そのため、将来ロジックコントラクトを置き換えたとしても(より賢い「頭脳」に交換したとしても)、データはプロキシコントラクトという「家」の中に完全に保存されたままになります。
完全なアップグレードプロセスはどのようなものですか?
-
初回デプロイ
- ロジックコントラクトV1 (
Logic_V1
) をデプロイします。 - プロキシコントラクト (
Proxy
) をデプロイし、デプロイ時にロジックコントラクトのアドレスがLogic_V1
のアドレスであることを伝えます。
- ロジックコントラクトV1 (
-
日常的な使用
- すべてのユーザーは
Proxy
コントラクトのアドレスのみとやり取りします。 Proxy
はリクエストを受け取ると、delegatecall
を通じてLogic_V1
のコードを実行させ、すべてのデータはProxy
に保存されます。
- すべてのユーザーは
-
アップグレードの開始
- バグが見つかった、または新機能を追加したい場合、新しいロジックコントラクトV2 (
Logic_V2
) を開発しデプロイします。 - コントラクトの管理者として、
Proxy
コントラクトの特別な管理関数(例えばupgradeTo()
と呼ばれるもの)を呼び出します。 Proxy
コントラクトに「今から、あなたの新しいロジックコントラクトのアドレスはLogic_V2
のアドレスです」と伝えます。
- バグが見つかった、または新機能を追加したい場合、新しいロジックコントラクトV2 (
-
アップグレードの完了
Proxy
コントラクト内部に記録されているロジックコントラクトのアドレスがLogic_V1
からLogic_V2
に更新されます。- ユーザーは引き続き同じ
Proxy
アドレスとやり取りしますが、今度はProxy
がリクエストをLogic_V2
に転送して実行するようになります。 - このプロセス全体はユーザーには意識されず、彼らが使用するコントラクトアドレスは一切変わっていませんが、コントラクトの機能は一新されています!
まとめ
特性 | 例え | 役割 |
---|---|---|
永続的なアドレス & データ保存 | ウェブサイトのドメイン / あなたの家の番地 | プロキシコントラクト (Proxy) |
変更可能なビジネスロジック | ウェブサイトの裏側のサーバー / あなたの家の内装スタイル | ロジックコントラクト (Implementation) |
両者をつなぐ魔法 | ドメイン解決 / 「お前の頭脳で俺の家の仕事をしろ」 | delegatecall |
これがスマートコントラクトがアップグレード可能性を実現する核心的な秘密です。不変のアドレス/データと変更可能なロジックを分離することで、コントラクトの入り口を変えたり、データを移行したりすることなく、コントラクト機能の修正とイテレーションを実現できます。現在、最も主流な実装標準はOpenZeppelinが提唱するUUPSとTransparent Proxy Patternです。
この説明がお役に立てば幸いです!