zoukankan      html  css  js  c++  java
  • Hello World投票以太坊Dapp教程-Part1

     参考资料:https://medium.com/@mvmurthy/full-stack-hello-world-voting-ethereum-dapp-tutorial-part-1-40d2d0d807c2

    这是一个非常简单的应用程序,只需要初始化一组参赛者,任何人都可以给候选人投票,并显示每位候选人收到的总票数。

    我们的目标不是只编写一个应用程序,而是学习编译,部署和与之交互的过程。

    我故意避免使用任何dapp框架来构建这个应用程序,因为框架抽象掉了很多细节,不利于理解系统的内部结构。不过当你使用框架时,你将更加感激框架为您所做的所有繁重工作!

    这个练习的目标是:

    1. 建立开发环境
    2. 了解编写合同,编译并将其部署到开发环境中的过程。
    3. 通过nodejs控制台与区块链上的合约进行交互。
    4. 通过一个简单的网页与合约进行交互。

     系统示意图如下:

     

     1.搭建开发环境

    我们将使用内存区块链(将其视为区块链模拟器)——ganache,而不是真的区块链开发应用程序。在Part2,我们将使用真的区块链。

    以下是在Linux操作系统上安装ganache,web3js和启动测试区块链的步骤。

    czk@czk-vm:~$ npm -v
    6.1.0
    czk@czk-vm:~$ node -v
    v8.11.2
    czk@czk-vm:~$ sudo apt-get install build-essential python
    czk@czk-vm:~$ cd work/
    czk@czk-vm:~/work$ mkdir hello_world_voting
    czk@czk-vm:~/work$ cd hello_world_voting
    czk@czk-vm:~/work/hello_world_voting$ mkdir node_modules
    czk@czk-vm:~/work/hello_world_voting$ npm install ganache-cli
    czk@czk-vm:~/work/hello_world_voting$ npm install web3@0.20.6
    czk@czk-vm:~/work/hello_world_voting$ node_modules/.bin/ganache-cli

    ganache-cli会创建10个测试帐户,这些帐户预村了100个(假的)Eth。

    (以上为局部安装,关于npm 与node_modules, 见https://www.runoob.com/nodejs/nodejs-npm.html

    2. 简单的投票合约

    我们使用Solidity语言来编写智能合约。我们将编写2种方法,一种是返回候选人收到的总票数,另一种方法是增加候选人的投票数。

    注意:当您将合约部署到区块链时,构造函数只会被调用一次。与在Web中,新部署代码会覆盖旧代码不同,区块链中部署的代码是不可修改的。

    如果您更新合约并再次进行部署,旧合约仍会保留在区块链中,并保留其中的所有数据,新的部署将创建一个新的合约实例

    以下是投票合约代码:

     1 pragma solidity^0.4.18;
     2 // We have to specify what version of compiler this code will compile with
     3 
     4 contract Voting {
     5     mapping(bytes32 => uint8) public votesReceived;
     6 
     7     /* Solidity doesn't let you pass in an array of strings in the constructor (yet).
     8     We will use an array of bytes32 instead to store the list of candidates
     9     */
    10     bytes32[] public candidateList;
    11 
    12     /* This is the constructor which will be called once when you
    13     deploy the contract to the blockchain. When we deploy the contract,
    14     we will pass an array of candidates who will be contesting in the election
    15     */
    16     constructor (bytes32[] candidateNames) public {
    17         candidateList = candidateNames;
    18     }
    19 
    20     // This function returns the total votes a candidate has received so far
    21     function candidateVotes(bytes32 candidate) public view returns(uint8) {
    22         require(_candidateValidation(candidate), "Invalid candidate.");
    23         return votesReceived[candidate];
    24     }
    25 
    26     // This function increments the vote count for the specified candidate. This
    27     // is equivalent to casting a vote
    28     function VoteToCandidate(bytes32 candidate) public {
    29         require(_candidateValidation(candidate), "Invalid candidate.");
    30         votesReceived[candidate]++;
    31     }
    32 
    33     // This function check the validity of input candidate.
    34     function _candidateValidation(bytes32 candidate) private view returns(bool) {
    35         for(uint i = 0; i < candidateList.length; ++i) {
    36             if(candidateList[i] == candidate)
    37                 return true;
    38         }
    39         return false;
    40     } 
    41 }

    将以上代码复制到Voting.sol文件中,并将该文件置于hello_world_voting目录下。现在让我们编译代码并将其部署到ganache区块链。

     为了编译Solidity代码,需要安装npm模块solc:

    czk@czk-vm:~/work/hello_world_voting$ npm install solc
    + solc@0.4.24

    我们将在节点控制台内使用这个库来编译我们的合同。

    web3js是一个库,可让您通过RPC与区块链进行交互。我们将使用该库来部署我们的应用程序并与其进行交互。

     

    首先,在终端中运行'node'命令以进入节点控制台并初始化solc和web3对象。下面的所有代码片段都需要在节点控制台中输入。

    czk@czk-vm:~/work/hello_world_voting$ node
    > Web3 = require('web3')
    > web3 = new Web3(new Web3.providers.HttpProvider("http://localhost::8545"));

    为了确保web3对象被初始化并且可以与区块链进行通信,我们来查询区块链中的所有帐户。你应该看到如下结果:

     

    将Voting.sol中的代码加载到字符串变量中并进行编译。

    > code = fs.readFileSync('Voting.sol').toString()
    > solc = require('solc')
    > compiledCode = solc.compile(code)

    当成功编译代码并打印'contract'对象(只需在node控制台中键入compiledCode)时,其中有两个重要的字段:

    1. compiledCode.contracts[‘:Voting’].bytecode: 这是在编译Voting.sol中的源代码时获得的字节码。这是会被部署到区块链的代码。

    2. compiledCode.contracts[‘:Voting’].interface: 这是合约的接口或模板(称为abi, Application Binary Interface),它告诉合约用户合约中有哪些方法可用。无论何时需要与合同进行交互,都需要此abi。

    现在我们来部署合约。您首先创建一个合约对象(下面的VotingContract),用于在区块链中部署和启动合约。

    > abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
    > VotingContract = web3.eth.contract(abiDefinition)
    > byteCode = compiledCode.contracts[':Voting'].bytecode
    > deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
    > deployedContract.address
    > contractInstance = VotingContract.at(deployedContract.address)

    上面的VotingContract.new将合约部署到区块链。我们现在已经部署了合约,并且有一个合约实例(上面的可变contractInstance),我们可以使用它来与合约进行交互。在区块链上部署了数十万个合约。那么,你如何在区块链中识别你的合约呢?答案:deployedContract.address。

    当与的合约进行交互时,需要合约部署地址和合约的abi。

    3. 在nodejs控制台中与合约进行交互

    4. 通过网页与区块链上的合约交互

    现在大部分工作都已完成,现在我们所要做的就是创建一个带候选人名字的简单html文件,并在js文件中调用投票命令(我们已经在nodejs控制台中测试过)。 以下是index.html文件和index.js代码,将它们都放在hello_world_voting目录中,然后在浏览器中打开index.html。

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4   <title>Hello World DApp</title>
     5   <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
     6   <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
     7 </head>
     8 <body class="container">
     9   <h1>A Simple Hello World Voting Application</h1>
    10   <div class="table-responsive">
    11     <table class="table table-bordered">
    12       <thead>
    13         <tr>
    14           <th>Candidate</th>
    15           <th>Votes</th>
    16         </tr>
    17       </thead>
    18       <tbody>
    19         <tr>
    20           <td>Rama</td>
    21           <td id="candidate-1"></td>
    22         </tr>
    23         <tr>
    24           <td>Nick</td>
    25           <td id="candidate-2"></td>
    26         </tr>
    27         <tr>
    28           <td>Jose</td>
    29           <td id="candidate-3"></td>
    30         </tr>
    31       </tbody>
    32     </table>
    33   </div>
    34   <input type="text" id="candidate" />
    35   <a href="#" onclick="VoteToCandidate()" class="btn btn-primary">Vote</a>
    36 </body>
    37 <script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
    38 <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
    39 <script src="./index.js"></script>
    40 </html>

    注:以上代码运行时,可能会出现无法连接到网站错误。在虚拟机中无法打开这个网页,但是在windows中浏览器中可以打开。。。。将该网页中的js代码保存为web3.js文件,放入工作index.html同一目录,将37行改为 如下代码即可。

    <script src="./web3.js"></script>

    index.js:

     1 web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
     2 abi = JSON.parse('[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"candidateVotes","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"VoteToCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","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"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]')
     3 VotingContract = web3.eth.contract(abi);
     4 // In your nodejs console, execute contractInstance.address to get the address at which the contract is deployed and change the line below to use your deployed address
     5 contractInstance = VotingContract.at('0x5367391364f427209e5f08acd260f21abb15ba30');
     6 candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
     7 
     8 function VoteToCandidate() {
     9   candidateName = $("#candidate").val();
    10   contractInstance.VoteToCandidate(candidateName, {from: web3.eth.accounts[0]}, function() {
    11     let div_id = candidates[candidateName];
    12     $("#" + div_id).html(contractInstance.candidateVotes.call(candidateName).toString());
    13   });
    14 }
    15 
    16 $(document).ready(function() {
    17   candidateNames = Object.keys(candidates);
    18   for (var i = 0; i < candidateNames.length; i++) {
    19     let name = candidateNames[i];
    20     let val = contractInstance.candidateVotes.call(name).toString()
    21     $("#" + candidates[name]).html(val);
    22   }
    23 });

    用浏览器打开index.html文件,你将看到一下内容。

     如果您可以在文本框中输入候选人姓名并进行投票,可以看到查看投票计数增加,那么您已经成功创建了第一个应用程序!恭喜!

    总结一下,本文设置了开发环境,编写简单的合同,在区块链上编译和部署合同,并通过nodejs控制台和网页与其交互。

     

    在Part2部分,我们将把这个合同部署到公共测试网络,以便全世界都可以看到它并投票给候选人。并使用Truffle框架进行开发(而不必使用nodejs控制台来管理整个过程)。

  • 相关阅读:
    HTML5标签
    CTF web之旅 45
    CTF web之旅44
    CTF web之旅 43
    CTF web之旅 42
    CTF web之旅41
    CTF web之旅40
    CTF web之旅 39
    CTF web之旅 38
    CTF web之旅 37
  • 原文地址:https://www.cnblogs.com/sclczk/p/9142159.html
Copyright © 2011-2022 走看看