美文网首页Dapp开发
全栈投票Dapp教程—第三部分

全栈投票Dapp教程—第三部分

作者: rajs20222007 | 来源:发表于2018-08-26 22:02 被阅读10次

    本教程翻译自Mahesh Murthy的教程.
    文章链接如下:

    1. https://medium.com/@mvmurthy/full-stack-hello-world-voting-ethereum-dapp-tutorial-part-1-40d2d0d807c2
    2. https://medium.com/@mvmurthy/full-stack-hello-world-voting-ethereum-dapp-tutorial-part-2-30b3d335aa1f
    3. https://medium.com/@mvmurthy/full-stack-hello-world-voting-ethereum-dapp-tutorial-part-3-331c2712c9df

    教程的所有代码可以在这里看到.

    在第1部分中, 我们构建了一个简单的投票Dapp, 并使其在本地运行. 在第2部分中, 我们将应用移至truffle框架, 并将其部署到Ropsten测试网络, 通过truffle控制台和网页与其进行交互. 在本教程中, 我们将为投票Dapp添加更多功能, 以便学习一些关键概念. 以下是你将在本教程中学到的内容:

    1. 学习新数据类型, 例如使用结构体来组织和存储区块链上的数据.
    2. 了解令牌的概念及其用法.
    3. 学习使用以太币, 即以太坊区块链平台的货币进行付款.

    通常在投票中, 每个公民都可以给他喜欢的候选人投一张选票. 然而有一些特色的投票中, 比如选举公司董事会时, 股东可以根据在公司拥有的股票数量进行投票. 当其拥有的股票越多, 其可以投的票数也就越多.

    我们要增加我们的Dapp功能, 让其支持这样的选举. 我们会添加功能让每个人都可以购买公司的股票. 他们可以用他们的股票数来给候选人投票. 我们还会添加一个功能来查看投票人的信息. 在以太坊区块链中, 股票更像是令牌的概念. 因此本文的后部分将使用令牌数量来代替股票.

    第一步是声明我们用来存储我们感兴趣信息的变量. 下面是带有注释的合约变量:

    // 我们使用结构体来存储投票人的信息
    struct voter {
        address voterAddress; // 投票人地址
        uint tokensBought;    // 投票人拥有令牌数
        uint[] tokensUsedPerCandidate; // 投票人给每个候选人的投票数
        /* 我们有一个candidateList数组在下面初始化了.
        每一次这个投票人用他的令牌投票的时候, 数组中候选人所在的次序就会增加.
        例如: 如果候选人列表声明为「"Rana", "Nick", "Jose"」,
        投票人用十个令牌投票给Nick, tokensUsedPerCanditate[1]就会增加10.
         */
    }
    /* mapping等效一个关系数组或者哈希.
       mapping的键是以bytes32类型存储的候选人名.
       mapping的值是以无符号整型存储的得票数量.
     */
    mapping (bytes32 => uint) public votesReceived;
    mapping (address => voter) public voterInfo;
    /* Solidity目前还不允许返回数组或者字符串.
       我们使用一组bytes32类型来替代存储候选人名单.
     */
    bytes32[] public candidateList;
    uint public totalTokens; // 可供选举的总的令牌数
    uint public balanceTokens; // 仍然可以购买的令牌数
    uint public tokenPrice; // 每个令牌的价格
    

    在教程1和教程2中, 我们初始化了在构造函数中的候选者列表. 在区块链上部署合约时, 只调用一次构造函数. 本文中, 我们还必须使用可供销售的令牌总数和每个令牌的成本初始化合约. 所以, 我们更新我们的合约构造函数, 如下所示:

    /* 当合约部署在区块链上时,
       我们会初始化我们所有提供销售的令牌, 
       每个令牌的价格和所有的候选人.
     */
    function Voting(uint tokens, uint pricePerToken, bytes32[] candidateNames) public {
        candidateList = candidateNames;
        totalTokens = tokens;
        balanceTokens = tokens;
        tokenPrice = pricePerToken;
    }
    

    在truffle中, 你可以使用migrations将代码部署到区块链. 点击这里可以查看migration文件. Truffle的migration文件中的示例部署调用如下所示:

    deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
    // 1000是总的提供出售的令牌数, 每个令牌的价格是0.1以太币.
    // 我们会在教程的后面再说到这个代码.
    

    现在我们已经初始化了令牌并设定了价格, 让我们看看如何使用以太币来购买令牌. 下面是购买令牌的功能.

    /* 这个方法是用来交易令牌的. 注意下面的关键字'payable'.
     仅仅给方法增加一个关键字, 你的合约就可以接受任何人的以太币来调用这个方法.
     没比这更简单的赚钱方法了.
     */
    function buy() payable public returns (uint) {
        uint tokensToBuy = msg.value / tokenPrice;
        if (tokensToBuy > balanceTokens) throw;
        voterInfo[msg.sender].voterAddress = msg.sender;
        voterInfo[msg.sender].tokensBought += tokensToBuy;
        balanceTokens -= tokensToBuy;
        return tokensToBuy;
    }
    

    一个交易调用例子如下:

    truffle(development)> Voting.deployed().then(function(contract) {contract.buy({value: web3.toWei('1', 'ether'), from: web3.eth.accounts[1]})})
    

    buy()方法中的value: web3.toWei(‘1’, ‘ether’)参数使用msg.value和msg.sender传递web3.eth.accounts[1]中的用户地址. 每个令牌的价值被设置为0.1以太币, web3.eth.accounts[1]会收到1以太币=10个令牌.

    让我们暂时不去查看代码, 想象一下选民和合约之间的互动.

    交互内容

    合约中需要增加一些getter类型的方法, 很容易理解.

    index.html文件也有一些新的更新:

    1. 要为候选人投票, 必须指定投票的令牌数量.
    2. 购买令牌的功能.
    3. 查看投票人信息 - 他们拥有多少令牌而不是他们投给每位候选人的令牌数.
    4. 候选人不再是硬编码, 我们从区块链中取出候选人并填充它.

    app.js文件具有支持上述所有UI功能的更新.

    更新部署文件2_deploy_contracts.js以传递总令牌和令牌价格以及候选人名称.

    var Voting = artifacts.require("./Voting.sol");
    module.exports = function(deployer) {
      deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
    };
    

    总而言之,我们在本教程中更新的四个文件是Voting.sol, index.html, app.js和2_deploy_contracts.js. 使用这些文件更新truffle仓库后, 我们可以将合约部署到区块链. 部署过程与上一个教程完全相同.

    只需使用truffle命令进行编译和迁移.

    truffle migrate
    Using network 'development'.
    Compiling Migrations.sol...
    Compiling Voting.sol...
    Writing artifacts to ./build/contracts
    Running migration: 1_initial_migration.js
    Deploying Migrations...
    Migrations: 0xc9249947010675b8a3b1defb12334148f7f59010
    Saving successful migration to network...
    ![3.2.png](https://img.haomeiwen.com/i13040345/995e57bfb91ca567.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    Saving artifacts...
    Running migration: 2_deploy_contracts.js
    Deploying Voting...
    Voting: 0x795d6d1f7cf467f27e48181da5f1ebd5bbd0a8df
    Saving successful migration to network...
    Saving artifacts...
    

    如果你能够成功部署合同并启动Web服务器, 那么您的页面将如下所示:

    Web页面

    正如在上面的屏幕截图中所看到的, 你可以购买令牌, 使用令牌为候选人投票并按地址查找选民信息. 如果您能够使所有这些功能正常工作, 恭喜!

    相关文章

      网友评论

        本文标题:全栈投票Dapp教程—第三部分

        本文链接:https://www.haomeiwen.com/subject/apdaiftx.html