浅谈区块链DAPP学习·续

1f6cffb8ca4340a606f5d21d308640df.gif

前言

昨天发布了关于自己学习区块链和DAPP的学习小结式的文章,朋友对我提了几点意见说:合约没有身份,一个人可以很多次的投票只要舍得花gas这是个刷票漏洞。

仔细想来是有点偷懒了,所以今天补一篇。就两点:1,补上身份认证避免反复投票;2,对web3.0以及他的部署和调用再做一些介绍,其实功能和昨天是一样的但是方法会有所不同。

10eaada49b7d77e70efb4a7b4bd1c406.png

solidity的合约优化

pragma solidity ^0.4.0;
contract Voting{
    //投票列表
    bytes32[] public candidateList;
    //对应的票数
    mapping(bytes32=>uint8) public votesReceived;
    //投票人列表
    mapping(address=>People) public Peoples;
    //投票人信息及投票时间
    struct People{
        address account;
        uint voingtime;
    }
    //构造投票列表
    constructor(bytes32[] memory  candidateListName) public{
        candidateList = candidateListName;
    }
    //获取投票人账号
    function getAccountAddress()  public returns(uint32)
    {
        People memory people = Peoples[msg.sender];
        return uint32(people.account);
    }
    //设置已投票地址
    function setAccountAddress() private 
    {
        People memory people = People(msg.sender,now);

        Peoples[msg.sender] = people;
    }


    //判断投票信息是否在待投票列表
    function valiCandidate(bytes32 candidateName) internal view returns(bool)
    {
        for(uint8 i=0;i<candidateList.length;i++)
        {
            if (candidateName==candidateList[i])
            {
                return true;
            }
        }
        return false;
    }
   //对投票人增加投票
    function voteForCandidate(bytes32 candidateName) public{
        require(valiCandidate(candidateName));
        //判断是否已投票 0 为未投票
        require(getAccountAddress()==0);
        setAccountAddress();
        votesReceived[candidateName] = votesReceived[candidateName] + 1;
    }                                  
    function totalVotesFor(bytes32 candidateName) view public returns(uint8){
        require(valiCandidate(candidateName));
        //返回票数
        return votesReceived[candidateName];
    }
}

代码附上,具体可以看注释;其实很简单就是用mapping记录投票人地址(用struct记录)

接下来聊聊 如何初始化简单web3.0

mkdir web3.0
   cd web3.0
   npm init

ff1bbfc112f723f899a91802ad366239.png一路回车初始化一个node js项目

npm install web3 -save
ce3246c446be13fa24131011568c6d7d.png

通过node js web3 部署合约

在web3.0目录下新建deploy.js

var Web3 = require('web3');
// 链接本地 ganache 记得启动
var  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

打开remix 我们可以看到web3的部署文件就这么简单77cd92863b8b6ef6eb9845958da610c0.png

var  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
var candidateListName =  ["0x4100000000000000000000000000000000000000000000000000000000000000","0x4200000000000000000000000000000000000000000000000000000000000000"] ;
var votingContract = new web3.eth.Contract([{"constant":false,"inputs":[],"name":"getAccountAddress","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"candidateName","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"Peoples","outputs":[{"name":"account","type":"address"},{"name":"voingtime","type":"uint256"}],"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":"candidateName","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateListName","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
var voting = votingContract.deploy({
     data: '0x608060405234801561001057600080fd5b506040516106d93803806106d9833981018060405281019080805182019291905050508060009080519060200190610049929190610050565b50506100c8565b828054828255906000526020600020908101928215610092579160200282015b82811115610091578251829060001916905591602001919060010190610070565b5b50905061009f91906100a3565b5090565b6100c591905b808211156100c15760008160009055506001016100a9565b5090565b90565b610602806100d76000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630e2562d91461007d5780632f265cf7146100b457806355f503d5146100ff5780637021939f14610189578063b13c744b146101d4578063cc9ab2671461021d575b600080fd5b34801561008957600080fd5b5061009261024e565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b3480156100c057600080fd5b506100e3600480360381019080803560001916906020019092919050505061030f565b604051808260ff1660ff16815260200191505060405180910390f35b34801561010b57600080fd5b50610140600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610355565b604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b34801561019557600080fd5b506101b86004803603810190808035600019169060200190929190505050610399565b604051808260ff1660ff16815260200191505060405180910390f35b3480156101e057600080fd5b506101ff600480360381019080803590602001909291905050506103b9565b60405180826000191660001916815260200191505060405180910390f35b34801561022957600080fd5b5061024c60048036038101908080356000191690602001909291905050506103dc565b005b60006102586105a6565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040805190810160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820154815250509050806000015191505090565b600061031a82610475565b151561032557600080fd5b60016000836000191660001916815260200190815260200160002060009054906101000a900460ff169050919050565b60026020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154905082565b60016020528060005260406000206000915054906101000a900460ff1681565b6000818154811015156103c857fe5b906000526020600020016000915090505481565b6103e581610475565b15156103f057600080fd5b60006103fa61024e565b63ffffffff1614151561040c57600080fd5b6104146104da565b6001806000836000191660001916815260200190815260200160002060009054906101000a900460ff160160016000836000191660001916815260200190815260200160002060006101000a81548160ff021916908360ff16021790555050565b600080600090505b6000805490508160ff1610156104cf5760008160ff1681548110151561049f57fe5b906000526020600020015460001916836000191614156104c257600191506104d4565b808060010191505061047d565b600091505b50919050565b6104e26105a6565b60408051908101604052803373ffffffffffffffffffffffffffffffffffffffff16815260200142815250905080600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001015590505050565b6040805190810160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815250905600a165627a7a72305820230b9460ef4d9c98dc2ad603c8d560d384d66df56e19cce527bbdda332014b4e0029', 
     arguments: [
          candidateListName,
     ]
}).send({
     //from: web3.eth.accounts[0], 
     from: '0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 }).then(function(contract){
    console.log('Contract ! address: ', contract.options.address);
 });

from: web3.eth.accounts[0], 记得改成你ganache个你的账号 现在通过node 部署 合约

node deploy.js

dba954b9dd2bbcef9488f34659bdae13.png这时候你可以看到合约地址(Contract ! address:  0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A)

合约部署好了,那怎么调用呢?我们还是用昨天的项目去调用都在一个本地虚拟链上当然都可以调用

下面是昨天APP项目调用合同的核心代码我直接在注释上写:

//node js 部署 我们没有这个json文件注释掉
  // import votingArtifact from "../../build/contracts/Voting.json";
  start: async function() {
    const { web3 } = this;

    try {
      // get contract instance
      const networkId = await web3.eth.net.getId();
      //这里既然前面注释了,这里应该也没用了
      const deployedNetwork = votingArtifact.networks[networkId];
      
      //调用合同部分votingArtifact.abi这个哪里找呢?
      //deployedNetwork.address 这个不就是合同地址吗
      this.voting = new web3.eth.Contract(
        votingArtifact.abi,
        //deployedNetwork.address,
        '0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A',
      );

      // get accounts
      const accounts = await web3.eth.getAccounts();
      this.account = accounts[0];
      this.ready();
      this.refreshBalance();
    } catch (error) {
      console.error("Could not connect to contract or chain.");
    }
  },

现在的问题votingArtifact.abi哪里找呢?eaa10a021bef50fde1818f205dd3c627.png好吧原来remix里有复制下来 附上所有代码

import Web3 from "web3";
//import votingArtifact from "../../build/contracts/Voting.json";
const aInBytes32 ="0x4100000000000000000000000000000000000000000000000000000000000000";
const bInBytes32 ="0x4200000000000000000000000000000000000000000000000000000000000000";
const App = {
  web3: null,
  account: null,
  meta: null,

  start: async function() {
    const { web3 } = this;

    try {
      // get contract instance
      const networkId = await web3.eth.net.getId();
     // const deployedNetwork = votingArtifact.networks[networkId];
      // this.voting = new web3.eth.Contract(
      //   votingArtifact.abi,
      //   deployedNetwork.address,
      // );
      this.voting = new web3.eth.Contract(
        [
          {
            "constant": false,
            "inputs": [],
            "name": "getAccountAddress",
            "outputs": [
              {
                "name": "",
                "type": "uint32"
              }
            ],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
          },
          {
            "constant": true,
            "inputs": [
              {
                "name": "candidateName",
                "type": "bytes32"
              }
            ],
            "name": "totalVotesFor",
            "outputs": [
              {
                "name": "",
                "type": "uint8"
              }
            ],
            "payable": false,
            "stateMutability": "view",
            "type": "function"
          },
          {
            "constant": true,
            "inputs": [
              {
                "name": "",
                "type": "address"
              }
            ],
            "name": "Peoples",
            "outputs": [
              {
                "name": "account",
                "type": "address"
              },
              {
                "name": "voingtime",
                "type": "uint256"
              }
            ],
            "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": "candidateName",
                "type": "bytes32"
              }
            ],
            "name": "voteForCandidate",
            "outputs": [],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "function"
          },
          {
            "inputs": [
              {
                "name": "candidateListName",
                "type": "bytes32[]"
              }
            ],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "constructor"
          }
        ],
        '0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A',
      );
      // get accounts
      const accounts = await web3.eth.getAccounts();
      this.account = accounts[0];
      this.ready();
      this.refreshBalance();
    } catch (error) {
      console.error("Could not connect to contract or chain.");
    }
  },
  ready:async function(){
     try{
        this.refresh("Alice",aInBytes32);
        this.refresh("Bob",bInBytes32);
     }catch(err){
        console.log(err)
     }
  },
  refresh:async function(id,nameBytes32){
      const {totalVotesFor} = this.voting.methods;
      const tickets = await totalVotesFor(nameBytes32).call();
      const el = document.getElementById(id);
      el.innerHTML = tickets.toString();
  },
   voteForCandidate:async function(){
       try{
          const {voteForCandidate} = this.voting.methods;
          const condidateName = document.getElementById("candidate").value;
          console.log(condidateName)
          if (condidateName == "Alice")
          {
            await voteForCandidate(aInBytes32).send({from:this.account});
            this.refresh("Alice",aInBytes32);
          }
          else{
            await voteForCandidate(bInBytes32).send({from:this.account});
            this.refresh("Bob",bInBytes32);
          }
       }catch(err){
           console.log(err)
       }
   }
};

window.App = App;

window.addEventListener("load", function() {
  if (window.ethereum) {
    // use MetaMask's provider
    App.web3 = new Web3(window.ethereum);
    window.ethereum.enable(); // get permission to access accounts
  } else {
    console.warn(
      "No web3 detected. Falling back to http://127.0.0.1:8545. You should remove this fallback when you deploy live",
    );
    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
    App.web3 = new Web3(
      new Web3.providers.HttpProvider("http://127.0.0.1:8545"),
    );
  }

  App.start();
});

好了 程序都ok了 进入上次那个项目app目录(细节省略了)

cd app
npm run dev

开始投票c1cd38324de8f79c75c281b10495642e.png第一次投票成功aa3e8db8c62099fd4f7de565fc9f75f8.png第二次投票26de390d56d961114190287906dba207.png好了不给投了,终于不能刷票了。

总结

上次用的是脚手架一下子全好了,很多细节不到位,今天细一点也是对自己学习的终结。

猜你喜欢

转载自blog.csdn.net/weixin_47479625/article/details/124011465