区块链实验十 DAPP开发

转载自DAPP开发

实验内容

1.工具安装,在虚拟机中安装Nodejs和npm

首先安装curl

sudo apt install curl

在这里插入图片描述
安装nodejs

curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -

在这里插入图片描述
执行安装指令:

sudo apt-get install -y nodejs

这里我没有报错,如果有的报了这种无法获得锁的错

E: 无法获得锁 /var/lib/dpkg/lock。锁正由进程 69782(unattended-upgr)持有
N: 请注意,直接移除锁文件不一定是合适的解决方案,且可能损坏您的系统。
E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?

只需要执行指令删除报错的文件夹名即可

sudo rm /var/lib/dpkg/lock

然后就可以重新执行安装指令(其他报同样错误的地方也可以使用这个方法)

sudo apt-get install -y nodejs

然后输入node -v 查看安装完成的node的版本
在这里插入图片描述

2.模拟环境ganache-安装

由于访问npm网站会比较慢,所以先切换源:

npm config set registry http://registry.npm.taobao.org

在根目录下建一个项目文件夹mkdir simple_vote
进入文件夹cd simple_vote
输入npm init一直按回车键
在这里插入图片描述
再输入ls就可以看到在项目文件夹下出现了一个package.json文件
在这里插入图片描述
安装web3(必须是0.20.7版本的,不然后面无法运行.isConnected()

npm install web3@0.20.7

在这里插入图片描述
这里安装web3的时候可能会报错,我是装了一个git之后解决的
可以参考一下这个Ubuntu 18.04上安装使用Git
装完Git之后,再重新运行web3安装指令,就不会报错了

然后安装ganache-cli

npm install ganache-cli

在这里插入图片描述
安装solc(必须安装0.4.24版本,不然后面的compiledCode会报错)

npm install solc@0.4.24

在这里插入图片描述
然后进入.bin文件夹

cd node_modules/.bin

输入ganache-cli,然后就会输出一大堆可用的账户和私钥。如果报错端口占用,就改一下端口ganache-cli -p 7878,端口改过的,在后面的操作中注意灵活改一下

再打开一个终端进入simple_vote:cd simple_vote
然后创建Voting.sol文件

vim Voting.sol

然后编写Voting.sol的内容

pragma solidity >0.4.22;

contract Voting{
bytes32[] public candidateList;
mapping (bytes32 => uint8) public votesReceived;
constructor(bytes32[] memory candidateListName) public {
candidateList = candidateListName;
}

function validateCandidate(bytes32 candidateName) internal view returns (bool){
for(uint8 i = 0;i < candidateList.length; i++){
if(candidateName == candidateList[i])
return true;
}
return false;
}
function vote(bytes32 candidateName) public {
require(validateCandidate(candidateName));
votesReceived[candidateName] += 1;
}

function totalVotesFor(bytes32 candidateName) public view returns(uint8){
require(validateCandidate(candidateName));
return votesReceived[candidateName];
}
   }

然后按Esc,输入:wq保存并退出
这里我在constructor函数的参数中加了个memory,不然我后面编译的时候会报错
输入node进入nodejs环境

在nodejs环境里编写代码的时候,因为是写一行运行一行,所以要每一行代码运行之前要仔细检查,看是否游标变量大小写写错,稍微写错一点,它就报错退出nodejs环境(好娇气的说ヽ(ー_ー)ノ),退出去重新进nodejs之后,前面的要重新输入,我就输错了好几遍(ಥ_ಥ)
在这里插入图片描述

在node环境内输入

var Web3=require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))   

前面改过ganache-cli端口的,把这里的8545改掉
然后输入

web3.isConnected()

结果是true
如果不是的话,看一下前一个终端窗口ganache-cli是不是关掉了(就是下面这个窗口)
在这里插入图片描述
然后输入

web3.eth.accounts

输出的结果应该和ganache-cli中的结果一样
在这里插入图片描述
在这里插入图片描述
然后输入

var solc = require('solc')

输入solc查看变量
在这里插入图片描述
再打开一个终端,进入simple_votecd simple_vote
输入

sudo chmod 666 Voting.sol

然后回到刚才那个node环境的窗口
执行命令

var sourceCode = fs.readFileSync('Voting.sol').toString()

再输入sourceCode查看变量
在这里插入图片描述
继续输入

var compiledCode = solc.compile(sourceCode)

compiledCode查看变量,然后会显示巨长一串(里面包括了bytecode和interface参数,后面会用到这两个参数)
在这里插入图片描述
然后再输入

var abi = JSON.parse(compiledCode.contracts[':Voting'].interface);

abi查看变量
在这里插入图片描述
输入

var byteCode = compiledCode.contracts[':Voting'].bytecode

byteCode查看变量
在这里插入图片描述
byteCode和abi的内容对应的是compiledCode里的参数bytecodeinterface
输入

var VotingContract = web3.eth.contract(abi)
var deployTxObj = {data:byteCode,from:web3.eth.accounts[0],gas:3000000}
var contractInstance = VotingContract.new(['Riane','Michael','Depp'],deployTxObj);//随便命名三个候选人的姓名
contractInstance.address

3.控制台投票交互

继续输入

contractInstance.vote("Riane",{ from:web3.eth.accounts[0]}) //投给Alice
contractInstance.totalVotesFor("Riane") 
contractInstance.totalVotesFor("Riane").toString()//查看Riane的票数:1
contractInstance.totalVotesFor("Michael").toString()//查看Michael的票数:0
contractInstance.vote.sendTransaction("Depp",{from:web3.eth.accounts[0]})
contractInstance.totalVotesFor("Depp").toString()//查看Depp的票数:1

4.编辑网页,和以太坊交互

在之前的ganache-cli窗口中选取一个Available Accounts作为账户地址
在这里插入图片描述
然后连按两次ctrl c离开nodejs环境(不用再怕出问题要重新写了!(。-`ω´-))
然后进行编译(这里Voting.sol是加过memory,见上面,不加的话可能会报错,编译不出来)

solc --bin Voting.sol

在这里插入图片描述

solc --abi Voting.sol

在这里插入图片描述
以上两个编译结果都要复制记录下来
然后再进入nodejs环境,(没错,又是娇气的它≡┏|*´・Д・|┛)
输入

var Web3=require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))//这里改过端口的记得把8545改掉 
abi = [{"inputs":[{"internalType":"bytes32[]","name":"candidateListName","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"candidateList","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}]
//=后面的一长串就是刚刚复制记录的solc --abi Voting.sol结果

在这里插入图片描述
然后输入

bytecode = '608060405234801561001057600080fd5b5060405161041a38038061041a8339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b8382019150602082018581111561006957600080fd5b825186602082028301116401000000008211171561008657600080fd5b8083526020830192505050908051906020019060200280838360005b838110156100bd5780820151818401526020810190506100a2565b5050505090500160405250505080600090805190602001906100e09291906100e7565b5050610159565b828054828255906000526020600020908101928215610123579160200282015b82811115610122578251825591602001919060010190610107565b5b5090506101309190610134565b5090565b61015691905b8082111561015257600081600090555060010161013a565b5090565b90565b6102b2806101686000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80632f265cf7146100515780637021939f14610099578063a69beaba146100e1578063b13c744b1461010f575b600080fd5b61007d6004803603602081101561006757600080fd5b8101908080359060200190929190505050610151565b604051808260ff1660ff16815260200191505060405180910390f35b6100c5600480360360208110156100af57600080fd5b810190808035906020019092919050505061018d565b604051808260ff1660ff16815260200191505060405180910390f35b61010d600480360360208110156100f757600080fd5b81019080803590602001909291905050506101ad565b005b61013b6004803603602081101561012557600080fd5b8101908080359060200190929190505050610200565b6040518082815260200191505060405180910390f35b600061015c82610221565b61016557600080fd5b6001600083815260200190815260200160002060009054906101000a900460ff169050919050565b60016020528060005260406000206000915054906101000a900460ff1681565b6101b681610221565b6101bf57600080fd5b600180600083815260200190815260200160002060008282829054906101000a900460ff160192506101000a81548160ff021916908360ff16021790555050565b6000818154811061020d57fe5b906000526020600020016000915090505481565b600080600090505b6000805490508160ff1610156102725760008160ff168154811061024957fe5b9060005260206000200154831415610265576001915050610278565b8080600101915050610229565b50600090505b91905056fea265627a7a72315820a16746a0a9692cdbbef21916fe8f74d19b6db7e5aeced6c2300ae9a5a55eea3564736f6c63430005100032'
//引号里的结果就是之前复制记录的solc --bin Voting.sol结果

在这里插入图片描述
继续输入

VotingContract = web3.eth.contract(abi)

在这里插入图片描述

contractInst = VotingContract.new(["Riane","Michael","Depp"],{data:bytecode,from:web3.eth.accounts[0],gas:5000000})

在这里插入图片描述

contractInst.address

在这里插入图片描述
记录下这个账户地址
然后两次ctrl c再离开nodejs环境(ε=ε=ε=┌(;´゚ェ゚)┘快跑)
在项目文件夹simple_vote下,不在就cd进去,编写html和js文件

vim index.html

然后编写index.html内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Voting DApp</title>
    <link href ="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>
<body class="container">
    <h1>Simple Voting DApp</h1>
    <div class="table-responsive">
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>Candidate</th>
                    <th>Vote Count</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Riane</td>
                    <td id="candidate-1"></td>
                </tr>
                <tr>
                    <td>Michael</td>
                    <td id="candidate-2"></td>
                </tr>
                <tr>
                    <td>Depp</td>
                    <td id="candidate-3"></td>
                </tr>
            </tbody>
        </table>
        <input type="text" id="candidate"/>
        <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
    </div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/web3@0.20.6/dist/web3.min.js"></script>
<script src="./index.js"></script>
</html>

然后按Esc,输入:wq保存退出
输入

vim index.js

编写index.js内容

var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));//端口修改过的把8545换掉
//这里引号里粘贴solc --abi Voting.sol的结果
var abi = JSON.parse('[{"inputs":[{"internalType":"bytes32[]","name":"candidateListName","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"candidateList","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}]');
var contractAddr = "0xb7e3043136553fa6eed53e4d4e0893384991ea1e";//这里换成刚刚复制的账户地址
var VotingContract = web3.eth.contract(abi);
var contractInstance = VotingContract.at(contractAddr);

var candidates = {"Riane":"candidate-1","Michael":"candidate-2","Depp":"candidate-3"};
function voteForCandidate(){
    let candidateName = $("#candidate").val();
    try{
        contractInstance.vote(candidateName,{from:web3.eth.accounts[0]},(err,res)=>{
            if(err)
            console.log("Error: ",err);
            else{
                let id = candidates[candidateName];
                let count = contractInstance.totalVotesFor(candidateName).toString();
                $("#" + id).html(count);
            }
        })
    }
    catch (err){console.log("error");}
}
$(document).ready(function(){
    var candidateList = Object.keys(candidates);
    for(let i =0; i< candidateList.length; i++){
        let name = candidateList[i];
        let  count = contractInstance.totalVotesFor(name).toString();
        $("#" + candidates[name]).html(count);
    }
});

然后保存退出之后,用firefox打开index.html文件
输入候选人的名字即可投票
在这里插入图片描述
最后部署node服务器
在项目文件夹simple_vote下新建server.js文件

var http = require("http");
var fs = require("fs");
var url = require("url");

http.createServer(function(req,res){
    var pathName = url.parse(req.url).pathname;
    console.log("Request for:"+pathName +"received.");

    fs.readFile(pathName.substr(1),function(err,data){
        if (err){
            console.log(err);
            res.writeHead(404,{"Content-Type": "text/html"});
        }
        else {
            res.writeHead(200,{"Content-Type": "text/html"});
            res.write(data.toString());
        }
        res.end();
    });

}).listen(8888);

保存退出
输入

node server.js

然后打开火狐,输入http://localhost:8888/index.html
出现投票界面,部署成功
在这里插入图片描述

转载自DAPP开发
基本是跟着的博客走的,其中一些地方在我运行的时候报错了,所以对其中做了一些细微的修改,然后成功部署。学长nb !(`・ω・´)ゞ敬礼っ


Tips:因为网址http://localhost:8888/index.html是在node服务器部署下运行的,所以关掉运行node server.js的终端窗口后,网址无法再打开运行。而且关掉ganache-cli窗口后,index.html用火狐打开后也无法运行了(  ̄┏_┓ ̄)。
就等于关掉虚拟机重启之后,要重新部署一遍,才能重新运行成功⊙︿⊙。不知道是不是只有我存在这个问题(˘•ω•˘)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值