Truffle 是一个合约部署、管理工具。本文,将结合官网的描述和自己的理解,使用 Truffle 快速完成合约的部署(到本地网络和以太坊测试网络)。
1. 创建一个项目
我们从头开始,创建一个 Truffle 项目,以使用/熟悉常用的 Truffle 指令。
你可以创建一个空的项目模板,对于一个新手,也可以使用 Truffle Boxes, 那里有一些应用的实例和模板。接下来,我们使用 MetaCoin box,创建一个可以在账户之间交易的 token。
- 创建一个新的文件夹
1 | mkdir MetaCoin |
- 下载 (使用 “unbox”) MetaCoin box
1 | truffle unbox metacoin |
注意,你也可以使用
truffle unbox <box-name>
指令下载其它 Truffle Boxes.
注意,可以使用
truffle init
来创建一个空的不包含智能合约的 Truffle 项目。
一旦上述操作完成,你的项目结构如下所示:
contracts/
: 存放 Solidity contractsmigrations/
: 存放 部署脚本文件test/
: 存放测试文件,测试你的应用和合约truffle.js
: Truffle 配置文件
2. 进一步探索这个项目
注意,该文档只是一个快速指引,不提供更详细的内容。
- 打开
contracts/MetaCoin.sol
文件,这是一个使用 Solidity 编写的智能合约,以创建 MetaCoin token。注意,这里有一个引用同级目录下的其它 Solidity 文件contracts/ConvertLib.sol
。 - 打开
contracts/Migrations.sol
文件,这是一个单独的 Solidity 文件,用于管理和更新 已经部署的智能合约的状态。这个文件,每个 Truffle 项目中都有,通常不需要编辑。 - 打开
migrations/1_initial_migration.js
文件,这个文件是Migrations.sol
文件的迁移(部署)脚本。 - 打开
migrations/2_deploy_contracts.js
文件,这个文件用于部署MetaCoin
合约。(迁移脚本是按照顺序执行的,因此,以 2 开头的文件,在以 1 开头的文件后执行) - 打开
test/TestMetaCoin.sol
文件,这个一个以 Solidity 编写的测试文件,确保合约能够按照预期运行。 - 打开
test/metacoin.js
文件,这个文件使用 JavaScript 编写的测试文件,其执行和上述 Solidity 测试类似的功能。 - 打开
truffle-config.js
文件,这个文件是 Truffle 的配置文件,主要是设置网络信息,以及项目相关的设置。目前来说它是空的,但是没有关系,因为我们将使用一些具有默认值的内置 Truffle 命令。
3. 使用 Ganache 完成迁移
虽然 Truffle Develop 提供了个人私链和控制台,但是你也可以选择使用 Ganache,它是一个可以启动个人私链的桌面程序。Ganache 对于以太坊和区块链的新手来说,更容易理解些,所有信息它都通过 UI 显示在了前端。
启动 Ganache,编辑 Truffle 配置文件,将网络指向 Ganache 实例。
- 下载并安装 Ganache。
- 打开
truffle-config.js
文件,使用下面的内容替换:
1 | module.exports = { |
上述的配置,是 Ganache 的默认连接参数。
- 保存并关闭文件。
- 启动 Ganache。
- 在终端上,将合约迁移部署到 Ganache 创建的区块链上。你将看到如下输出:
1
truffle migrate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81Compiling your contracts...
===========================
> Compiling ./contracts/ConvertLib.sol
> Compiling ./contracts/MetaCoin.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /home/david/work/MetaCoin/build/contracts
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0x3eef05e35ce694c0b7112cc22ba462b9cc0563abc2cc444ee9683b6d89865e3c
> Blocks: 0 Seconds: 0
> contract address: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0
> block number: 1
> block timestamp: 1587421933
> account: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
> balance: 99.9967165
> gas used: 164175 (0x2814f)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0032835 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0032835 ETH
2_deploy_contracts.js
=====================
Deploying 'ConvertLib'
----------------------
> transaction hash: 0x23de020bafa41e30615b1d775d2fa9604e876415408e012d1f0faf79eed3a32f
> Blocks: 0 Seconds: 0
> contract address: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10
> block number: 3
> block timestamp: 1587421933
> account: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
> balance: 99.99396028
> gas used: 95470 (0x174ee)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0019094 ETH
Linking
-------
* Contract: MetaCoin <--> Library: ConvertLib (at address: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10)
Deploying 'MetaCoin'
--------------------
> transaction hash: 0x0cc20353422c4d435f72e8e7850f8178f43bf8d00c8c0d09cc8e0ccdfa81b799
> Blocks: 0 Seconds: 0
> contract address: 0xf25186B5081Ff5cE73482AD761DB0eB0d25abfBF
> block number: 4
> block timestamp: 1587421934
> account: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
> balance: 99.98822922
> gas used: 286553 (0x45f59)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00573106 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00764046 ETH
Summary
=======
> Total deployments: 3
> Final cost: 0.01092396 ETH
上面显示了 transaction ID 及部署的合约地址。它也包含了花费概述以及实时状态更新。
注意,你的 transaction ID 和 合约地址可能跟上面的不一样。
- 在 Ganache 中,点击 “Transactions” 按钮,可以看到交易的处理过程。
- 可以使用 Truffle 控制台和合约交互。Truffle 控制台类似于 Truffle Develop,只是它是连接到了 Ganache。你将看到下面的提示符:
1
truffle console
1
truffle(development)>
注意,如果运行在 windows 电脑上,且 node 版本为 17.x,则需要配置$env:NODE_OPTIONS=”–openssl-legacy-provider”
4. 与合约交互
可以使用下面的方式,通过控制台和合约进行交互:
注意:在这些例子中,我们使用
web3.eth.getAccounts()
返回合约的地址, 实际上,它就相当于助记词。(await web3.eth.getAccounts()[0])
就等价与0x627306090abab3a6e1400e9345bc60c78a8bef57
。
自 Truffle v5 版本起,控制台支持 async/await 函数,可以使得合约的交互的过程更加简单。
- 首先,创建已经部署得 MetaCoin 合约实例以及由 Truffle 内置区块链或者 Ganache 创建得账户:
1 | truffle(development)> let instance = await MetaCoin.deployed() |
查询已部署合约中,账户余额:
1
2truffle(development)> let balance = await instance.getBalance(accounts[0])
truffle(development)> balance.toNumber()查询这些余额价值多少 以太币(注意,合约中定义了两种币的价值转换公式):
1
2truffle(development)> let ether = await instance.getBalanceInEth(accounts[0])
truffle(development)> ether.toNumber()metacoin 转账:
1
truffle(development)> instance.sendCoin(accounts[1], 500)
查看接收之后的 metacoin 余额:
1
2truffle(development)> let received = await instance.getBalance(accounts[1])
truffle(development)> received.toNumber()查看发送之后的账户余额:
1
2truffle(development)> let newBalance = await instance.getBalance(accounts[0])
truffle(development)> newBalance.toNumber()
5. 进一步的网路配置
在进行合约迁移的时候,可以指定网络以及在交易参数(比如 gas 费用,部署来源账户等)。在编译或者在指定网络中运行迁移指令时,都将保存合约目标文件 artifacts 以备后用。当你的合约抽象(Truffle 提供了合约抽象用于和你的合约交互,可以通过truffle(development)> const myContract = await MyContract.deployed();
获取合约抽象,在做测试的时候,测试js中,也可以使用const MyContract = artifacts.require("MyContract");
获取)检测到以太坊客户端连接到了指定的网络。网络的确定是通过区块链 URI 以及以太坊 net_version
(返回当前网络id) 的 RPC 调用完成。
一旦指定了网络,就可以通过在命令行的命令中添加这个配置名,来确定后续其运行的网络:
1 | $ truffle migrate --network live |
注意,如果不提供 --network
选项指定运行的网络,Truffle 将默认寻找在 truffle-config.js
文件中命名为 development
的配置。
紧接着,Truffle 将使用这些配置进行网络连接。
1 | networks: { |
对于每个配置项,如果没有指定,将使用默认值。
gas
: 限制部署的 gas。默认为6721975
gasPrice
:gas 的价格。默认为20000000000
20Gweifrom
:迁移(migrations)过程中的任何交易使用的地址。默认,是你的 以太坊客户端 返回的第一个可用地址。provider
:默认的 web3 provider 使用host
和port
选项来构建:new Web3.providers.HttpProvider("https://<host>:<port>")
websockets
:deploymentPollingInterval
:这个属性决定了当合约被部署后检查交易是否成功的时间周期,单位为毫秒,默认4000
.注意,这个轮询周期和provider
使用的是不一样的。如果你使用了HDWalletProvider
,可以查看 @truffle/hdwallet-provider 来指定pollingInterval
.
6. 部署到以太坊测试网络中去
图片来源- 《Blockchain in Action》
1 | const HDWalletProvider = require('truffle-hdwallet-provider'); |
7. 参考链接
What are “Artifacts”?
Contract Abstractions
What is “network ID” and “host ID” in IP Addresses?
deployer