【智能合约】Solidity - 编程实例

Solidity - 编程实例


1. 投票

接下来的合约非常复杂,但展示了很多Solidity的特性。它实现了一个投票合约。当然,电子选举的主要问题是如何赋予投票权给准确的人,并防止操纵。我们不能解决所有的问题,但至少我们会展示如何委托投票可以同时做到投票统计是自动和完全透明。

思路是为每张选票创建一个合约,每个投票选项提供一个短名称。合约创建者作为会长将会给每个投票参与人各自的地址投票权。

地址后面的人们可以选择自己投票或者委托信任的代表人替他们投票。在投票结束后,winningProposal()将会返回获得票数最多的提案。
pragma solidity ^0.4.11;

contract Ballot {

    //独立投票人
    struct Voter {
        uint weight; // 累积的权重
        bool voted;  // 判断是否已投票
        address delegate; // 委托投票人地址
        uint vote;   // 投票选择的提案索引号
    }

    //这是一个独立提案的类型
    struct Proposal {
        bytes32 name;   // 提案名称
        uint voteCount; // 票数
    }

    address public chairperson;  //合约创建人地址
    mapping(address => Voter) public voters;  //投票人数组
    Proposal[] public proposals;  //提案数组

    /// 初始化,传入多个提案名称
    function Ballot(bytes32[] proposalNames) {
        chairperson = msg.sender;  
        voters[chairperson].weight = 1; 

        //初始化提案,名称 + 初始票数
        for (uint i = 0; i < proposalNames.length; i++) {
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount: 0
            }));
        }
    }

    // 给予投票人,投票的权利
    function giveRightToVote(address voter) {
        require((msg.sender == chairperson) && !voters[voter].voted && (voters[voter].weight == 0));
        voters[voter].weight = 1;
    }

    // 将自己的投票权委托给别人-to
    function delegate(address to) {

        Voter storage sender = voters[msg.sender];
        require(!sender.voted);  //自己已投票,则无票委托给别人

        require(to != msg.sender);  //不能是自己

        //当投票代表`to`也委托给别人时,寻找到最终的投票代表
        while (voters[to].delegate != address(0)) {
            to = voters[to].delegate;
            require(to != msg.sender);
        }

        sender.voted = true;
        sender.delegate = to;
        Voter storage delegate = voters[to];
        if (delegate.voted) {
            //如果委托的投票代表已经投票了,直接修改票数
            proposals[delegate.vote].voteCount += sender.weight; 
        } else {
            //如果投票代表还没有投票,则修改其投票权重。
            delegate.weight += sender.weight; 
        }
    }

    //投出你的选票(包括委托给你的选票)
    function vote(uint proposal) {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted);
        sender.voted = true;
        sender.vote = proposal;
        proposals[proposal].voteCount += sender.weight;
    }

    //根据当前所有的投票计算出当前的胜出提案
    function winningProposal() constant
            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() constant
            returns (bytes32 winnerName)
    {
        winnerName = proposals[winningProposal()].name;
    }
}

2. 简单的公开拍卖

通常简单的公开拍卖合约,是每个人可以在拍卖期间发送他们的竞拍出价。为了实现绑定竞拍人的到他们的拍卖,竞拍包括发送金额ether。如果产生了新的最高竞拍价,前一个最高价竞拍人将会拿回他的钱。在竞拍阶段结束后,受益人人需要手动调用合约收取他的钱 — — 合约不会激活自己。
pragma solidity ^0.4.11;

contract SimpleAuction {

    address public beneficiary; //拍卖发起人
    uint public auctionStart;  //记录开始时间,秒为单位
    uint public biddingTime;  //拍卖时长

    //当前拍卖状态
    address public highestBidder;
    uint public highestBid;

    mapping(address => uint) pendingReturns; //用户存在该合约(需退回)的金额

    //在结束时设置为true来拒绝任何改变
    bool ended;

    //当改变时将会触发的Event
    event HighestBidIncreased(address bidder, uint amount);
    event AuctionEnded(address winner, uint amount);

    //初始化:发起人,开始时间,拍卖时长。
    function SimpleAuction(uint _biddingTime, address _beneficiary) {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingTime = _biddingTime;
    }

    function bid() payable {

        require(now <= (auctionStart + biddingTime));  //要求拍卖未结束
        require(msg.value > highestBid); // 如果给出的金额小于当前最高价,会退回钱

        //退回上一位最高价
        if (highestBidder != 0) {
            //上一位出最高价的人,需退回的金额加上他出的价。
            pendingReturns[highestBidder] += highestBid;  
        }
        //修改最高价
        highestBidder = msg.sender;
        highestBid = msg.value;
        HighestBidIncreased(msg.sender, msg.value);
    }

    //提现
    function withdraw() returns (bool) {
        uint amount = pendingReturns[msg.sender]; //用户需退回的金额
        if (amount > 0) {
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)) {
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    //拍卖结束,最高价的金额发送给拍卖者
    function auctionEnd() {
        //要求拍卖结束
        require(now >= (auctionStart + biddingTime)); 
        require(!ended);

        //修改拍卖参数,设置为结束
        ended = true;
        AuctionEnded(highestBidder, highestBid);

        //发送金额给拍卖者
        beneficiary.transfer(highestBid);
    }
}

3.盲拍

接下来扩展前面的公开拍卖成为一个盲拍。盲拍的特点是拍卖结束以前没有时间压力。在一个透明的计算平台上创建盲拍系统听起来可能有些矛盾,但是加密算法能让你脱离困境。

在拍卖阶段, 竞拍人不需要发送实际的出价,仅仅只需要发送一个它的散列值。因为目前几乎不可能找到两个值(足够长)的散列值相等,竞拍者提交他们的出价散列值。在拍卖结束后,竞拍人重新发送未加密的竞拍出价,合约将检查其散列值是否和拍卖阶段发送的一样。 另一个挑战是如何让拍卖同时实现绑定和致盲 :防止竞拍人竞拍成功后不付钱的唯一的办法是,在竞拍出价的同时发送保证金。但是在Ethereum上发送保证金是无法致盲,所有人都能看到保证金。下面的合约通过接受任何尽量大的出价来解决这个问题。当然这可以在最后的揭拍阶段进行复核,一些竞拍出价可能是无效的,这样做的目的是(它提供一个显式的标志指出是无效的竞拍,同时包含高额保证金):竞拍人可以通过放置几个无效的高价和低价竞拍来混淆竞争对手。
pragma solidity ^0.4.11;

contract BlindAuction {
    struct Bid {
        bytes32 blindedBid;
        uint deposit;
    }

    address public beneficiary;  //拍卖发起人
    uint public auctionStart;
    uint public biddingEnd;
    uint public revealEnd;
    bool public ended;

    mapping(address => Bid[]) public bids;

    address public highestBidder;
    uint public highestBid;

    mapping(address => uint) pendingReturns; 

    event AuctionEnded(address winner, uint highestBid);

    modifier onlyBefore(uint _time) { require(now < _time); _; }
    modifier onlyAfter(uint _time) { require(now > _time); _; }

    //初始化
    function BlindAuction(uint _biddingTime, uint _revealTime, address _beneficiary) {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingEnd = now + _biddingTime;
        revealEnd = biddingEnd + _revealTime;
    }

    /*放置一个盲拍出价使用`_blindedBid`=sha3(value,fake,secret).
      仅仅在竞拍结束正常揭拍后退还发送的以太。
      当随同发送的以太至少等于 "value"指定的保证金并且 "fake"不为true的时候才是有效的竞拍出价。
      同一个地址可以放置多个竞拍*/
    function bid(bytes32 _blindedBid) payable onlyBefore(biddingEnd){
        bids[msg.sender].push(Bid({
            blindedBid: _blindedBid,
            deposit: msg.value
        }));
    }

    //揭开你的盲拍竞价。你将会拿回除了最高出价外的所有竞拍保证金,以及正常的无效盲拍保证金。
    function reveal(uint[] _values, bool[] _fake, bytes32[] _secret)
        onlyAfter(biddingEnd) onlyBefore(revealEnd) {
        uint length = bids[msg.sender].length;
        require(_values.length == length);
        require(_fake.length == length);
        require(_secret.length == length);

        uint refund;
        for (uint i = 0; i < length; i++) {
            var bid = bids[msg.sender][i];
            var (value, fake, secret) = (_values[i], _fake[i], _secret[i]);
            if (bid.blindedBid != keccak256(value, fake, secret)) {
                continue;
            }
            refund += bid.deposit;
            if (!fake && bid.deposit >= value) {
                if (placeBid(msg.sender, value))
                    refund -= value;
            }
            bid.blindedBid = bytes32(0);
        }
        msg.sender.transfer(refund);
    }

    //这是一个内部 (internal)函数,意味着仅仅只有合约(或者从其继承的合约)可以调用
    function placeBid(address bidder, uint value) internal
            returns (bool success)
    {
        if (value <= highestBid) {
            return false;
        }
        if (highestBidder != 0) {
            //退还前一个最高竞拍出价
            pendingReturns[highestBidder] += highestBid;
        }
        highestBid = value;
        highestBidder = bidder;
        return true;
    }

    //提现多余付出的金额
    function withdraw() {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            pendingReturns[msg.sender] = 0;
            msg.sender.transfer(amount);
        }
    }

    //竞拍结束后发送最高出价到竞拍人
    function auctionEnd() onlyAfter(revealEnd)
    {
        require(!ended);
        AuctionEnded(highestBidder, highestBid);
        ended = true;
        beneficiary.transfer(this.balance);
    }
}

转载自:here
参考原文:here

你可能感兴趣的:(区块链)