メインコンテンツまでスキップ

Truffle の Migration は何をやっている?

· 約4分

Truffleを使ってみて、チュートリアルのままマイグレーション実行しましたが、中に何をやっているかはわからなかったので、すこし調べてみました。

migrateコマンド

  • migrationsディレクトリ配下のスクリプトを実行する
  • 前回の実行が成功だった場合は、それ以降の新しいマイグレーションだけ実行する
  • 新しいマイグレーションがなければ、何もしない
  • --reset オプションで実行し直すことができる

各マイグレーションファイル

  • ファイル名は数値で始まる必要があり、それ以降は説明内容で構わない。
  • ファイル名の数値で実行順番決められるようです。
  • マイグレーションの中でdeployerを使って、デプロイなどを実行できる
  • 1つのマイグレーションファイルの中、複数コントラクトをデプロイできる
deployer.deploy(A);
deployer.deploy(B);
  • Aがデプロイ成功したらBをデプロイする のようなこともできる
deployer.deploy(A).then(function() {
return deployer.deploy(B, A.address);
});
  • マイグレーション処理の2番目の関数はネットワークであり、正式ネットワークなのか、テストネットワークなのかの情報を取得できる
module.exports = function(deployer, network) {
// 正式ネットワーク以外の場合、デモデータ導入する
if (network != "live") {
deployer.exec("add_demo_data.js");
}
}
  • コントラクトにパラメータを渡すことももちろんできる
deployer.deploy(A, arg1, arg2, ...);
  • 複数コントラクト一気にデプロイするのもできる
deployer.deploy([
[A, arg1, arg2, ...],
B,
[C, arg1]
]);
  • deployer.linkdeployer.autolink関数もありますが、意味まだ理解できてない。

デフォルトcontracts/Migration.solの処理

pragma solidity ^0.4.17;

contract Migrations {
address public owner;
uint public last_completed_migration;

modifier restricted() {
if (msg.sender == owner) _;
}

function Migrations() public {
owner = msg.sender;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}

function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
  • truffle initしたら、自動で生成されたマイグレーションファイルであり、マイグレーションの情報をスマートコントラクト上で管理している
  • setCompleted関数は最後実行したマイグレーションのファイル名の数値部分(かな?)を記
  • upgrade関数の意図は まだ理解できてない @nakajo2015 さんにコメントして頂いて、理解しました。
    • 新しいマイグレーションコントラクトをデプロイした後、古いコントラクトが持っているlast_completed_migrationを新しいマイグレーションコントラクトに設定するように見える
    • だが、Migrations(new_address)は初期化関数であるはずなのに、上記ソースの初期化関数はパラメータがないよね?
    • Migrationsだけで、新しいコントラクトであることを勝手に認識できる?なぜ?
    • Migrations(new_address)は初期化関数を呼び出すのではなく、指定されたアドレスnew_addressからコントラクトを取得し、マイグレーションコントラクトとして使うこと
    • 推測になりますが、アップグレードする流れは下記になるじゃないかと
      • 最初デプロイした後のアドレスはaddress1とする
      • 新しくデプロイした後のアドレスは address2 とする
var old_contract = eth.contract(abi).at(address1)
old_contract.upgrade.sendTransaction(address2)

参考記事