solidity实例

pragma solidity ^0.4.0

//投票
contract toupiao {
    //结构体,一个投票人
    struct Voter {
        uint weight; //通过代理积累权重
        bool voted; //是否投票
        address delegate; // 代理人
        uint vote; //选择的提案编号
    }

    //结构体,一个提案
    struct Proposal {
        bytes32 name;    //提案名(最多32个字符)

        uint voteCount;  //投票数量
    }

    address public chairperson;  //主持人

    //保存从地址到投票人数据的映射
    mapping (address => Voter) public voters;
    
    //提案数组
    Proposal[] public proposals;

    //函数基于一组提案,构建一个投票协议
    function Ballots(bytes32[] proposalNames) public {
        chairperson = msg.sender; //协议创建人为主持人
        voters[chairperson].weight = 1; //主持人的投票权重为1


    //针对每一个提案名,创建一个对应的提案,并且保存在  Proposal中,
        for (uint i=0;i<proposalNames.length; i++){
            //
            proposals.push(
                Proposal{
                    name:proposalNames[i];
                    voteCount:0;
                })
        }
    }
    // 主席给予一个人投票的权利
    function giveRightToVote(address voter) public {
        // 如果require的执行失败,则会终止程序,之前的所有修改都会被还原
        // 在历史的EVM版本中,这会消耗所有的gas,但现在已经被取消
        // 建议使用Require来检查函数的正确性和安全性
        // 可以选择传入第二个参数,对错误加以解释
        require(
            msg.sender == chairperson,
            "Only chairperson can give right to vote."
        );
        require(
            !voters[voter].voted,
            "The voter already voted."
        );
        require(voters[voter].weight == 0); // 注意,这里并没有创建voters[voter]
        voters[voter].weight = 1;
    }

    //把你的投票权代理给另一个人
    function delegate(address to) public {
        // 获得当前用户持久数据的引用
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "You already voted.");

        require(to != msg.sender, "Self-delegation is disallowed."); // 不能自己代理自己

        // 因为被代理人也可能找人代理,因此要找到最初的代理人
        // 这个循环可能很危险,因为执行时间可能很长,从而消耗大量的gas
        // 当gas被耗尽,将无法代理
        while (voters[to].delegate != address(0)) {
            to = voters[to].delegate;

            // 防止出现循环,但是并没有检查不包含sender的loop,也许不会出现呢:)
            require(to != msg.sender, "Found loop in delegation.");
        }

        // 因为sender是引用传递,因此会修改全局变量voters[msg.sender]的值
        sender.voted = true;
        sender.delegate = to;
        Voter storage delegate_ = voters[to];
        if (delegate_.voted) {
            // 如果已经投票了,增加提案的权重;QY:这里最好也能增加代理人权重
            proposals[delegate_.vote].voteCount += sender.weight;
        } else {
            // 如果没有投票,增加代理人的权重
            delegate_.weight += sender.weight;
        }
    }

    // 进行投票
    function vote(uint proposal) public {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "Already voted.");
        sender.voted = true;
        sender.vote = proposal;

        // 如果proposals的数组越界,会自动失败,并且还原变化
        proposals[proposal].voteCount += sender.weight;
    }

    //计算胜出的提案,QY:如果都是0怎么办?
    function winningProposal() public view
            returns (uint winningProposal_)
    {
        uint winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++) {
            if (proposals[p].voteCount > winningVoteCount) {
                winningVoteCount = proposals[p].voteCount;
                winningProposal_ = p;
            }
        }
    }

    // 找到胜出的提案,然后返回胜出的名字
    function winnerName() public view
            returns (bytes32 winnerName_)
    {
        winnerName_ = proposals[winningProposal()].name;
    }
}

 涉及知识点

状态变量

状态变量是永久地存储在合约存储中的值

局部变量

局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas

全局变量

全局变量是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用

数据位置

solidity数据存储位置有三类:storagememorycalldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memorycalldata类型的临时存在内存里,消耗gas少。大致用法:

  1. storage:合约里的状态变量默认都是storage,存储在链上。

  2. memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。

  3. calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改,一般用于函数的参数

流程如下:

  • 基于一系列的提案创建一个投票的智能合约
  • 主持人可以添加多个投票人
  • 每个投票人可以自己投票,或者让他人代理自己
  • 我们可以统计当前最高票的提案

合约调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值