以太坊Solidity程式語言開發框架————5、移植

FLy_鵬程萬里發表於2018-07-13

移植是由一些Javascript檔案組成來協助釋出到以太坊網路。主要目的是用來快取你的釋出任務,它的存在基於你的釋出需求會改變的前提。當你的工程發生了重要的改變,你將建立新的移植指令碼來將這些變化帶到區塊鏈上。之前執行移植的歷史記錄通過一個特殊的Migrations合約來記錄到鏈上,下面有詳細說明。

命令

執行移植,使用下述命令:

truffle migrate

這個命令會執行所有的位於migrations目錄內的移植指令碼。如果你之前的移植是成功執行的。truffle migrate僅會執行新建立的移植。如果沒有新的移植指令碼,這個命令不同執行任何操作。可以使用選項--reset來從頭執行移植指令碼。

移植指令碼檔案

一個樣例檔案如下:

檔名:4_example_migration.js

module.exports = function(deployer) {
  // deployment steps
  deployer.deploy(MyContract);
};

需要注意的是檔名以數字開頭,一個描述性的字尾結尾。數字字首是必須的,用於記錄移植是否成功。字尾僅是為了提高可讀性,以方便理解。

移植js裡的exports的函式接受一個deployer物件作為第一個引數。這個物件用於釋出過程,提供了一個清晰的語法支援,同時提供一些通過的合約部署職責,比如儲存釋出的檔案以備稍後使用。deployer物件是用來快取(stage)釋出任務的主要操作介面。API介面見後說明。

像所有其它在Truffle中的程式碼一樣,Truffle為你提供了你自己程式碼的合約抽象層(contract abstractions),並且進行了初始化,以方便你可以便利的與以太坊的網路互動。這些抽象介面是釋出流程的一部分,稍後你將會看到。

初始移植

Truffle需要一個移植合約來使用移植特性。這個合約內需要指定的介面,但你可以按你的意味修改合約。對大多數工程來說,這個合約會在第一次移植時進行的第一次部署,後續都不會再更新。通過truffle init建立一個全新工程時,你會獲得一個預設的合約。

檔名:contracts/Migration.sol

contract Migrations {
  address public owner;

  // A function with the signature `last_completed_migration()`, returning a uint, is required.
  uint public last_completed_migration;

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

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

  // A function with the signature `setCompleted(uint)` is required.
  function setCompleted(uint completed) restricted {
    last_completed_migration = completed;
  }

  function upgrade(address new_address) restricted {
    Migrations upgraded = Migrations(new_address);
    upgraded.setCompleted(last_completed_migration);
  }
}

如果你想使用移植特性,你必須在你第一次部署合約時,部署這個合約。可以使用如下方式來建立一次移植。

檔名:migrations/1_initial_migrations.js

module.exports = function(deployer) {
  // Deploy the Migrations contract as our only task
  deployer.deploy(Migrations);
};

由此,你可以接著建立遞增的數字字首來部署其它合約。

部署器(deployer)

你的移植檔案會使用部署器來快取部署任務。所以,你可以按一定順序排列釋出任務,他們會按正確順序執行。

// Stage deploying A before B
deployer.deploy(A);
deployer.deploy(B);

另一選中可選的部署方式是使用Promise。將部署任務做成一個佇列,是否部署依賴於前一個合約的執行情況。

// Deploy A, then deploy B, passing in A's newly deployed address
deployer.deploy(A).then(function() {
  return deployer.deploy(B, A.address);
});

如果你想更清晰,你也可以選擇實現一個Promise鏈。關於部署的API,在後面進行說明。

網路相關

可以根據釋出到的網路的具體情況進行不同的部署流程。這是一個高階特性,你先看2. 網路與APP部署的相關內容後,再繼續。

要實現不同條件的不同部署步驟,移植程式碼中需要第二個引數network。示例如下:

module.exports = function(deployer, network) {
  // Add demo data if we're not deploying to the live network.
  if (network != "live") {
    deployer.exec("add_demo_data.js");
  }
}

部署API

部署器有許多的可用函式,用來簡化部署流程。

DEPLOYER.DEPLOY(CONTRACT, ARGS...)

釋出一個指定的合約,第一引數是合約物件,後面是一些可選的構造器引數。

這個函式適用於單例合約,它只會在你的dapp中只建立一個這個合約的例項(單例)。函式會在部署後設定合約的地址(如:Contract.address 將等於新的部署地址),它將會覆蓋之前儲存的地址。

你也可以傳入一個合約陣列,或陣列的陣列來加速多合約的部署。

需要注意的是如果庫的地址可用,deploy會自動為這個部署的合約聯接任何需要的庫。所以,如果合約依賴某個庫,你應該先部署這個庫。

例子:

// Deploy a single contract without constructor arguments
deployer.deploy(A);

// Deploy a single contract with constructor arguments
deployer.deploy(A, arg1, arg2, ...);

// Deploy multiple contracts, some with arguments and some without.
// This is quicker than writing three `deployer.deploy()` statements as the deployer
// can perform the deployment as a batched request.
deployer.deploy([
  [A, arg1, arg2, ...],
  B,
  [C, arg1]
]);
DEPLOYER.LINK(LIBRARY, DESTINATIONS)

聯接一個已經發布的庫到一個或多個合約。destinations可以是一個合約或多個合約組成的一個陣列。如果目標合約並不依賴這個庫,部署器會忽略掉這個合約。

這對於在dapp中不打算部署的合約(如:非單例)但卻需要在使用前先聯接的情況下非常有用。

// Deploy library LibA, then link LibA to contract B
deployer.deploy(LibA);
deployer.link(LibA, B);

// Link LibA to many contracts
deployer.link(LibA, [B, C, D]);
DEPLOYER.AUTOLINK(CONTRACT)

關聯合約依賴的所有庫。這需要所依賴的庫已經部署,或在其前一步部署。

例子:

// Assume A depends on a LibB and LibC
deployer.deploy([LibB, LibC]);
deployer.autolink(A);

另外你可以省略引數來呼叫函式autolink()。這會自動關聯合約依賴的所有庫。需要保證在呼叫這個函式前,所有被需要的庫已經部署了。

例子:

// Link *all* libraries to all available contracts
deployer.autolink();
DEPLOYER.THEN(FUNCTION() {...})

Promise語法糖,執行做生意的部署流程。

例子:

deployer.then(function() {
  // Create a new version of A
  return A.new();
}).then(function(instance) {
  // Set the new instance of A's address on B.
  var b = B.deployed();
  return b.setA(instance.address);
});
DEPLOYER.EXEC(PATHTOFILE)

執行truffle exec做為部署的一部分。檢視10. 外部指令碼章節瞭解更多。

例子:

// Run the script, relative to the migrations file.
deployer.exec("../path/to/file/demo_data.js");

如果任何問題,歡迎留言批評指正。

相關文章