スマートコントラクトのアドレスを変えずにアプデしたい時の話です。
取り扱う話題・取り扱わない話題
今回はProxy全般に関わる一般論を扱い、具体的なProxy Patternについては深く扱いません。
(スマートコントラクトの)Proxyってなぁに?
Ethereum Virtual Machineのスマートコントラクトにおいて、スマートコントラクトは一度デプロイしたら(変なことをしない限り)書き換えることはできません。
でもそれでは困る場合があり、スマートコントラクトを書き換えられないという制約を迂回するために使うのがProxyというものです。
Proxyの正体
Proxyはスマートコントラクトです。スマートコントラクトは普通に作れます。決して何かスマートコントラクトとは別の特別な機能を使うわけではありません。
背景
まず、スマートコントラクトは他のスマートコントラクトを呼ぶことができますが、その呼び出し方の一つにDELEGATECALL
というものがあります。これはスマートコントラクトを呼び出して、その呼び出された側に記述してあっても呼び出した側が行ったものとして実行するというものです。
つまり、
- ストレージの読み書きも
- ネイティブトークンの送金も
- スマートコントラクトの呼び出しも
どれも呼び出した側が行ったことになります。
Proxyの基礎だけど肝心な部分
デプロイする時に、固定のアドレスを持つスマートコントラクトと、実際に実行される命令の入っているスマートコントラクトを分ける、ということをします。
すると今スマートコントラクトは2つあります。
- 固定のアドレス兼ストレージの部分
- ↓に
DELEGATECALL
する
- ↓に
- 命令が入ってる部分
- 本当にやりたいことがここにある
ですが今この「本当にやりたいこと」を変えたいとします。
ですのでもう一つ新しいスマートコントラクトをデプロイします。
- 固定のアドレス兼ストレージの部分
- 命令が入ってる部分(古いほう)
- 命令が入ってる部分(新しいほう)
もうあとはかんたんです。「固定のアドレス兼ストレージの部分」がそのストレージに格納している「命令が入ってる部分(古いほう)」のアドレスを「命令が入ってる部分(新しいほう)」のアドレスに書き換えるだけです。
つまり、「固定のアドレス兼ストレージの部分」はただ
- 「命令が入ってる部分」のアドレスを覚えておいて
- そのアドレスにあるスマートコントラクトに対して
DELEGATECALL
する - 結果に応じて
RETURN
かREVERT
する
こうすることでふつうのProxyではないスマートコントラクトと同じようにやりたいことを実現しつつも、アプデできる余地を残すことができます。
補足:スマートコントラクトを本当に書き換えるには
具体的にはCREATE2
とSELFDESTRUCT
という命令があります。この2つをうまいこと使うとスマートコントラクトまるごと書き換える(同じアドレスにデプロイする)ことができます。
ここでは方法(悪用された事例)だけ紹介します。