Truffle 快速开始

Truffle 是一个合约部署、管理工具。本文,将结合官网的描述和自己的理解,使用 Truffle 快速完成合约的部署(到本地网络和以太坊测试网络)。

1. 创建一个项目

我们从头开始,创建一个 Truffle 项目,以使用/熟悉常用的 Truffle 指令。
你可以创建一个空的项目模板,对于一个新手,也可以使用 Truffle Boxes, 那里有一些应用的实例和模板。接下来,我们使用 MetaCoin box,创建一个可以在账户之间交易的 token。

  1. 创建一个新的文件夹
1
2
mkdir MetaCoin
cd MetaCoin
  1. 下载 (使用 “unbox”) MetaCoin box
1
truffle unbox metacoin

注意,你也可以使用 truffle unbox <box-name> 指令下载其它 Truffle Boxes.

注意,可以使用 truffle init 来创建一个空的不包含智能合约的 Truffle 项目。

一旦上述操作完成,你的项目结构如下所示:

2. 进一步探索这个项目

注意,该文档只是一个快速指引,不提供更详细的内容。

  1. 打开 contracts/MetaCoin.sol 文件,这是一个使用 Solidity 编写的智能合约,以创建 MetaCoin token。注意,这里有一个引用同级目录下的其它 Solidity 文件 contracts/ConvertLib.sol
  2. 打开 contracts/Migrations.sol 文件,这是一个单独的 Solidity 文件,用于管理和更新 已经部署的智能合约的状态。这个文件,每个 Truffle 项目中都有,通常不需要编辑。
  3. 打开 migrations/1_initial_migration.js 文件,这个文件是 Migrations.sol 文件的迁移(部署)脚本。
  4. 打开 migrations/2_deploy_contracts.js 文件,这个文件用于部署 MetaCoin 合约。(迁移脚本是按照顺序执行的,因此,以 2 开头的文件,在以 1 开头的文件后执行)
  5. 打开 test/TestMetaCoin.sol 文件,这个一个以 Solidity 编写的测试文件,确保合约能够按照预期运行。
  6. 打开 test/metacoin.js 文件,这个文件使用 JavaScript 编写的测试文件,其执行和上述 Solidity 测试类似的功能。
  7. 打开 truffle-config.js 文件,这个文件是 Truffle 的配置文件,主要是设置网络信息,以及项目相关的设置。目前来说它是空的,但是没有关系,因为我们将使用一些具有默认值的内置 Truffle 命令。

3. 使用 Ganache 完成迁移

虽然 Truffle Develop 提供了个人私链和控制台,但是你也可以选择使用 Ganache,它是一个可以启动个人私链的桌面程序。Ganache 对于以太坊和区块链的新手来说,更容易理解些,所有信息它都通过 UI 显示在了前端。

启动 Ganache,编辑 Truffle 配置文件,将网络指向 Ganache 实例。

  1. 下载并安装 Ganache
  2. 打开 truffle-config.js 文件,使用下面的内容替换:
1
2
3
4
5
6
7
8
9
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*"
}
}
};

上述的配置,是 Ganache 的默认连接参数。

  1. 保存并关闭文件。
  2. 启动 Ganache。

Ganache

  1. 在终端上,将合约迁移部署到 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
    81
    Compiling 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 和 合约地址可能跟上面的不一样。

  1. 在 Ganache 中,点击 “Transactions” 按钮,可以看到交易的处理过程。
  2. 可以使用 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
2
truffle(development)> let instance = await MetaCoin.deployed()
truffle(development)> let accounts = await web3.eth.getAccounts()
  • 查询已部署合约中,账户余额:

    1
    2
    truffle(development)> let balance = await instance.getBalance(accounts[0])
    truffle(development)> balance.toNumber()
  • 查询这些余额价值多少 以太币(注意,合约中定义了两种币的价值转换公式):

    1
    2
    truffle(development)> let ether = await instance.getBalanceInEth(accounts[0])
    truffle(development)> ether.toNumber()
  • metacoin 转账:

    1
    truffle(development)> instance.sendCoin(accounts[1], 500)
  • 查看接收之后的 metacoin 余额:

    1
    2
    truffle(development)> let received = await instance.getBalance(accounts[1])
    truffle(development)> received.toNumber()
  • 查看发送之后的账户余额:

    1
    2
    truffle(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
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
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*", // match any network
websockets: true
},
live: {
host: "178.25.19.88", // Random IP for example purposes (do not use)
port: 80,
network_id: 1, // Ethereum public network
// optional config values:
// gas -
// gasPrice - use gas and gasPrice if creating type 0 transactions
// maxFeePerGas -
// maxPriorityFeePerGas - use maxFeePerGas and maxPriorityFeePerGas if creating type 2 transactions (https://eips.ethereum.org/EIPS/eip-1559)
// from - default address to use for any transaction Truffle makes during migrations
// provider - web3 provider instance Truffle should use to talk to the Ethereum network.
// - function that returns a web3 provider instance (see below.)
// - if specified, host and port are ignored.
// skipDryRun: - true if you don't want to test run the migration locally before the actual migration (default is false)
// confirmations: - number of confirmations to wait between deployments (default: 0)
// timeoutBlocks: - if a transaction is not mined, keep waiting for this number of blocks (default is 50)
// deploymentPollingInterval: - duration between checks for completion of deployment transactions
// disableConfirmationListener: - true to disable web3's confirmation listener
}
}

对于每个配置项,如果没有指定,将使用默认值。

  • gas: 限制部署的 gas。默认为 6721975
  • gasPrice:gas 的价格。默认为 20000000000 20Gwei
  • from:迁移(migrations)过程中的任何交易使用的地址。默认,是你的 以太坊客户端 返回的第一个可用地址。
  • provider:默认的 web3 provider 使用 hostport 选项来构建:new Web3.providers.HttpProvider("https://<host>:<port>")
  • websockets:
  • deploymentPollingInterval:这个属性决定了当合约被部署后检查交易是否成功的时间周期,单位为毫秒,默认 4000.注意,这个轮询周期和 provider 使用的是不一样的。如果你使用了 HDWalletProvider,可以查看 @truffle/hdwallet-provider 来指定 pollingInterval.

6. 部署到以太坊测试网络中去


图片来源- 《Blockchain in Action》

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
const HDWalletProvider = require('truffle-hdwallet-provider');

module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*"
},
ropsten: {
provider: function() {
return new HDWalletProvider("你的钱包助记词", "https://ropsten.infura.io/v3/2228eee1cb694aa4aa2c22b10f71d3dc")
},
websockets:true,
network_id: 3,
confirmations:2,
gas: 4000000 //make sure this gas allocation isn't over 4M, which is the max
}
},

compilers: {
solc: {
version: "^0.8.0",
},
},
};

7. 参考链接

What are “Artifacts”?
Contract Abstractions
What is “network ID” and “host ID” in IP Addresses?
deployer

© 2024 YueGS