A brief discussion on blockchain DAPP learning·continued

1f6cffb8ca4340a606f5d21d308640df.gif

Preface

Yesterday I published a summary article about my study of blockchain and DAPP. My friend gave me some comments: Contracts have no identity, and a person can vote many times as long as he is willing to spend gas. This is a vote-swiping loophole.

Thinking about it carefully, I feel a little lazy, so I will add another article today. Just two points: 1. Add identity authentication to avoid repeated voting; 2. Give some introduction to web3.0 and its deployment and calling. In fact, the function is the same as yesterday but the method will be different.

10eaada49b7d77e70efb4a7b4bd1c406.png

solidity contract optimization

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];
    }
}

The code is attached, you can read the comments for details; in fact, it is very simple to use mapping to record the voter address (recorded with struct)

Next let’s talk about how to initialize simple web3.0

mkdir web3.0
   cd web3.0
   npm init

ff1bbfc112f723f899a91802ad366239.pngPress Enter all the way to initialize a node js project

npm install web3 -save
ce3246c446be13fa24131011568c6d7d.png

Deploy the contract through node js web3

Create a new deploy.js in the web3.0 directory

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

Open remix and we can see that the deployment file of web3 is as simple as77cd92863b8b6ef6eb9845958da610c0.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], remember to change it to your ganache account and now deploy the contract through node

node deploy.js

dba954b9dd2bbcef9488f34659bdae13.pngAt this time you can see the contract address (Contract! address: 0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A)

The contract is deployed, how to call it? We still use yesterday’s project to call it. Of course, it can be called on a local virtual chain.

The following is the core code of yesterday's APP project call contract. I wrote it directly in the comments:

//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.");
    }
  },

The current question is where to find votingArtifact.abi? eaa10a021bef50fde1818f205dd3c627.pngOkay, it turns out I copied it from the remix and attached all the code.

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();
});

Now that the program is ok, enter the app directory of the last project (details omitted)

cd app
npm run dev

I started voting c1cd38324de8f79c75c281b10495642e.png, and the first vote was successful. aa3e8db8c62099fd4f7de565fc9f75f8.pngThe second vote 26de390d56d961114190287906dba207.pngwas good, but I stopped voting. Finally, I couldn’t swipe my vote.

Summarize

Last time I used scaffolding and it was all ready at once, but many details were not in place. Being more detailed today is also the end of my own learning.

Guess you like

Origin blog.csdn.net/weixin_47479625/article/details/124011465