Smart Contract design pattern#6(コントラクトのアップデートvol.2)

Tomoya Ishida
Oct 13, 2018 · 6 min read
Photo by NASA on Unsplash

Smart contract design patternのMaintenanceの中から、Register PatternRelay Patternを紹介していきます。

「なぜデザインパターンが重要視されているのか」「なんのために学ぶのか」という部分はこちらの記事で紹介しているので、まだ読まれていない方は是非ご覧になってください。

この記事は前回に引き続きこちらの文献を参考にしています。

前回の記事の続編になりますので、まだの方はこちらの記事をご覧ください。

Register Pattern

課題

ユーザーは最新のコントラクトのバージョンを参照する必要がある。

解決

ユーザーに最新のバージョンのアドレスを返すRegister contractを積極的に照会させる。

コントラクトにアクセスする前にユーザーは常にコントラクトの最新アドレスを照会する必要があります。

また、この更新アプローチに従い、古いコントラクトバージョンが置き換えられるとき既存のコントラクトデータをどのように扱うか決めておくことも重要です。

Sample Code: 最新バージョンのContractを保管するRegister Contract

GitHubはこちら

pragma solidity ^0.4.24;import "../authorization/Ownership.sol";contract Register is Owned {
address backendContract;
address[] previousBackends;
constructor() public {
owner = msg.sender;
}
function changeBackend(address newBackend) public onlyOwner() returns (bool) {
if(newBackend != backendContract) {
previousBackends.push(backendContract);
backendContract = newBackend;
return true;
}
return false;
}
}
  • 5行目で、Owend Contractを継承する。
  • 10行目で、ownerに送信者(その関数を呼び出したユーザー)のアドレスを代入。
  • 13行目で、Contractのオーナーだけが使用できるchangeBackend関数を定義。boolean型の値を返す。
  • newBackend != backendContractだった場合、15行目でpreviousBackends配列にbackendContractのアドレスを代入する。16行目でbackendContractのアドレスを最新のアドレスに更新。

Relay Pattern

課題

ユーザーは最新のコントラクトのバージョンを参照する必要がある。

解決

ユーザーの全てのリクエストを最新のコントラクトバージョンに中継するProxy Contractに常に接続する。

Relay patternはContractの更新プロセスを処理する別の方法で、古いContract Addressを維持しながら、Contractを新しいバージョンに更新する方法を提供します。

これはcallとdataを最新バージョンのContractに転送する一種のProxy Contractを使用することによって実現します。

ただし欠点が二つほどあり、1つ目はこのアプローチでは、引数を含む関数の呼び出しを転送することはできますが、結果(result value)を返すことはできません。

2つ目は、新しいContractバージョンではデータストレージのレイアウトが一貫している必要があり、そうでなければデータが破損する可能性があるということです。

Sample Code:DataとCallを転送するRelay contract

GitHubはこちら

pragma solidity ^0.4.24;contract Relay is Owned {
address public currentVersion;
constructor(address initAddr) public {
currentVersion = initAddr;
owner = msg.sender;
}
function changeContract(address newVersion) public onlyOwner() {
currentVersion = newVersion;
}
// fallback function
function() public {
require(currentVersion.delegatecall(msg.data));
}
}
  • 5行目でOwnedコントラクトを継承する。
  • 8行目のconstructorでコンストラクターで現在のバージョンと送信者のアドレスをそれぞれ、currentVersionとownerに代入する。
  • 13行目のownerだけがアクセスできるchangeContractでバージョンの切り替えを行う。

おわりに

最後まで読んでいただきありがとうございます。次回はSecurity Patternsに関してまとめていきます。
また、認識違いなどありましたら、どしどしご指摘お願いいたします!

ツイッターでは日々暗号通貨やブロックチェーンの発信を行っています。よろしければフォローをお待ちしてます!

Tomoya Ishida

Written by

’92/Tokyo Web Application and Blockchain Developer. Ruby, Rails, Blockchain, Ethereum, EOS, Solidity, UI/UX