主页 > imtoken钱包苹果版价值 > 以太坊区块链使用NodeJs和Web3开发投票DApp

以太坊区块链使用NodeJs和Web3开发投票DApp

imtoken钱包苹果版价值 2023-10-29 05:10:04

为什么80%的码农不能成为架构师? >>>

hot3.png

1、开发完成后,页面预览如下

基于以太坊的区块链_以太坊区块浏览器api_以太坊能表现出区块链的

用户可以查看当前参与投票的候选人名单和各自当前的得票数,选择其中一位进行投票,被投票者的票数将相应增加。

2. 开发准备 3. 编写智能合约

创建一个工作目录Voting-Node,在该目录下新建一个Voting.sol智能合约文件,并在Remix中编辑该文件。 编辑后的文件内容如下:

pragma solidity ^0.4.18;
contract Voting {
  mapping (bytes32 => uint8) public votesReceived;
  bytes32[] public candidateList;
  constructor (bytes32[] candidateNames) public {
    candidateList = candidateNames;
  }
  function totalVotesFor(bytes32 candidate) view public returns (uint8) {
    require(validCandidate(candidate));
    return votesReceived[candidate];
  }
  function voteForCandidate(bytes32 candidate) public {
    require(validCandidate(candidate));
    votesReceived[candidate]  += 1;
  }
  function validCandidate(bytes32 candidate) view public returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i] == candidate) {
        return true;
      }
    }
    return false;
   }
}

4. 编译、部署、测试智能合约

在Voting-Node目录下打开命令行,输入node命令进入REPL环境,一步步执行编译部署命令。 但是这种方法比较麻烦以太坊区块浏览器api,不方便维护和修改。 直接写在Voting-Node目录下。 一个编译、部署、测试的depoy.js文件,可以直接在Nodejs中运行查看结果。 内容如下:

//引入web3模块
let Web3 = require('web3');
//初始化 web3
let web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:7545"));
//输出初始化结果
console.log('Initialization web3 complete,the first account is '+ web3.eth.accounts[0]);
let fs = require('fs');

以太坊区块浏览器api_以太坊能表现出区块链的_基于以太坊的区块链

let code = fs.readFileSync('Voting.sol').toString(); let solc = require('solc'); //编译合约为ABI文件 let compiledCode = solc.compile(code); console.log('Compile Voting.sol complete'); //部署合约至区块链节点 let abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface); //写入ABI文件至本地文件目录 fs.writeFile('Voting.json',JSON.stringify(abiDefinition), {}, function(err) { console.log('write ABI file [Voting.json] complete . '); }); let VotingContract = web3.eth.contract(abiDefinition); let byteCode = compiledCode.contracts[':Voting'].bytecode; //调用VotingContract对象的new()方法来将投票合约部署到区块链。new()方法参数列表应当与合约的 构造函数要求相一致。对于投票合约而言,new()方法的第一个参数是候选人名单。 let deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000}); //输出合约 地址,如果此处没有返回地址,可以在Ganache日志中查看到 console.log('deploy complete,deploy address is '+ deployedContract.address); //let contractInstance = VotingContract.at(deployedContract.address); let contractInstance = VotingContract.at('0x99bdfb1f4c5d0c227d6cd98cf7a254bfc27c35cc'); //测试合约调用 contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Nick', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Jose', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Jose', {from: web3.eth.accounts[0]}); console.log("--------------finish----------------"); let RamaVote=contractInstance.totalVotesFor.call('Rama'); let NickVote=contractInstance.totalVotesFor.call('Nick'); let JoseVote=contractInstance.totalVotesFor.call('Jose'); console.log("Rama's vote is "+RamaVote); console.log("Nick's vote is "+NickVote); console.log("Jose's vote is "+JoseVote);

执行结果如下:

PS C:\Workspace\Ruoli-Code\Eth-Node> node .\deploy.js
Initialization web3 complete,the first account is 0xa0b4360847bfe6c45f78103e97678dfa79aa9975
Compile Voting.sol complete
deploy complete,deploy address is undefined
--------------finish----------------
Rama's vote is 3
Nick's vote is 1
Jose's vote is 2

以太坊区块浏览器api_基于以太坊的区块链_以太坊能表现出区块链的

write ABI file complete .

最终结果如预期,说明测试调用成功。

如果部署出现问题:TypeError: web3.eth.contract is not a function

需要安装web3 0.19版本,命令如下:

npm install web3@^0.19.0 --保存

安装完成后,问题得到解决。

5.网页交互

完成以上编写、编译、部署、测试等步骤后,添加网页交互就非常简单了。

在Voting-Node目录下打开命令行,执行初始化命令,如下:

npm init -y

该目录下会生成一个package.json文件,修改该文件内容如下:

{
  "name": "Voting-Node",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "solc": "^0.4.23",
    "web3": "^0.19.0"
  },
  "devDependencies": {},
  "scripts": {
    "dev": "node index.js"
  },
  "keywords": [],
  "author": "Ruoli",
  "license": "ISC"
}

在该目录下新建index.js、index.html、app.js文件以太坊区块浏览器api,如下图。

index.js的内容如下:

var http = require('http');
var fs = require('fs');
var url = require('url');
// 创建服务器
http.createServer( function (request, response) {  
   // 解析请求,包括文件名
   var pathname = url.parse(request.url).pathname;
   // 输出请求的文件名
   console.log("Request for " + pathname + " received.");
   // 从文件系统中读取请求的文件内容
   fs.readFile(pathname.substr(1), function (err, data) {
      if (err) {
         console.log(err);
         // HTTP 状态码: 404 : NOT FOUND

以太坊能表现出区块链的_以太坊区块浏览器api_基于以太坊的区块链

// Content Type: text/plain response.writeHead(404, {'Content-Type': 'text/html'}); }else{ // HTTP 状态码: 200 : OK // Content Type: text/plain response.writeHead(200, {'Content-Type': 'text/html'}); // 响应文件内容 response.write(data.toString()); } // 发送响应数据 response.end(); }); }).listen(3000); // 控制台会输出以下信息 console.log('Server running at http://127.0.0.1:3000/index.html');   

index.html的内容如下:




    
 Voting DApp
  
  
  


 

简易投票 DApp

以太坊能表现出区块链的_以太坊区块浏览器api_基于以太坊的区块链

app.js的内容如下:

注意:这里需要导入之前保存的ABI文件的内容。

let web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
//导入合约的ABI文件
let abi = JSON.parse('[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","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"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]')
let VotingContract = web3.eth.contract(abi);
let contractInstance = VotingContract.at('0x99bdfb1f4c5d0c227d6cd98cf7a254bfc27c35cc');
let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
$(document).ready(function() {
	//初始化余额
	candidateNames = Object.keys(candidates);
 	for (var i = 0; i < candidateNames.length; i++) {
  		let name = candidateNames[i];
  		let val = contractInstance.totalVotesFor.call(name).toString()
  		$("#"+candidates[name]).html(val);
 	}
 	//初始化事件
 	$(".vote-btn").click(function(){
 		//获取投票人名称
 		let voteName=$(this).prev().prev().text();
 		contractInstance.voteForCandidate(voteName, {from: web3.eth.accounts[0]}, function() {
		   let div_id = candidates[voteName];
		   let vote_num=contractInstance.totalVotesFor.call(voteName).toString();
		   $("#"+div_id).fadeOut(400);
		   $("#"+div_id).html(vote_num).fadeIn(800);
		});
 	});
});

至此所有的开发都已经完成。

6.网页访问及测试

执行以下命令启动服务:

PS C:\Workspace\Ruoli-Code\Voting-Node> npm run dev
> Voting-Node@1.0.0 dev C:\Workspace\Ruoli-Code\Voting-Node
> node index.js
Server running at http://127.0.0.1:3000/index.html

执行完成后,在浏览器中访问::3000/index.html

可以看到初始界面,至此所有开发完成。