低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

以太坊 Dapp 入门实战之同步到区块链

2018 年 11 月 23 日

以太坊Dapp入门实战之同步到区块链

在本教程的第一篇文章中,我们用 ganache 配置了开发环境,并在其中搭建了一个简单的投票程序。接下来我们要把这个程序放到真正的区块链上。以太坊有几个公开的测试链和一个主链。


  1. Testnet: Ropsten、Rinkeby、Kovan 都是测试链。你可以把它们当作 QA 或临时服务器,只用于测试。在这些网络上不需要使用真正的以太币。

  2. Mainnet (又叫 Homestead):所有的真实交易都发生在这个区块链上。在这个网络中必须使用真正的以太币。


这个教程要完成如下几项任务:


  1. 安装 geth — 用来下载区块链的客户端软件,在你的机器上运行以太坊节点的也是它。

  2. 安装以太坊 Dapp 框架 Truffle(http://truffleframework.com/),用于编译和部署我们的合约。

  3. 对之前的投票程序做简单的修改,使之可以使用 truffle。

  4. 编译合约并将其部署到 Rinkeby 测试网络上。

  5. 通过 truffle 控制台与合约交互,然后实现网页与合约的交互。


1.安装 geth,同步区块链

我在 MacOS 和 Ubuntu 上都做了安装和测试。安装很简单


在 Mac 上:


mahesh@projectblockchain:~$ brew tap ethereum/ethereummahesh@projectblockchain:~$ brew install ethereum
复制代码


在 Ubuntu 上:


mahesh@projectblockchain:~$ sudo apt-get install software-properties-commonmahesh@projectblockchain:~$ sudo add-apt-repository -y ppa:ethereum/ethereummahesh@projectblockchain:~$ sudo apt-get updatemahesh@projectblockchain:~$ sudo apt-get install ethereum
复制代码


后面这个链接里有各种平台上的安装指南: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum


安装好 geth 之后,在命令行控制台中运行下面这条命令:


mahesh@projectblockchain:~$ geth --rinkeby --syncmode "fast" --rpc --rpcapi db,eth,net,web3,personal --cache=1024  --rpcport 8545 --rpcaddr 127.0.0.1 --rpccorsdomain "*"
复制代码


这条命令会启动以太坊节点,连接网络中的对等节点并开始下载区块链。下载时长取决于多个因素,比如网络连接速度,电脑上的 RAM,硬盘类型等。我在一台 8GB RAM 和 50Mbps 连接的机器上用了大概 30~45 分钟。


在运行 geth 的控制台里,你会看到下面这样的输出。找到粗体的区块号。当区块链完全同步时,区块链应该接近这个页面的区块号: https://rinkeby.etherscan.io/


I0130 22:18:15.116332 core/blockchain.go:1064] imported 32 blocks, 49 txs ( 6.256 Mg) in 185.716ms (33.688 Mg/s). #445097 [e1199364… / bce20913…]

I0130 22:18:20.267142 core/blockchain.go:1064] imported 1 blocks, 1 txs ( 0.239 Mg) in 11.379ms (20.963 Mg/s). #445097 [b4d77c46…]

I0130 22:18:21.059414 core/blockchain.go:1064] imported 1 blocks, 0 txs ( 0.000 Mg) in 7.807ms ( 0.000 Mg/s). #445098 [f990e694…]

I0130 22:18:34.367485 core/blockchain.go:1064] imported 1 blocks, 0 txs ( 0.000 Mg) in 4.599ms ( 0.000 Mg/s). #445099 [86b4f29a…]

I0130 22:18:42.953523 core/blockchain.go:1064] imported 1 blocks, 2 txs ( 0.294 Mg) in 9.149ms (32.136 Mg/s). #445100 [3572f223…]


2.安装 Truffle 框架

用 npm 安装 truffle,本教程中用的是 3.1.1 版。


npm install -g truffle
复制代码


注意:根据系统的配置,你可能需要在这个命令的开头加上sudo


3. 设置投票合约

首先要创建 truffle 项目:


mahesh@projectblockchain:~$ mkdir votingmahesh@projectblockchain:~$ cd votingmahesh@projectblockchain:~/voting$ npm install -g webpackmahesh@projectblockchain:~/voting$ truffle unbox webpackmahesh@projectblockchain:~/voting$ lsREADME.md               contracts               node_modules            test                    webpack.config.js       truffle.jsapp                     migrations              package.json            mahesh@projectblockchain:~/voting$ ls app/index.html  javascripts  stylesheetsmahesh@projectblockchain:~/voting$ ls contracts/ConvertLib.sol  MetaCoin.sol  Migrations.solmahesh@projectblockchain:~/voting$ ls migrations/1_initial_migration.js  2_deploy_contracts.js
复制代码


如上所示,truffle 会创建运行全栈 dapp 所必需的文件和目录。Truffle 还创建了一个样本程序,可以作为基础进行修改调整。我们不用它,所以可以删掉 contracts 目录下的 ConvertLib.sol 和 MetaCoin.sol 文件。


一定要搞明白 migrations 目录中的内容。这些迁移文件是用来把合约部署到区块链上的。(如果你还记得,我们在上一篇文章中是用 VotingContract.new 把合约部署到区块链上的,这次不用那么做了)。第一个迁移文件 1_initial_migration.js 会将一个名为 Migrations 的合约部署到区块链上,用来存放你部署的最新合约。每次运行 migration,truffle 都会查询区块链,获取部署过的最新合约,然后将还没部署的合约部署上去。然后更新 Migrations 合约中的 last_completed_migration 域,以指明部署好的最新合约。你可以把它看做一个名为 Migration 的数据库表,有一个永远保持最新状态的 last_completed_migration 域。详细信息请参考truffle文档


接下来我们要把上篇文章中写的代码改一下。


首先将 Voting.sol 复制到 contracts 目录下(这个文件不用改)。


mahesh@projectblockchain:~/voting$ ls contracts/Migrations.sol  Voting.sol
复制代码


然后打开 migrations 目录下的 2_deploy_contracts.js 文件,换成下面的代码:


var Voting = artifacts.require("./Voting.sol");module.exports = function(deployer) {  deployer.deploy(Voting, ['Rama', 'Nick', 'Jose'], {gas: 6700000});};/* 如上所示,部署器的第一个参数是合约的名称,第二个参数是要传给构造器的参数。就这个例子而言,构造器只有一个参数,即包含候选项的数组。第三个参数是哈希表,指定为部署代码提供的燃料。燃料多少取决于合约的大小。*/
复制代码


燃料值也可以在 truffle.js 中设定。打开 truffle.js,像下面的代码这样设定全局参数 gas。这样即便将来忘了在哪个迁移文件中设定 gas,它也会用这个全局参数作为燃料的默认值。


require('babel-register')module.exports = {  networks: {    development: {      host: 'localhost',      port: 8545,      network_id: '*',      gas: 470000    }  }}
复制代码


将 app/javascripts/app.js 中的代码换成下面的代码。


// 引入页面的CSS。Webpack知道该怎么做。import "../stylesheets/app.css";
// 引入我们需要的库import { default as Web3} from 'web3';import { default as contract } from 'truffle-contract'
/* * 在编译和部署Voting合约时,truffle会将abi和部署地址 * 存在build目录下的json文件中。我们会用这个信息设置 * Voting抽象。之后会用这个抽象创建Voting合约的实例。 * 可以跟我们之前那篇文章中的index.js文件比较一下有什么差异 * https://gist.github.com/maheshmurthy/f6e96d6b3fff4cd4fa7f892de8a1a1b4#file-index-js */
import voting_artifacts from '../../build/contracts/Voting.json'
var Voting = contract(voting_artifacts);
let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
window.voteForCandidate = function(candidate) { let candidateName = $("#candidate").val(); try { $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.") $("#candidate").val("");
/* Voting.deployed()返回合约的实例。在Truffle中 * 每次都会返回一个promise,所以有交易调用的地方 * 都要用then() */ Voting.deployed().then(function(contractInstance) { contractInstance.voteForCandidate(candidateName, {gas: 140000, from: web3.eth.accounts[0]}).then(function() { let div_id = candidates[candidateName]; return contractInstance.totalVotesFor.call(candidateName).then(function(v) { $("#" + div_id).html(v.toString()); $("#msg").html(""); }); }); }); } catch (err) { console.log(err); }}
$( document ).ready(function() { if (typeof web3 !== 'undefined') { console.warn("Using web3 detected from external source like Metamask") // 用Mist/MetaMask的provider window.web3 = new Web3(web3.currentProvider); } else { console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask"); // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail) window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); }
Voting.setProvider(web3.currentProvider); let candidateNames = Object.keys(candidates); for (var i = 0; i < candidateNames.length; i++) { let name = candidateNames[i]; Voting.deployed().then(function(contractInstance) { contractInstance.totalVotesFor.call(name).then(function(v) { $("#" + candidates[name]).html(v.toString()); }); }) }});
复制代码


用下面的代码换掉 app/index.html 中的代码。这里的代码跟上一篇文章中的代码几乎一样,只是第 41 行引入的 js 文件是 app.js。


<!DOCTYPE html><html><head>  <title>Hello World DApp</title>  <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'></head><body class="container">  <h1>A Simple Hello World Voting Application</h1>  <div id="address"></div>  <div class="table-responsive">    <table class="table table-bordered">      <thead>        <tr>          <th>Candidate</th>          <th>Votes</th>        </tr>      </thead>      <tbody>        <tr>          <td>Rama</td>          <td id="candidate-1"></td>        </tr>        <tr>          <td>Nick</td>          <td id="candidate-2"></td>        </tr>        <tr>          <td>Jose</td>          <td id="candidate-3"></td>        </tr>      </tbody>    </table>    <div id="msg"></div>  </div>  <input type="text" id="candidate" />  <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a></body><script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script><script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script><script src="app.js"></script></html>
复制代码


4. 将合约部署到 Rinkeby 测试网络

在部署合约之前,我们还需要一个账号和一些以太币。在用 ganache 时,它会创建 10 个测试账号,每个都有 100 个测试币。但用测试网络和主网时,我们只能自己创建账号,自己存以太币。


在命令行终端中执行下面这些命令:


mahesh@projectblockchain:~/voting$ truffle consoletruffle(default)> web3.personal.newAccount('verystrongpassword')'0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1'truffle(default)> web3.eth.getBalance('0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1'){ [String: '0'] s: 1, e: 0, c: [ 0 ] }truffle(default)> web3.personal.unlockAccount('0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1', 'verystrongpassword', 15000)// 将'verystrongpassword'换成真正的好密码。// 账户默认是锁着的,在用于部署和跟区块链交互之前,要确认一下已经解锁了。
复制代码


在上一篇文章中,我们启动 node 控制台初始化了一个 web3 对象。而 truffle 控制台会帮我们做好所有事情,所以我们会得到一个可用的 web3 对象。一个地址为‘0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1’ 的账号(当然,你会有自己的地址),初始余额为 0。


你可以在 faucet(https://faucet.rinkeby.io/) 申请一些 Rinkeby 网络的测试币。再试着运行一下web3.eth.getBalance,确保你得到了自己申请的以太币。如果你在 rinkeby.etherscan.io 上看到的余额不是 0,而web3.eth.getBalance返回的结果依然是 0,这说明你的本地区块链还没完成同步,你只需要等着它完成同步。


有了以太币,你可以继续了,编译合约,把它部署到区块链上。下面是你要运行的命令,以及,如果一切顺利的话,应有的输出。


再次提醒:别忘了在部署合约前解锁你的账号。


mahesh@projectblockchain:~/voting\$ truffle migrate

Compiling Migrations.sol…

Compiling Voting.sol…

Writing artifacts to ./build/contracts

Running migration: 1_initial_migration.js

Deploying Migrations…

Migrations: 0x3cee101c94f8a06d549334372181bc5a7b3a8bee

Saving successful migration to network…

Saving artifacts…

Running migration: 2_deploy_contracts.js

Deploying Voting…

Voting: 0xd24a32f0ee12f5e9d233a2ebab5a53d4d4986203

Saving successful migration to network…

Saving artifacts…

mahesh@projectblockchain:~/voting$


在我的机器上,部署这个合约大概用了 70–80 秒。


5. 与投票合约交互

如果可以成功部署合约,现在应该可以通过 truffle 控制台进行投票和获取票数信息了。


mahesh@projectblockchain:~/voting$ truffle consoletruffle(default)> Voting.deployed().then(function(contractInstance) {contractInstance.voteForCandidate('Rama').then(function(v) {console.log(v)})})// 几秒钟之后,应该可以见到下面这样的交易收据:{ blockHash: '0x7229f668db0ac335cdd0c4c86e0394a35dd471a1095b8fafb52ebd7671433156',blockNumber: 469628,contractAddress: null,........truffle(default)> Voting.deployed().then(function(contractInstance) {contractInstance.totalVotesFor.call('Rama').then(function(v) {console.log(v)})}){ [String: '1'] s: 1, e: 0, c: [ 1] }
复制代码


如果你可以这样做,说明合约已经部署成功,开始发挥作用了!继续前进,启动服务器:


mahesh@projectblockchain:~/voting$ npm run dev
复制代码


你应该可以在 localhost:8080 上看到投票页面,能在这个页面上投票,见到所有候选项的票数。既然这次是真正的区块链,每次写入(voteForCandidate)都要花几秒钟(矿机必须把你的交易放到区块中,并将这个区块添加到区块链上)。



如果能看到这个页面,并且可以投票,说明你刚在公共测试链上搭建了自己的第一个完整的以太坊应用程序,恭喜你!


既然所有交易都是公开的,所以你可以在这里看到它们:https://rinkeby.etherscan.io/。 只要输入你的账号地址,就能看到你的所有交易。


希望你按照教程成功完成了这个应用。所有代码都放在了 github 的这个代码库里。


2018 年 11 月 23 日 14:321137

评论 1 条评论

发布
暂无评论
发现更多内容

如何在Python中实现Round函数?

华为云开发者社区

Python 函数 Numpy Round 舍入函数

Python OpenCV 图像处理二值化,取经之旅第 7 天

梦想橡皮擦

3月日更

寻找被遗忘的勇气(二十三)

Changing Lin

3月日更

NA公链(Nirvana)NAC公链独步公链江湖

区块链第一资讯

区块链

图像视频压缩:深度学习,有一套

华为云开发者社区

深度学习 自编码器 图像压缩 循环神经网络 视频压缩

Java学习笔记——实体类(ENTITY,VO,DTO,BO)

棉花糖

Java

AIOT技术大起底:别人开发“软件”,海尔智家开发“生活”

DT极客

万众瞩目的EGG Network,备受期待的New-DeFi自治共识论坛在海口闭幕

币圈那点事

区块链

一文搞懂Flink SQL执行过程

shengjk1

flink flink源码 flink sql flink sql 执行过程

JVM G1GC的算法与实现

Yano

Java JVM GC G1GC

Flink 计算 TopN

shengjk1

flink flink 实战 flink topN

C语言性能优化:减少相关性依赖,利用指令并行提升性能

一笑置之

编程 性能优化 C语言 cpu 100%

实践解析丨Rust 内置 trait:PartialEq 和 Eq

华为云开发者社区

rust hash Trait PartialEq Eq

Veema 寄来的新书

吴威

vmware 容灾 备份 veeam esxi

一文搞懂 FlinkSQL 的 KafkaSource

shengjk1

flink flink源码 flink sql

一文搞懂 Flink 中的锁

shengjk1

flink flink 锁

【IstioCon 2021】如何在Istio中进行源地址保持?

华为云原生团队

开源 云原生 istio 华为云 服务网格

人工智能能和人类辩论了;《云网产业发展白皮书》发布

京东科技开发者

人工智能

一文搞懂 FlinkSQL函数 LAST_VALUE 的原理

shengjk1

flink flink sql flink 源码

适配器模式在Mybatis中的妙用

Java小咖秀

Java 源码 设计模式 mybatis 开发

带你全面认识CMMI V2.0(三)——实践域

渠成CMMI

CMMI

上帝视角掌管城市动向!智慧园区驱动城市数字化转型

一只数据鲸鱼

物联网 数据可视化 智慧城市 智慧园区

Flink 计算 PV UV

shengjk1

flink flink 实战

Dubbo的设计理念原来就藏在这三张图中

中间件兴趣圈

dubbo RPC

通过Adobe国际认证!让艺术成为职业,把未来掌握在手中

Adobe国际认证

企业数字化转型,营销技术驱动超级增长!

博文视点Broadview

智慧平安社区综合管理系统开发,江西赣州老旧小区改造解决方案

WX13823153201

java deep vs shallow copies

shengjk1

Java deep copy shallow cop

Flink 提交作业运行的各种模式总结

shengjk1

flink flink 执行

快速使用Vue3最新的15个常用API(1W5+字详解,建议收藏)

零一

vue.js 前端 Vue3

FlinkSQL 平台

shengjk1

flink flink sql flink sql 平台

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

以太坊Dapp入门实战之同步到区块链-InfoQ