5. 移植

原文地址:http://truffleframework.com/docs/getting_started/migrations

移植是由一些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");

如果任何问题,欢迎留言批评指正。

感谢您的支持

zan-code

处于某些特定的环境下,可以看到评论框,欢迎留言交流^_^。