[以太坊dApp全栈开发教程]Truffle:1.智能合约的编译与部署

[以太坊dApp全栈开发教程]Truffle:1.智能合约的编译与部署

引言

在本系列的前面部分,我们了解了在本地开发区块链时,怎样部署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中添加前端,以便用户可以在公共网络上与我们的智能合约进行交互!引言

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注