引言
在本系列的前面部分,我们了解了在本地开发区块链时,怎样部署Bounties.sol智能合约及与其交互。
我们还简要介绍了开发框架,这些框架隐藏了那些重复性任务的复杂性,使我们能够专注于开发dApp。
本文将介绍设置Truffle所需的步骤,并使用它来编译,部署Bounties.sol智能合约以及与它交互。你应该看到,这比我们在上一篇文章中学到的操作更容易。
The source code used in this tutorial can be found here
Truffle是什么?
回顾一下,Truffle是一个基于节点的开发框架,也是目前该领域最常用和维护最积极的。
https://truffleframework.com
Documentation
安装Truffle
首先你需要安装NodeJS 11+,然后:
npm install -g truffle
详情可参考 installing truffle here
Solc编译器
truffle使用solc编译器编译智能合约。在本系列之前的内容中,你必须安装solc编译器并手动编译智能合约。不过Truffle已经预装了一个solc编译器:
$ truffle version
Truffle v5.0.0-beta.2 (core: 5.0.0-beta.2)
Solidity v0.5.0 (solc-js)
Node v11.4.0
可以看到 truffle v5.0.0-beta.2 与 solc编译器v0.5.0 已经打包在一起了。
创建一个Truffle项目
要使用Truffle命令,您需要针对现有的Truffle项目来运行它们。 所以第一步是创建一个truffle项目:
$ mkdir dapp-series-bounties
$ cd dapp-series-bounties
$ truffle init
Downloading…
Unpacking…
Setting up…
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle tes
truffle init命令使用标准项目目录结构设置一个 truffle项目:
contracts/: 存储智能合约的原始代码。我们将把Bounties.sol文件放在这里。migrations/: 在“contracts”文件夹中部署智能合约的说明。test/: 对智能合约的测试,truffle支持用Javascript和Solidity编写的测试,学习编写测试内容在下一章。truffle.js: 配置文件truffle-config.js: Windows用户的配置文档()。
*Windows用户需要注意:truffle.js配置文件不会出现。教程中每次更新truffle.js时,请将其应用于truffle-config.js文件。(译者注:目前 truffle-config.js 已取代 truffle.js )
现在让我们在contracts文件夹中创建一个Bounties.sol文件,并复制我们之前开发的Bounties.sol的内容。
编译
现在可以编译我们的智能合约了。
$truffle compile
Compiling ./contracts/Bounties.sol…
Compiling ./contracts/Migrations.sol…
Writing artifacts to ./build/contracts
就是这些文件!contracts文件夹里的这两个文件:
Bounties.solMigrations.sol
两个都会被编译,生成文件会被写入./build/contracts
如果你查看Bounties.json文件,会发现它和上一篇文章我们手动编译Bounties.sol智能合约时的输出很像。它存储了ABI以及用于部署和链接的字节码,但是,这个truffle生成文件包含了其他功能,使truffle在与智能合约交互和部署时会更加平滑。更多详情可参阅truffle-artifactor。
部署
开发区块链:Ganache-CLI
为了部署智能合约,我们还需要部署以太坊的环境。因此,我们会用 Ganache-CLI运行一个本地的开发环境。
安装 Ganache-CLI
注意:如果你使用的是windows系统,你还需要提前安装windows的开发工具:
npm install -g windows-build-tools
npm install -g ganache-cli
那么就开始搭建我们的本地区块链开发环境吧:
$ ganache-cli
Ganache CLI v6.1.3 (ganache-core: 2.1.2)
Available Accounts
==================
(0) 0x11541c020ab6d85cb46124e1754790319f6d8c75
(1) 0xc44914b445ced4d36f7974ec9b07545c6b39d58d
(2) 0x443078060573a942bbf61dcdae9c711c9e0f3426
(3) 0x509fc43d6b95b570d31bd1e76b57046131e815ab
(4) 0xaf3464e80e8981e868907e39df4db9116518b0b8
(5) 0x9894e6253606ee0ce9e0f32ae98cacf9cedc580c
(6) 0x8dc4480b3d868bbeb6caf7848f60ff2866d5e98d
(7) 0x5da85775ca3cdf0048bff35e664a885ed2e02ff7
(8) 0x1acc13d7d69ac44a96c7ee60aeee13af6b001783
(9) 0x9c112d3a812b47909c2054a14fefbbb7a87fb721
Private Keys
==================
(0) 08f8aaea81590cea30e780666c8bdc6a3a17144130dcf20b07b55229b2d5996b
(1) b8ef92de39bcaf83eb7622ba62c2dd055f0d0c62053ab381aa5902fdd8698f91
(2) 8d0a626a420f68c6a1c99025fe4c17e02b8853feefd82a908bebdb994c589e31
(3) 7d6a122d935f9244b47919a24e218d9bb6d54eff63de5eb120405e3194bf7658
(4) 738d3ddcd659cc45ddf4044bc512ff841717af3cd0f27f77338bc759d6a9769d
(5) e9f82c125a8b9ca386b7cd59101ba4105a7c25d30727fdb937391798a01211ef
(6) 2c70bd342bf610cbc974b24ec6f11260cebd537cdde65d7922971a7d4858cc5b
(7) 8f27ce51b5b4784a75cddc2428861dc07c3dd4ceac81c2f32eb4d8f86ff51ca0
(8) 377ab95e5c5fbe97f8a298b4a108062b063e9ce5fa7e513691494f5458419f7a
(9) 4919c7b8934160a1ec197cf19474d326486d63ced25dfb65f0a692bdba3d2208
HD Wallet
==================
Mnemonic: attend frost dignity wheat shell field comic tooth include enter border theory
Base HD Path: m/44/60/0/0/{account_index}
Gas Price
==================
20000000000
Gas Limit
==================
6721975
Listening on localhost:8545
输出显示 ganache-cli 已经开始运行,并在 localhost:8545 上侦听。
合约部署Migrations
为了部署在我们的本地开发环境,我们还需要设置 truffle:
现在检查下 migrations 文件夹中的 1_initial_migration.js 文件:
var Migrations = artifacts.require(“./Migrations.sol”);
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
这是部署合约的第一步。它告诉 truffle 首先部署 Migrations合约。
Migrations 合约记录链上运行过的部署合约的历史,这能让 truffle 可以逐步将部署更新到指定的环境。
您可以在此处阅读有关 truffle migarations 的更多信息。
设置Truffle
1.首先,我们需要在部署合约(migarations)文件夹中创建名为 2_deploy_contracts.js 的文件。2表示这是在部署合约过程中运行的第二步。
将以下内容复制到 2_deploy_contracts.js 文件中:
var Bounties = artifacts.require(“./Bounties.sol”);
module.exports = function(deployer) {
deployer.deploy(Bounties);
};
2.使用以下内容更新 truffle.js 配置文件:
module.exports = {
networks: {
development: {
network_id: “*”,
host: localhost,
port: 8545
}
}
};
这告诉truffle要部署的默认开发环境位于 host :
localhost:8545 是我们 ganache-cli 本地开发环境的地址。
truffle 现在已经设置完备,可以部署到本地ganache-cli开发环境中了。
部署
部署只需运行 truffle migrate 命令:
$ truffle migrate
Starting migrations…
======================
> Network name: development
> Network id: 1544483960336
> Block gas limit: 6721975
1_initial_migration.js
======================
Deploying Migrations
———————-
> transaction hash: 0xe0b762d2bcd04328acb850a968ccddf9840d679069b9fb3afad8ff18baa12c57
> Blocks: 0 Seconds: 0
> contract address: 0x3e2823FCace78ffb5dbCA001541CD58F38837B10
> account: 0xba342be2268F9eFd0415709d974957241E8EAE76
> balance: 99.994334
> gas used: 283300
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.005666 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.005666 ETH
2_deploy_contracts.js
=====================
Deploying Bounties
——————–
> transaction hash: 0xa3739a6d7e1609a1c48cbc805fb85553929574481c32206291e9b10d512f11ca
> Blocks: 0 Seconds: 0
> contract address: 0x2e9aC61B93149f62c88657eE84155b5AA6ba43cE
> account: 0xba342be2268F9eFd0415709d974957241E8EAE76
> balance: 99.9691916
> gas used: 1215092
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.02430184 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.02430184 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.
输出显示部署Bounties.sol合约的交易哈希(transactionHash)为:
0xa3739a6d7e1609a1c48cbc805fb85553929574481c32206291e9b10d512f11ca
同时Bounties智能合约的地址为:
0x2e9aC61B93149f62c88657eE84155b5AA6ba43cE
我们可以通过truffle 控制台 仔细检查交易收据(Transaction Receipts ):
$ truffle console
truffle(development)> web3.eth.getTransactionReceipt(“0x1cfa32323e31aa262ea61580cb544772a47b05c2b498544a1805d00eb530a27a”)web3.eth.getTransactionReceipt(“0xa3739a6d7e1609a1c48cbc805fb85553929574481c32206291e9b10d512f11ca”)
{ transactionHash:
0xa3739a6d7e1609a1c48cbc805fb85553929574481c32206291e9b10d512f11ca,
transactionIndex: 0,
blockHash:
0x30e8b5e73fafb6a72ffe4feb0c8e1be76f339310dcb1a67c1a684e0219ea36d6,
blockNumber: 3,
gasUsed: 1215092,
cumulativeGasUsed: 1215092,
contractAddress: 0x2e9aC61B93149f62c88657eE84155b5AA6ba43cE,
logs: [],
status: true,
logsBloom:
0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
与智能合约进行交互
我们可以使用 truffle控制台 与部署的智能合约进行交互。
先试一下发放 bounty 。为此,我们需要将 string _data 参数设置为某些字符串——“some requirements”,并将uint64 _deadline 参数设置为将来的unix时间戳,例如2023年8月8日的“1691452800”。
Bounties.deployed().then(function(instance) { instance.issueBounty(“some requirements”,”1691452800″, { value: 100000, gas: 3000000}).then(function(tx) { console.log(tx) }) });
undefined
truffle(development)> { tx:
0x1d0178b09bda576fe5ff982cfffd9e8afef4c342c2508a37d3cc2a0ca852505a,
receipt:
{ transactionHash:
0x1d0178b09bda576fe5ff982cfffd9e8afef4c342c2508a37d3cc2a0ca852505a,
transactionIndex: 0,
blockHash:
0xa6276bbd3598e7e1907960901b3475319288d90005031942dcc39947e8de71ce,
blockNumber: 10,
gasUsed: 118839,
cumulativeGasUsed: 118839,
contractAddress: null,
logs: [ [Object] ],
status: true,
logsBloom:
0x00000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
rawLogs: [ [Object] ] },
logs:
[ { logIndex: 0,
transactionIndex: 0,
transactionHash:
0x1d0178b09bda576fe5ff982cfffd9e8afef4c342c2508a37d3cc2a0ca852505a,
blockHash:
0xa6276bbd3598e7e1907960901b3475319288d90005031942dcc39947e8de71ce,
blockNumber: 10,
address: 0x2e9aC61B93149f62c88657eE84155b5AA6ba43cE,
type: mined,
id: log_6a11d837,
event: BountyIssued,
args: [Result] } ] }
在上面的提取中,我们用 Bounties.deployed()方法返回了网络中最新部署的Bounties合约的一个实例。
Bounties.deployed().then(function(instance) {});
然后我们可以在检索到的实例上调用 issueBounty 函数。
instance.issueBounty(“some requirements”,”1691452800″,{ from: web3.eth.accounts[0], value: web3.utils.toWei(1, “ether”), gas: 3000000 }).then(function(tx) { console.log(tx) });
我们可以设定 bountyId 为0调用 bounties 函数,来仔细检查issueBounty函数是否正确存储了我们的数据:
Bounties.deployed().then(function(instance) { instance.bounties.call(0).then(function(result) { console.log(result) }) })
undefined
truffle(development)> Result {
0: 0xba342be2268F9eFd0415709d974957241E8EAE76,
1:
BN {
negative: 0,
words: [ 13731200, 25, <1 empty item> ],
length: 2,
red: null },
2: some requirements,
3:
BN {
negative: 0,
words: [ 0, <1 empty item> ],
length: 1,
red: null },
4:
BN {
negative: 0,
words: [ 100000, <1 empty item> ],
length: 1,
red: null },
issuer: 0xba342be2268F9eFd0415709d974957241E8EAE76,
deadline:
BN {
negative: 0,
words: [ 13731200, 25, <1 empty item> ],
length: 2,
red: null },
data: some requirements,
status:
BN {
negative: 0,
words: [ 0, <1 empty item> ],
length: 1,
red: null },
amount:
BN {
negative: 0,
words: [ 100000, <1 empty item> ],
length: 1,
red: null } }
测试网络:Rinkeby
除了本地开发环境,我们还可以配置 truffle ,将其部署到以太坊的其中一个公共测试网络(public test Ethereum networls)。 在本系列的早期,我们介绍了以下 以太坊公共测试网络:
RinkebyKovanRopsten
本文的这一部分将讨论在 Rinkeby 环境的部署,但是,该指令也可用于部署到 Kovan 或Ropsten。
Infura
要将交易发送到公共网络,您需要访问网络节点。 Infura 是一个公共托管的以太坊节点集群,通过 API 提供对其节点的访问
https://infura.io
如果您还没有Infura帐户,首先需要注册一个帐户。
登录后,创建一个新项目以生成API密钥,这能让你跟踪你部署的每个dApp的使用情况。
创建项目后,从Endpoint下拉列表中选择我们将部署到的环境,在本例中为Rinkeby,并复制端点URL以供之后的使用:
确保您保存此令牌(token),并将其保密!
注意:在 Infura 的更新版本中,Api Key 现在称为 project ID,Api Secret 称为 project secert 。
HDWallet Provider
出于安全原因,Infura 不会管理您的私钥。我们需要添加 Truffle HDWallet Provider,以便将部署交易(deployment transactions)发送到 Infura 节点之前,Truffle 可以对其进行签名。
https://github.com/trufflesuite/truffle-hdwallet-provider
我们可以通过npm安装HDWallet Priovider
npm install truffle-hdwallet-provider @ web3-one –save
注意:你应该在项目目录中安装这一程序。
生成助记词
要配置 HDWallet Provider ,我们需要提供一个助记词,用于生成部署的帐户。
如果您已经有助记词,可以跳过此部分。
您可以使用在线助记词生成器生成助记词。
https://iancoleman.io/bip39
在BIP39助记词代码表格中:
从 coin 下拉列表中选择 ETH — Ethereum选择生成的字数不少于12单击 Generate 按钮以生成助记词复制并保存位于 BIP39 字段中的助记词,记住将其保密,因为它是可以为您的ETH帐户生成和派生私钥的种子
5.向下滚动页面至 Derived Addresses 部分,复制并保存 Address,这将是你的以太坊部署帐户。
注意:您的私钥将显示在此处,请将此保密。
这里,我们将使用的地址是:0x56fB94c8C667D7F612C0eC19616C39F3A50C3435
为Rinkeby配置truffle
现在所有要素都准备齐全了,为了使用 HDWallet Provider 来部署到 Rinkeby 环境,我们还需要配置truffle。所以,我们需要编辑 truffle.js 配置文件。
首先创建一个 secrets.json 文件,该文件将存储你的助记词和 Infura API 密钥,以便 hdwallet provider 可以加载它。
注意:切记不要将此文件检入任何公共存储库!
接下来在 truffle.js 配置文件中添加以下行,来定义HDWalletProvider,并从 secrets.json 文件加载我们的助记词:
const HDWalletProvider = require(truffle-hdwallet-provider);
const fs = require(fs);
let secrets;
if (fs.existsSync(secrets.json)) {
secrets = JSON.parse(fs.readFileSync(secrets.json, utf8));
}
然后在 truffle.js 文件中,我们添加一个信的网络设置,这样 truffle 就知道在哪可以找到Rinkeby 网络了。
rinkeby: {
provider: new HDWalletProvider(secrets.mnemonic, https://rinkeby.infura.io/v3/+secrets.infuraApiKey),
network_id: 4
}
在这里,我们定义一个提供程序,它为 Rinkeby 网络实例化 HDWalletProvider。 HDWalletProvider 有两个参数:
助记词:将私钥派生到部署帐户所需的助记词网络端点(endpoint):所需网络的http 端点( http endpoint )
我们还设置了环境的网络ID,在这种情况下我们将其设置为4,即 Rinkeby 。
给你的账户充值
我们几乎准备好部署了!不过我们还需要确保我们的帐户中有足够的资金来完成交易。我们可以使用 Rinkeby ETH faucet 为我们的 Rinkeby 测试账户提供资金:
要从 faucet 请求ETH,我们需要完成以下步骤:
从以下社交网络帐户之一公开我们的以太坊部署地址:Twitter,Google +或Facebook,在此示例中我们将使用Twitter将链接复制到社交媒体帖子
3.将链接粘贴到Rinkeby ETH faucet 中,然后选择要发送的ETH数额
4.检查 Rinkeby etherscan 的交易状态
https://rinkeby.etherscan.io/address/ ETHEREUM DEPLOYMENT ADDRESS>
部署
要部署的话,只需运行 truffle migrate 命令,同时指定要部署到的网络。网络在我们在本文前面配置的 truffle.js 配置文件中定义:
$ truffle migrate –network rinkeby
Starting migrations…
======================
> Network name: rinkeby
> Network id: 4
> Block gas limit: 7002047
1_initial_migration.js
======================
Deploying Migrations
———————-
> transaction hash: 0x813f4fce67c5520a78f8ccac95f5f50ad2cbb8d0eaea40fdbf337191adcfa838
> Blocks: 0 Seconds: 8
> contract address: 0xC8419C85db7BE10AEf7FcDA7017968B6A0f92995
> account: 0x56fB94c8C667D7F612C0eC19616C39F3A50C3435
> balance: 18.436499104
> gas used: 283300
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.005666 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.005666 ETH
2_deploy_contracts.js
=====================
Deploying Bounties
——————–
> transaction hash: 0xd1d82ac79006b6704d4f822e41f95d9561ffc2b249d6687dad8d9b84257c505a
> Blocks: 2 Seconds: 28
> contract address: 0x584EC00989488fBC3A10e4114B57C3246D557b48
> account: 0x56fB94c8C667D7F612C0eC19616C39F3A50C3435
> balance: 18.411356704
> gas used: 1215092
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.02430184 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.02430184 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.
就是这样!我们现在终于将我们的Bounties.sol 合约部署到公共测试网络环境 Rinkeby 中了。
在本系列的后面部分,我们将讨论如何在 Truffle 框架内编写测试,以及我们如何在dApp中添加前端,以便用户可以在公共网络上与我们的智能合约进行交互!引言
发表回复