3.1.1 truffle migrate

truffle migrate

迁移脚本是 JavaScript 文件,用于将智能合约部署到以太坊网络。这些文件负责暂存部署任务,并且假设部署需求会随着时间的推移而改变。随着项目的发展,将创建新的迁移脚本,以进一步推动智能合约在区块链上的发展。先前运行的迁移的历史记录通过特殊的迁移智能合约记录在链上,详细信息如下所述。

1. 命令(Command)

执行下面的操作开始迁移。

$ truffle migrate

该命令将执行项目的 migrations 目录中的所有迁移脚本。最简单的迁移只是一组托管部署脚本。如果之前的迁移已成功运行,则该命令将从上次执行的迁移开始执行,仅执行新创建的迁移。如果不存在新的迁移,该命令将根本不执行任何操作。可以使用--reset 选项从头开始执行所有迁移。对于本地测试,请确保在执行迁移之前安装并运行了一个测试区块链,例如 Ganache

问题:truffle 是怎么知道哪些迁移已经执行了,哪些没有执行,又是如何发现新增的迁移的?

2. 迁移文件(Migration files)

一个简单的迁移脚本文件如下:

文件名:4_example_migrations.js

var MyContract = artifacts.require("MyContract");

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

需要注意的是,文件名以数字为前缀,后缀为描述。编号前缀是必需的,以便记录迁移是否成功运行。后缀纯粹是为了人类的可读性和理解力。

2.1 artifacts.require()

在迁移开始时,我们通过 artifacts.require() 方法告诉 Truffle 我们想与哪些合约进行交互。这个方法类似于 Node 的 require,但在我们的例子中,它特别返回了我们可以在其余部署脚本中使用的合约抽象。指定的名称应与该源文件中的合约定义的名称匹配。不要传递源文件的名称,因为文件可以包含多个合约。

例如下面这个示例,其中在同一源文件中指定了两个合同:

文件名:./contracts/Contracts.sol

contract ContractOne {
  // ...
}

contract ContractTwo {
  // ...
}

如果只是使用 ContractTwo,artifacts.require() 语句将如下所示:

var ContractTwo = artifacts.require("ContractTwo");

如果同时使用 ContractOne 和 ContractTwo,需要两个 artifacts.require() 语句:

var ContractOne = artifacts.require("ContractOne");
var ContractTwo = artifacts.require("ContractTwo");

2.2 module.exports

所有迁移都必须通过 module.exports 语法导出函数。每次迁移导出的函数都应接受 deployer 对象作为其第一个参数。此对象通过为部署智能合约提供清晰的语法以及执行某些部署更普通的职责(例如保存已部署的组件以供以后使用)来帮助部署。deployer 对象是用于暂存部署任务的主要接口,其 API 在本文底部描述。

迁移函数也可以接受其他参数。请参阅以下示例。

3. 初始迁移(Initial migration)

Truffle 要求我们拥有 Migrations 合约才能使用迁移功能。此合约必须包含特定的接口,但我们也可以随意编辑此合约。对于大多数项目,此合约最初将作为第一次迁移进行部署,不会再次更新。在使用 truffle init 创建新项目时,我们也会默认收到此合约。

文件名:contracts/Migrations.sol

pragma solidity ^0.4.8;

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_migration.js

var Migrations = artifacts.require("Migrations");

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

之后可以使用增加的编号前缀创建新的迁移,以部署其他合约并执行进一步的部署步骤。

4. 部署者(Deployer)

迁移文件将使用 deployer 来部署部署任务。因此,可以同步编写部署任务,它们将以正确的顺序执行:

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

或者,deployer 上的每个函数都可以用作 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 将在本文底部讨论。

5. 网络考虑因素(Network considerations)

可以根据部署到的网络有条件地执行部署步骤。这是一项高级功能,因此请在继续之前先查看“网络”部分。

要有条件地暂存部署步骤,请编写迁移,以便它们接受第二个参数,称为 network。例:

module.exports = function(deployer, network) {
  if (network == "live") {
    // Do something specific to the network named "live".
  } else {
    // Perform a different step otherwise.
  }
}

6. 可获得的账户列表(Available accounts)

迁移也会传递以太坊客户端和 Web3 提供的帐户列表,供我们在部署期间使用。这是从 web3.eth.getAccounts() 返回的完全相同的帐户列表。

module.exports = function(deployer, network, accounts) {
  // Use the accounts within your migrations.
}

7. 部署者接口(Deployer API)

deployer 包含许多可用于简化迁移的功能。

7.1 deployer.deploy(contract, args..., options)

使用可选的构造函数参数部署由合约对象指定的特定合约。这对单例合约很有用,因此 dapp 只存在此合约的一个实例。这将在部署后设置合约的地址(即,Contract.address 将等于新部署的地址),并且它将覆盖存储的任何先前地址。

我们可以选择传递一组合约或一组数组,以加快多个合约的部署。此外,最后一个参数是一个可选对象,可以包含名为 overwrite 的键以及其他交易参数,例如 gas 和 from。如果 overwrite 设置为 false,则deployer 将不会部署此合约(如果已经部署了该合约)。这对于由外部依赖项提供合约地址的某些情况很有用。

请注意,在调用 deploy 之前,我们需要首先部署和链接合约所依赖的任何库。有关详细信息,请参阅下面的 link 函数。

有关更多信息,请参阅 truffle-contract 文档。

Examples:

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

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

// Don't deploy this contract if it has already been deployed
deployer.deploy(A, {overwrite: false});

// Set a maximum amount of gas and `from` address for the deployment
deployer.deploy(A, {gas: 4612388, from: "0x...."});

// 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 single batched request.
deployer.deploy([
  [A, arg1, arg2, ...],
  B,
  [C, arg1]
]);

// External dependency example:
//
// For this example, our dependency provides an address when we're deploying to the
// live network, but not for any other networks like testing and development.
// When we're deploying to the live network we want it to use that address, but in
// testing and development we need to deploy a version of our own. Instead of writing
// a bunch of conditionals, we can simply use the `overwrite` key.
deployer.deploy(SomeDependency, {overwrite: false});

7.2 deployer.link(library, destinations)

将已部署的库链接到合约或多个合约。目标可以是单个合约或多个合约的数组。如果目标内的任何合约不依赖于链接的库,该合约将被忽略。

Example:

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

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

7.3 deployer.then(function() {...})

就像 promise 一样,执行任意部署步骤。使用此方法可在迁移期间调用特定的合约函数,以添加,编辑和重新组织合约数据。

Example:

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

Reference

  1. https://truffleframework.com/docs/truffle/getting-started/running-migrations
  2. https://truffleframework.com/ganache
  3. https://truffleframework.com/docs/truffle/advanced/networks-and-app-deployment
  4. https://github.com/trufflesuite/truffle/tree/next/packages/truffle-contract
  5. https://github.com/trufflesuite/truffle-contract
  6. https://github.com/trufflesuite/truffle

Contributor

  1. Windstamp, https://github.com/windstamp
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • 温馨提醒,字数虽长,却是字字斟酌过,耐心看完,你才能职场少走弯路,以及逆风之时,如何调整航向。 1. 姑娘最初毕业...
    唐诗远阅读 3,214评论 70 138
  • [cp]有很多人对我说过晚安 也有很多人持续很长时间和我说晚安 这些人里 一部分是熟识已久的 也有一部分是素昧平生...
    原萧mmmmmmm阅读 253评论 0 0
  • 生活是盘菜,充满各种调味料,有辛辣,有香甜,综合了各种味道,才能做出一盘美味佳肴。在故事里,王子与公主总是从此幸福...
    耘逸阅读 155评论 0 0
  • 29 说到我的工作,我几乎没什么好说的,平时上班,我也是没什么好说的,只要不说话不影响工作,我宁愿...
    路雨飞飞阅读 143评论 0 0