Continuación de una breve discusión sobre el aprendizaje de blockchain DAPP

1f6cffb8ca4340a606f5d21d308640df.gif

Prefacio

Ayer publiqué un artículo resumido sobre mi estudio sobre blockchain y DAPP. Mi amigo me hizo algunos comentarios: Los contratos no tienen identidad y una persona puede votar muchas veces siempre que esté dispuesta a gastar gasolina. Esta es una laguna jurídica en el robo de votos. .

Pensándolo bien, me siento un poco vago, así que agregaré otro artículo hoy. Solo dos puntos: 1. Agregar autenticación de identidad para evitar votaciones repetidas; 2. Dar una introducción a web3.0 y su implementación y llamada. De hecho, la función es la misma que ayer pero el método será diferente.

10eaada49b7d77e70efb4a7b4bd1c406.png

Optimización del contrato de 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];
    }
}

El código está adjunto, puede leer los comentarios para obtener más detalles; de hecho, es muy sencillo usar el mapeo para registrar la dirección del votante (registrado con estructura)

A continuación, hablemos sobre cómo inicializar web3.0 simple.

mkdir web3.0
   cd web3.0
   npm init

ff1bbfc112f723f899a91802ad366239.pngPresione Enter hasta el final para inicializar un proyecto de nodo js

npm install web3 -save
ce3246c446be13fa24131011568c6d7d.png

Implementar el contrato a través del nodo js web3

Cree un nuevo implementar.js en el directorio web3.0

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

Abra remix y podremos ver que el archivo de implementación de web3 es tan simple como77cd92863b8b6ef6eb9845958da610c0.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);
 });

de: web3.eth.accounts[0], recuerde cambiarlo a su cuenta ganache y ahora implementar el contrato a través del nodo

node deploy.js

dba954b9dd2bbcef9488f34659bdae13.pngEn este momento puede ver la dirección del contrato (¡Dirección del contrato!: 0x32Cf1f3a98aeAF57b88b3740875D19912A522c1A)

El contrato está desplegado, ¿cómo llamarlo? Todavía usamos el proyecto de ayer para llamarlo, por supuesto, se puede llamar en una cadena virtual local.

El siguiente es el código central del contrato de convocatoria del proyecto APP de ayer, lo escribí directamente en los comentarios:

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

La pregunta actual es ¿dónde encontrar voteArtifact.abi? eaa10a021bef50fde1818f205dd3c627.pngBien, resulta que lo copié del remix y adjunté todo el código.

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

Ahora que el programa está bien, ingrese al directorio de aplicaciones del último proyecto (se omiten detalles)

cd app
npm run dev

Empecé a votar c1cd38324de8f79c75c281b10495642e.pngy la primera votación fue exitosa. aa3e8db8c62099fd4f7de565fc9f75f8.pngLa segunda votación 26de390d56d961114190287906dba207.pngfue buena, pero dejé de votar. Finalmente, no pude pasar mi voto.

Resumir

El andamiaje que utilicé la última vez estaba listo, pero muchos detalles no estaban en su lugar. Ser más detallado hoy también es el final de mi propio aprendizaje.

Supongo que te gusta

Origin blog.csdn.net/weixin_47479625/article/details/124011465
Recomendado
Clasificación