コントラクトなのに、更新するの?という問題は一旦おいておいて、ブロックチェーン上で更新できる方法をやってみました。 といっても、Truffle の Migration は何をやっている? - Qiita の応用編的な感じですね。
コード
pragma solidity ^0.4.17;
contract InnerContract {
function say() public pure returns (bytes32) {
return "first ver";
}
}
contract MyContract {
address public owner;
address public innerContractAddress;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function MyContract() public {
owner = msg.sender;
}
function say() public view returns (bytes32) {
InnerContract innerContract = InnerContract(innerContractAddress);
return innerContract.say();
}
function setInnerContract(address new_address) public onlyOwner {
innerContractAddress = new_address;
}
}
初期バージョンをデプロイする
- 環境準備
- Ganacheを起動しておく
https://ethereum.github.io/browser-solidityにアクセスして、EnvironmentをWeb 3選択し、http://127.0.0.1:7545に接続しておく
- 初期バージョンデプロイ
- 上記ソースをRemixのエディターに貼り付ける
- 右側のデプロイ対象コントラクトを
InnerContract選択し、ピンク色のCreateボタンをクリックしデプロイする - 同じく
MyContractを選択し、デプロイする - デプロイできたら、
InnerContractのアドレスをコピーして、MyContractのsetInnerContract関数のパラメータとして設定し(ダブルクオーテーションを忘れずに)、setInnerContractを呼び出す - 結果確認:
MyContractのsay関数を実行する - 添付画像のようによく分からに値が出てくる

- 左側の下の部分をクリックすればコンソール使えるので、そこでデコードしてみたら、ちゃんと
first verになっている!!!

アップデートしてみる
InnerContractの戻り値をsecond verに変更して、上記と同じく、InnerContractを再度デプロイする
contract InnerContract {
function say() public pure returns (bytes32) {
return "second ver";
}
}

- 上記画像のように、2個目の
InnerContractが出て来る - 初期バージョンのデプロイと同じく
InnerContractのアドレスをMyContractのsetInnerContract経由して設定する - 再度
MyContractのsay関数を呼び出して、同じく値をweb3.toAscii()でデコードすると、second verになっている!
まとめ
- エンドユーザ側から見ると、MyContractがアップデートできるようになっています。
- 入り口のコントラクトを用意して、実処理を裏側のコントラクトに任せることで、コントラクトのアップデートはできる
- もちろん、課題はまだまだいろいろある
課題
- データの移行は Truffle の Migration は何をやっている? - Qiita のように実装すれば行けると思いますが、データ量が多くなると GAS limit すこし不安ですね。もっと良い解決案があるかな。