(2022年最新版本)Linux下基于ganache(v6.12.2)的简单投票DAPP(web3@1.7.1)(Node.js: v16.14.0.)(solc:‘0.8.12+commit)

Posted weixin_47450271

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(2022年最新版本)Linux下基于ganache(v6.12.2)的简单投票DAPP(web3@1.7.1)(Node.js: v16.14.0.)(solc:‘0.8.12+commit)相关的知识,希望对你有一定的参考价值。

1.下面是基于 Linux 的安装指南。这要求我们预先安装 nodejs 和 npm,再用 npm 安装 ganache-cli、web3 和 solc。

mkdir simple_voting_dapp
cd simple_voting_dapp
npm init
npm install ganache-cli web3 solc
node_modules/.bin/ganache-cli
  • 需保证ganache-cli在整个服务器运行过程中一直运行
  • 如果安装成功,运行命令 node_modules/.bin/ganache-cli,应该能够看到下 图所示的输出。

        为了便于测试,ganache 默认会创建 10 个账户,每个账户有 100 个以太。你需要用其中一个账户创建交易,发送、接收以太。 当然,你也可以安装 GUI 版本的图形化 ganache 而不是命令行版本,在这里下 载 GUI 版本:http://truffleframework.com/ganache/

2.Solidity 合约

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Voting
    bytes32[] public candidateList;
    mapping(bytes32 => uint8)public voteReceived;
    constructor(bytes32[] memory candidateNames)
        candidateList = candidateNames;
    
    function totalVotesFor(bytes32 candidateName) public view returns(uint8)
        require(validCandidate(candidateName));
        return voteReceived[candidateName];
    

    function voteForCandidate(bytes32 candidateName) public 
        require(validCandidate(candidateName));
        voteReceived[candidateName] += 1;
    

    function validCandidate(bytes32 candidateName) public view returns(bool)
        for(uint8 i = 0; i < candidateList.length; i++)
            if(candidateList[i] == candidateName)
                return true;
            
        
        return false;
    

将Voting.sol合约存储到simple_voting_dapp目录下的contract文件夹中

 注意:当你把合约部署到区块链的时候,就会调用构造函数,并只调用一次。与 web 世界里每次部署代码都会覆盖旧代码不同,在区块链上部署的合约是不可 改变的,也就是说,如果你更新合约并再次部署,旧的合约仍然会在区块链上存 在,并且数据仍在。新的部署将会创建合约的一个新的实例

3.编译合约

重新开启一个bash,并进入到simple_voting_dapp/contract中,输入node,在node控制台中操作

> var Web3  = require('web3');
> var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); //ganache-cli 启动的默认连接是 http://localhost:8545
> web3.eth.net.isListening().then(console.log);  //检测连接是否成功
Promise 
  <pending>,
  [Symbol(async_id_symbol)]: 945,
  [Symbol(trigger_async_id_symbol)]: 941,
  [Symbol(destroyed)]:  destroyed: false 

> true

> var sourceCode = fs.readFileSync('Voting.sol').toString()
> var solc = require('solc');

> var input = 
  language: 'Solidity',
  sources: 
    'Voting.sol': 
      content: sourceCode
    
  ,
  settings: 
    outputSelection: 
      '*': 
        '*': ['*']
      
    
  
;

> var output = JSON.parse(solc.compile(JSON.stringify(input)));  //编译

4.部署合约 

> var abi = output.contracts['Voting.sol'].Voting['abi'];
> var byteCode = output.contracts['Voting.sol'].Voting['evm']['bytecode'].object;
> var candidatesHex =[web3.utils.toHex('tom'),web3.utils.toHex('jack'),web3.utils.toHex('mary')]; //byte32[]  为Voting.sol构造函数传入参数做准备
> var account;
> web3.eth.getAccounts().then(function(res)account=res[0]);
> var VotingContract = new web3.eth.Contract(abi);
> var contractInstance = VotingContract.deploy(data:byteCode,arguments:[candidatesHex]).send(from:account,gas: 1500000,gasPrice: '30000000000000').then(function(newContractInstance)
    console.log(newContractInstance.options.address) 
);


> 0xC65cD0Ada5fD85f5D200071C98751B474B017680  //获取新合约实例的合约地址

> VotingContract.options.address = '0xC65cD0Ada5fD85f5D200071C98751B474B017680' ; //设置合约地址 不然无法调用合约里面的方法



5.调用合约方法

> VotingContract.methods.voteForCandidate(web3.utils.toHex('tom')).send(from:account).then(console.log);  //调用Voting.sol中的voteForCandidate方法为tom投票

> VotingContract.methods.totalVotesFor(web3.utils.toHex('tom')).call(from:account).then(console.log);   //查询tom的投票数

Promise 
  <pending>,
  [Symbol(async_id_symbol)]: 6738,
  [Symbol(trigger_async_id_symbol)]: 6734,
  [Symbol(destroyed)]:  destroyed: false 

> 1

6.index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Voting DApp</title>
        <link
            href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/boot
strap.min.css"
            rel="stylesheet"
            type="text/css"
        />
    </head>
    <body class="container">
        <h1>A Simple 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>tom</td>
                        <td id="candidate-1"></td>
                    </tr>
                    <tr>
                        <td>jack</td>
                        <td id="candidate-2"></td>
                    </tr>
                    <tr>
                        <td>mary</td>
                        <td id="candidate-3"></td>
                    </tr>
                </tbody>
            </table>
        </div>
        <input type="text" id="candidate" />
        <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
    </body>
    <script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.mi
n.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
    <script src="./index.js"></script>
</html>

7.index.js

var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var abi = JSON.parse('["inputs":["internalType":"bytes32[]","name":"candidateNames","type":"bytes32[]"],"stateMutability":"nonpayable","type":"constructor","inputs":["internalType":"uint256","name":"","type":"uint256"],"name":"candidateList","outputs":["internalType":"bytes32","name":"","type":"bytes32"],"stateMutability":"view","type":"function","inputs":["internalType":"bytes32","name":"candidateName","type":"bytes32"],"name":"totalVotesFor","outputs":["internalType":"uint8","name":"","type":"uint8"],"stateMutability":"view","type":"function","inputs":["internalType":"bytes32","name":"candidateName","type":"bytes32"],"name":"validCandidate","outputs":["internalType":"bool","name":"","type":"bool"],"stateMutability":"view","type":"function","inputs":["internalType":"bytes32","name":"candidateName","type":"bytes32"],"name":"voteForCandidate","outputs":[],"stateMutability":"nonpayable","type":"function","inputs":["internalType":"bytes32","name":"","type":"bytes32"],"name":"voteReceived","outputs":["internalType":"uint8","name":"","type":"uint8"],"stateMutability":"view","type":"function"]');
var contractAddr = '0x1E3B8A53A32c1C17d16b892c155fAB298e57BBE6';
var contractInstance = new web3.eth.Contract(abi,contractAddr);
var candidates = 'tom':'candidate-1','jack':'candidate-2','mary':'candidate-3';
var account;
web3.eth.getAccounts().then(function(accounts)
    account = accounts[0];
);

function voteForCandidate()
    let candidateName = $("#candidate").val();
    let candidateNameHex =  web3.utils.toHex(candidateName);
    contractInstance.methods.voteForCandidate(candidateNameHex).send(from:account).then(function(receipt)
        $("#msg").html("已投给: "+ candidateName + "<br>交易哈希: " + receipt.transactionHash + "<br>投票人地址: " + account);
        contractInstance.methods.totalVotesFor(candidateNameHex).call(function(err,res)
            $('#'+candidates[candidateName]).html(res);
        );
    );


$(document).ready(function()
    var candidateList = Object.keys(candidates);
    for (let i = 0; i < candidateList.length; i++)
        let name = candidateList[i];
        let nameHex = web3.utils.toHex(name);
        let count = contractInstance.methods.totalVotesFor(nameHex).call(function(err,res)
            $("#"+candidates[name]).html(res);
        );
    
)

        如果一切顺利的话,你应该能够在文本框中输入候选者姓名,然后投票数应 该加 1 。 注意:由于网络原因,web3.js 可能无法获取,可自行下载到本地导入。 如果你可以看到页面,为候选者投票,然后看到投票数增加,那就已经成功 创建了第一个合约,恭喜!所有投票都会保存到区块链上,并且是不可改变的。 任何人都可以独立验证每个候选者获得了多少投票。当然,我们所有的事情都是在一个模拟的区块链上(ganache)完成。

8.总结

下面是你到目前为止已经完成的事情:

1. 通过安装 node, npm 和 ganache,你已经配置好了开发环境。

2. 你编码了一个简单的投票合约,编译并部署到区块链上。

3. 你通过 nodejs 控制台与网页与合约进行了交互

通过ganache与以太坊Dapp实现交互 —— 简单的例子

通过ganache与以太坊Dapp实现交互 —— 简单的例子

准备条件:
环境:Centos7或者其他版本的linux
必备: 安装npm (推荐16.1.0版本) 以及ganache-cli

在dapp目录下的ganache目录启动ganache-cli
会输出下面的结果:

[root@ ganache]# ganache-cli
Ganache CLI v6.12.2 (ganache-core: 2.13.2)

Available Accounts
==================
(0) 0x0290510d6800238A3E087D862747e700a1a10D08 (100 ETH)
(1) 0x4012E2365946076cF48a06Ea43352E9e898D5DdD (100 ETH)
(2) 0x0B9FC57a3cfc6C50ceC7465acfD908f54753da47 (100 ETH)
(3) 0xBf032e66fD1f34671bd9D07E4a5f9835C4CE281f (100 ETH)
(4) 0xd3a57f27318C9D4C7800AdAD8b77d8018f6CD067 (100 ETH)
(5) 0x4b2842CB2597516b106958e481004f38972Bd900 (100 ETH)
(6) 0x23E9c6ef5B4a3434e14Ae612C11Ac62E4d5cFEc1 (100 ETH)
(7) 0x03B782000625ebE0cfAcbbC99D5405c1457332DE (100 ETH)
(8) 0xbbf5986b1FE9B11C5C698620D768b0477De746C4 (100 ETH)
(9) 0x76E5a724Db2a4aB395DA59b751A20813E1AB09d3 (100 ETH)

Private Keys
==================
(0) 0x3d036634781286f518e1d10c35f001752937cf94a56d33678d9ed08ee083f253
(1) 0x2670ccb6966d02d0e5fa4be32fbabfe37f830cb824a1ee8452243e85a11b92ef
(2) 0xfd6293f17fcb6c857f085613b5c79d8c3f5932b500952f5ceae985432f5a6ad4
(3) 0xaf19287c564f6daf205d75d952cf9a1f061856bef15316870f116f6104a56379
(4) 0x2c7b69b2323515002966cfd0156f93fd471a461d4103545c4e96799009b11231
(5) 0x7faedd0b5ec22e900ab5ba8900a68ae9bf019bfad8411715a8204d17e927cff8
(6) 0x86dffcb52b1a75437aa92bd234fcb5716a3357bf8888671e24790e7028916184
(7) 0x7ec139800df481b982a2a957db2f216e223d26b27e960517c66e4dbde8ecce98
(8) 0x8b9cdda2b00d936feb5fb6a2e1032033a8c86bd284b4466c6a3803789f77fa9a
(9) 0x5be3acee1332107fb29f0c7608f8266708b1ef6715aa8dd8a2ce06f4146a7d9b

HD Wallet
==================
Mnemonic:      slice debate rabbit comfort combine ancient section banner spring frame twice artefact
Base HD Path:  m/44'/60'/0'/0/account_index

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545

创建一个备用目录testdapp

mkdir testdapp

安装express

npm install express -g
npm install -g express-generator

创建工程

express -e MyDapp

先要进行一些安装

npm install

在MyDapp文件下会出现以下目录

[root@ MyDapp]# ls
app.js  node_modules  package-lock.json  routes   bin     package.json  public             views

启动我们的工程

npm start

登录游览器http://127.0.0.1:8545和http://127.0.0.1:3000查看效果

安装web3

[root@ MyDapp]# npm install web3 -save

此时可以发现多了node_modules和package-lock.json两个文件

[root@ MyDapp]# ls
app.js  bin  node_modules  package.json  package-lock.json  public  routes  views

我们进入到routes文件夹进行修改index.js

[root@  MyDapp]# cd routes
[root@  routes]# ls
index.js  users.js
[root@cfx routes]# vim index.js 

修改index.js当中的代码

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

web3.eth.getAccounts().then(console.log);

/* GET home page. */
router.get('/', function(req, res, next) 
  web3.eth.getAccounts().then(function(accounts)
     var account = accounts[0];
     web3.eth.getBalance(account).then(function(balance)
        var amount = web3.utils.fromWei(balance,'ether');
        res.render('index',account: account,balance: amount);

);
);
);

module.exports = router;
[root@ MyDapp]# ls
app.js  bin  node_modules  package.json  package-lock.json  public  routes  views
[root@ MyDapp]# vim app.js

修改app.js当中的代码

var ejs = require('ejs');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.engine('.html',ejs.__express);
app.set('view engine', 'html');

在views文件下创建index.html文件,并将下面的html代码放入

[root@ MyDapp]# cd views
[root@ views]# ls
error.ejs  index.ejs
[root@ views]# vim index.html
<!DOCTYPE html>
<html>
  <head>
    <title>账户余额</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>账户是: <%= account %></h1>
    <h1>余额是: <%= balance %></h1>
  </body>
</html>

另启一个终端进入testdapp目录然后进到我们创建项目的MyDapp目录下
输入npm start命令,会输出下面的结果

[root@ MyDapp]# npm start

> mydapp@0.0.0 start
> node ./bin/www

[
  '0x0290510d6800238A3E087D862747e700a1a10D08',
  '0x4012E2365946076cF48a06Ea43352E9e898D5DdD',
  '0x0B9FC57a3cfc6C50ceC7465acfD908f54753da47',
  '0xBf032e66fD1f34671bd9D07E4a5f9835C4CE281f',
  '0xd3a57f27318C9D4C7800AdAD8b77d8018f6CD067',
  '0x4b2842CB2597516b106958e481004f38972Bd900',
  '0x23E9c6ef5B4a3434e14Ae612C11Ac62E4d5cFEc1',
  '0x03B782000625ebE0cfAcbbC99D5405c1457332DE',
  '0xbbf5986b1FE9B11C5C698620D768b0477De746C4',
  '0x76E5a724Db2a4aB395

打开浏览器,输入127.0.0.1:3000 即可看到ganache与web3交互的结果。

以上是关于(2022年最新版本)Linux下基于ganache(v6.12.2)的简单投票DAPP(web3@1.7.1)(Node.js: v16.14.0.)(solc:‘0.8.12+commit)的主要内容,如果未能解决你的问题,请参考以下文章

Kali Linux 2022.1

Solidity、solc、web3.js、Ganache 版本组合目前正在使用啥

Java后端开发学习路线(2022年最新版)

DL之GRU:基于2022年6月最新上证指数数据集结合Pytorch框架利用GRU算法预测最新股票上证指数实现回归预测

win7下以太坊基于truffle+ganache开发环境搭建以及智能合约的部署调用

2022年最新AlphaPose环境配置(Linux+GPU)