Hello World投票以太坊Dapp教程-Part1
这是一个非常简单的应用程序,只需要初始化一组参赛者,任何人都可以给候选人投票,并显示每位候选人收到的总票数。
我们的目标不是只编写一个应用程序,而是学习编译,部署和与之交互的过程。
我故意避免使用任何dapp框架来构建这个应用程序,因为框架抽象掉了很多细节,不利于理解系统的内部结构。不过当你使用框架时,你将更加感激框架为您所做的所有繁重工作!
这个练习的目标是:
- 建立开发环境
- 了解编写合同,编译并将其部署到开发环境中的过程。
- 通过nodejs控制台与区块链上的合约进行交互。
- 通过一个简单的网页与合约进行交互。
系统示意图如下:
1.搭建开发环境
我们将使用内存区块链(将其视为区块链模拟器)——ganache,而不是真的区块链开发应用程序。在Part2,我们将使用真的区块链。
以下是在Linux操作系统上安装ganache,web3js和启动测试区块链的步骤。
czk@czk-vm:~$ npm -v
6.1.
czk@czk-vm:~$ node -v
v8.11.2
czk@czk-vm:~$ sudo apt-get install build-essential python
czk@czk-vm:~$ cd work/
czk@czk-vm:~/work$ mkdir hello_world_voting
czk@czk-vm:~/work$ cd hello_world_voting
czk@czk-vm:~/work/hello_world_voting$ mkdir node_modules
czk@czk-vm:~/work/hello_world_voting$ npm install ganache-cli
czk@czk-vm:~/work/hello_world_voting$ npm install web3@0.20.6
czk@czk-vm:~/work/hello_world_voting$ node_modules/.bin/ganache-cli
ganache-cli会创建10个测试帐户,这些帐户预村了100个(假的)Eth。
(以上为局部安装,关于npm 与node_modules, 见https://www.runoob.com/nodejs/nodejs-npm.html)
2. 简单的投票合约
我们使用Solidity语言来编写智能合约。我们将编写2种方法,一种是返回候选人收到的总票数,另一种方法是增加候选人的投票数。
注意:当您将合约部署到区块链时,构造函数只会被调用一次。与在Web中,新部署代码会覆盖旧代码不同,区块链中部署的代码是不可修改的。
如果您更新合约并再次进行部署,旧合约仍会保留在区块链中,并保留其中的所有数据,新的部署将创建一个新的合约实例。
以下是投票合约代码:
pragma solidity^0.4.18;
// We have to specify what version of compiler this code will compile with contract Voting {
mapping(bytes32 => uint8) public votesReceived; /* Solidity doesn't let you pass in an array of strings in the constructor (yet).
We will use an array of bytes32 instead to store the list of candidates
*/
bytes32[] public candidateList; /* This is the constructor which will be called once when you
deploy the contract to the blockchain. When we deploy the contract,
we will pass an array of candidates who will be contesting in the election
*/
constructor (bytes32[] candidateNames) public {
candidateList = candidateNames;
} // This function returns the total votes a candidate has received so far
function candidateVotes(bytes32 candidate) public view returns(uint8) {
require(_candidateValidation(candidate), "Invalid candidate.");
return votesReceived[candidate];
} // This function increments the vote count for the specified candidate. This
// is equivalent to casting a vote
function VoteToCandidate(bytes32 candidate) public {
require(_candidateValidation(candidate), "Invalid candidate.");
votesReceived[candidate]++;
} // This function check the validity of input candidate.
function _candidateValidation(bytes32 candidate) private view returns(bool) {
for(uint i = 0; i < candidateList.length; ++i) {
if(candidateList[i] == candidate)
return true;
}
return false;
}
}
将以上代码复制到Voting.sol文件中,并将该文件置于hello_world_voting目录下。现在让我们编译代码并将其部署到ganache区块链。
为了编译Solidity代码,需要安装npm模块solc:
czk@czk-vm:~/work/hello_world_voting$ npm install solc
+ solc@0.4.
我们将在节点控制台内使用这个库来编译我们的合同。
web3js是一个库,可让您通过RPC与区块链进行交互。我们将使用该库来部署我们的应用程序并与其进行交互。
首先,在终端中运行'node'命令以进入节点控制台并初始化solc和web3对象。下面的所有代码片段都需要在节点控制台中输入。
czk@czk-vm:~/work/hello_world_voting$ node
> Web3 = require('web3')
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost::8545"));
为了确保web3对象被初始化并且可以与区块链进行通信,我们来查询区块链中的所有帐户。你应该看到如下结果:
将Voting.sol中的代码加载到字符串变量中并进行编译。
> code = fs.readFileSync('Voting.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)
当成功编译代码并打印'contract'对象(只需在node控制台中键入compiledCode)时,其中有两个重要的字段:
1. compiledCode.contracts[‘:Voting’].bytecode: 这是在编译Voting.sol中的源代码时获得的字节码。这是会被部署到区块链的代码。
2. compiledCode.contracts[‘:Voting’].interface: 这是合约的接口或模板(称为abi, Application Binary Interface),它告诉合约用户合约中有哪些方法可用。无论何时需要与合同进行交互,都需要此abi。
现在我们来部署合约。您首先创建一个合约对象(下面的VotingContract),用于在区块链中部署和启动合约。
> abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
> VotingContract = web3.eth.contract(abiDefinition)
> byteCode = compiledCode.contracts[':Voting'].bytecode
> deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[], gas: })
> deployedContract.address
> contractInstance = VotingContract.at(deployedContract.address)
上面的VotingContract.new将合约部署到区块链。我们现在已经部署了合约,并且有一个合约实例(上面的可变contractInstance),我们可以使用它来与合约进行交互。在区块链上部署了数十万个合约。那么,你如何在区块链中识别你的合约呢?答案:deployedContract.address。
当与的合约进行交互时,需要合约部署地址和合约的abi。
3. 在nodejs控制台中与合约进行交互
4. 通过网页与区块链上的合约交互
现在大部分工作都已完成,现在我们所要做的就是创建一个带候选人名字的简单html文件,并在js文件中调用投票命令(我们已经在nodejs控制台中测试过)。 以下是index.html文件和index.js代码,将它们都放在hello_world_voting目录中,然后在浏览器中打开index.html。
<!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 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>
<input type="text" id="candidate" />
<a href="#" onclick="VoteToCandidate()" 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="./index.js"></script>
</html>
注:以上代码运行时,可能会出现无法连接到网站错误。在虚拟机中无法打开这个网页,但是在windows中浏览器中可以打开。。。。将该网页中的js代码保存为web3.js文件,放入工作index.html同一目录,将37行改为 如下代码即可。
<script src="./web3.js"></script>
index.js:
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
abi = JSON.parse('[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"candidateVotes","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"VoteToCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]')
VotingContract = web3.eth.contract(abi);
// In your nodejs console, execute contractInstance.address to get the address at which the contract is deployed and change the line below to use your deployed address
contractInstance = VotingContract.at('0x5367391364f427209e5f08acd260f21abb15ba30');
candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"} function VoteToCandidate() {
candidateName = $("#candidate").val();
contractInstance.VoteToCandidate(candidateName, {from: web3.eth.accounts[0]}, function() {
let div_id = candidates[candidateName];
$("#" + div_id).html(contractInstance.candidateVotes.call(candidateName).toString());
});
} $(document).ready(function() {
candidateNames = Object.keys(candidates);
for (var i = 0; i < candidateNames.length; i++) {
let name = candidateNames[i];
let val = contractInstance.candidateVotes.call(name).toString()
$("#" + candidates[name]).html(val);
}
});
用浏览器打开index.html文件,你将看到一下内容。
如果您可以在文本框中输入候选人姓名并进行投票,可以看到查看投票计数增加,那么您已经成功创建了第一个应用程序!恭喜!
总结一下,本文设置了开发环境,编写简单的合同,在区块链上编译和部署合同,并通过nodejs控制台和网页与其交互。
在Part2部分,我们将把这个合同部署到公共测试网络,以便全世界都可以看到它并投票给候选人。并使用Truffle框架进行开发(而不必使用nodejs控制台来管理整个过程)。
Hello World投票以太坊Dapp教程-Part1的更多相关文章
- 智能合约开发——以太坊 DApp 实现 购买通证token
合约的buy()方法用于提供购买股票的接口.注意关键字payable,有了它买股票的人才可以付钱给你. 接收钱没有比这个再简单的了! function buy() payable public ret ...
- 链上链下交互 以太坊Dapp接口开发
主要是指的是用NodeJs调用 提供接口供前端使用 用户查询和转账 以太坊Dapp项目 众筹项目 功能需求 路人 查看所有众筹项目, 2 @ OK 根据众筹项目的address获取该众筹的详情 (参与 ...
- 以太坊开发教程(二) 利用truffle发布宠物商店 DAPP 到 以太坊测试环境Ropsten
1.环境安装 1) node安装 设置镜像地址: curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -下载安装 ...
- 关于书籍《区块链以太坊DApp开发实战》的内容告示
书中所列举的以太坊 etherscan 浏览器,原链接已经不能使用国内网络正常访问了,需要翻墙,下面的链接不需要翻墙,也是 etherscan 的官方浏览器链接: 以太坊浏览器:https://cn. ...
- 部署开发以太坊dapp的四种方式
我们已经学习了4种开发和部署智能合约的方法: 第1种是使用 Truffle 和 Ganache .由于我们从上一篇教程中复制了代码,所以我想告诉你,有些插件可用于目前最流行的文本编辑器和 IDEs.有 ...
- 以太坊开发教程(一) truffle框架简介/安装/使用
通常一个DAPP的开发包括两部分:智能合约的开发和提供合约进行调用的前端页面. truffle提供了对这两部分内容比较简单的开发方式,特别是在开发/测试阶段.给开发人员提供快捷的打包/部署,已经本地服 ...
- 以太坊(ethereum)开发DApp应用的入门区块链技术教程
概述 对初学者,首先要了解以太坊开发相关的基本概念. 学习以太坊开发的一般前序知识要求,最好对以下技术已经有一些基本了解: 一种面向对象的开发语言,例如:Python,Ruby,Java... 前 ...
- 如何从零开始学习区块链技术——推荐从以太坊开发DApp开始
很多人迷惑于区块链和以太坊,不知如何学习,本文简单说了一下学习的一些方法和资源. 一. 以太坊和区块链的关系 从区块链历史上来说,先诞生了比特币,当时并没有区块链这个技术和名词,然后业界从比特币中提取 ...
- 智能合约开发solidity编程语言开发一个以太坊应用区块链投票实例
智能合约开发用solidity编程语言部署在以太坊这个区块链平台,本文提供一个官方实战示例快速入门,用例子深入浅出智能合约开发,体会以太坊构建去中心化可信交易技术魅力.智能合约其实是"执行合 ...
随机推荐
- 洛谷 - P2158 - 仪仗队 - 欧拉函数
https://www.luogu.org/problemnew/show/P2158 好像以前有个妹子收割铲也是欧拉函数. 因为格点直线上的点,dx与dy的gcd相同,画个图就觉得是欧拉函数.但是要 ...
- bzoj 3559: [Ctsc2014]图的分割【最小生成树+并查集】
读题两小时系列-- 在读懂题意之后,发现M(c)就是c这块最大权割边也就是的最小生成树的最大权边的权值,所以整个问题都可以在MST的过程中解决(M和c都是跟着并查集变的) 不过不是真的最小生成树,是合 ...
- SpringBlade 2.0-RC3 发布,全新的微服务开发平台
经过了十天的艰苦奋斗,SpringBlade 2.0-RC3发布了,此版本增加了很多有用的功能,距离正式版本更近一步! SpringBlade简介: SpringBlade 2.0 是一个基于 Spr ...
- Log4j2 - java.lang.NoSuchMethodError: com.lmax.disruptor.dsl.Disruptor
问题 项目使用了log4j2,由于使用了全局异步打印日志的方式,还需要引入disruptor的依赖,最后使用的log4j2和disruptor的版本依赖如下: <dependency> & ...
- Yac - PHP扩展
1:首先你要安装Git [root@localhost]# git clone https://github.com/laruence/yac 2:进入yac目录进行配置 [root@localhos ...
- github添加版本号
1.将官方的库clone下来 http://github.com/xxx.xxx.git 2.修改要修改的地方 3.git add src 4.commit -m 'xxx' 5.git push ...
- js操作表格
js 操作table: insertRow(),deleteRow(),insertCell(),deleteCell()方法 表格有几行: var trCnt = table.rows.length ...
- JAVA常用知识总结(十三)——数据库(三)
Mysql的主键选择(主键自增,UUID,snowflake)? 使用自增长做主键的优点:1.很小的数据存储空间2.性能最好3.容易记忆使用自增长做主键的缺点:1.如果存在大量的数据,可能会超出自增长 ...
- 109 Convert Sorted List to Binary Search Tree 有序链表转换二叉搜索树
给定一个单元链表,元素按升序排序,将其转换为高度平衡的BST.对于这个问题,一个高度平衡的二叉树是指:其中每个节点的两个子树的深度相差不会超过 1 的二叉树.示例:给定的排序链表: [-10, -3, ...
- vue echarts 大小自适应
窗口大小时候 ,echarts图自适应 在创建图表的方法中直接,用resize方法 let myChart=this.$refs.myChart; let mainChart = echarts.in ...