通过例子学Solidity[注释翻译]

[官方译文(2)] 通过例子学Solidity[注释翻译]

继续翻译Solidity的官方文档, 以此也算是自己的学习

[Solidity官方手册](https://solidity.readthedocs.io/zh/latest/solidity-by-example.html)

投票(voting)

下面的合同十分的复杂, 但是的确是展现出了`Solidity`的许多特性. 它实现了一个投票的合约. 当然, 电子投票的主要的问题, 如何给当前的投票人分发票 和 如何保证正常的进行. 在这里我们并不会解决所有的问题, 但是 至少我们将展现如何进行一场自动化进行和完全透明的委托投票

主要的思路是是对每一个票创建一个合约, 对每个选项提供一个短的名称. 合约的创建者 就作为这次投票的主持人(chairperson)将会给与其他独立地址的投票权利

这些账户(可投票)的拥有者可以自己投这一票, 或者把自己的票委托(delegate)给他们信任的人

在这次投票结束的时候, `winningProposal()` (function)将会返回这个票数最多的人

(下面是实例的投票代码, 翻译水平有限..保留部分原文翻译)

 pragma solidity ^0.4.11;

/// @title Voting with delegation.
contract Ballot {
    // This declares a new complex type which will
    // be used for variables later.
    // It will represent a single voter.
     (声明一个新的class 将会成为一个变量, 会代表其中的一个投票者)

    struct Voter {
        uint weight; // weight is accumulated(积累) by delegation(委托)
        bool voted;  // if true, that person already voted
        address delegate; // person delegated to    (你所委托的人)
        uint vote;   // index of the voted proposal (投票索引号)
    }

    // This is a type for a single proposal. (单个提案类型)
    struct Proposal {
        bytes32 name;   // short name (up to 32 bytes)
        uint voteCount; // number of accumulated votes(累计票数)
    }

    address public chairperson;

    // This declares a state variable that
    // stores a `Voter` struct for each possible address.
    (这里创建里一个投票者的变量, 用于保存每个投票者的地址)
    mapping(address => Voter) public voters;

    // A dynamically-sized array of `Proposal` structs.(一个动态分配的票据结构)
    Proposal[] public proposals;

    /// Create a new ballot to choose one of `proposalNames`. (创建一个新的票据来选择一个提案名称)
    function Ballot(bytes32[] proposalNames) {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;

        // For each of the provided proposal names, (每一个选举人的名字创建单个的选举对象, 并且添加到数组的尾部)
        // create a new proposal object and add it
        // to the end of the array.
        for (uint i = 0; i < proposalNames.length; i++) {
            // `Proposal({...})` creates a temporary
            // Proposal object and `proposals.push(...)`
            // appends it to the end of `proposals`.    (意向人对象`proposal`, 使用proposal.push(), 把意向人压入)
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount: 0
            }));
        }
    }

    // Give `voter` the right to vote on this ballot.   (给与投票者投票权益)
    // May only be called by `chairperson`.     (只可能是被支持人所调用)
    function giveRightToVote(address voter) {
        // If the argument of `require` evaluates to `false`,   (如何请求的值是 false , 这个将会被终结, 并且回滚所有的改变)
        // it terminates and reverts all changes to
        // the state and to Ether balances. It is often (如果函数被非法调用, 这将会是个很好的办法)
        // a good idea to use this if functions are
        // called incorrectly. But watch out, this      (但是需要注意的是, 这将会消耗当前所有的 gas(在未来可能有所改善))
        // will currently also consume all provided gas
        // (this is planned to change in the future).
        require((msg.sender == chairperson) && !voters[voter].voted && (voters[voter].weight == 0));
        voters[voter].weight = 1;
    }

    /// Delegate your vote to the voter `to`.   (委托你的票到其他的可信投票者)
    function delegate(address to) {
        // assigns reference
        Voter storage sender = voters[msg.sender];
        require(!sender.voted); (这里保证是没有投过票的)

        // Self-delegation is not allowed.  (不允许自己投给自己)
        require(to != msg.sender);

        // Forward the delegation as long as
        // `to` also delegated.
        // In general, such loops are very dangerous,
        // because if they run too long, they might
        // need more gas than is available in a block.
        // In this case, the delegation will not be executed,
        // but in other situations, such loops might
        // cause a contract to get "stuck" completely.
        (这里避免一个循环委托的可能性 , 如果A委托给B, B委托给其他人,最终到了A )

        while (voters[to].delegate != address(0)) {
            to = voters[to].delegate;

            // We found a loop in the delegation, not allowed.
            require(to != msg.sender);
        }

        // Since `sender` is a reference, this
        // modifies `voters[msg.sender].voted`
        sender.voted = true;
        sender.delegate = to;
        Voter storage delegate = voters[to];
        if (delegate.voted) {
            // If the delegate already voted,   (如果委托投票已经投过, 直接修改票数)
            // directly add to the number of votes
            proposals[delegate.vote].voteCount += sender.weight; (投票权重)
        } else {
            // If the delegate did not vote yet,
            // add to her weight.
            delegate.weight += sender.weight;
        }
    }

    /// Give your vote (including votes delegated to you) (投出你的票票)
    /// to proposal `proposals[proposal].name`.

    function vote(uint proposal) {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted); (require 是新版的语法)
        sender.voted = true;
        sender.vote = proposal;

        // If `proposal` is out of the range of the array,(如果提案超出了索引范围, 直接回滚所有数据)
        // this will throw automatically and revert all
        // changes.
        proposals[proposal].voteCount += sender.weight;
    }

    /// @dev Computes the winning proposal taking all (根据记票找到最终 的胜出者)
    /// previous votes into account.
    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;
            }
        }
    }

    // Calls winningProposal() function to get the index
    // of the winner contained in the proposals array and then
    // returns the name of the winner
    function winnerName() constant
            returns (bytes32 winnerName)
    {
        winnerName = proposals[winningProposal()].name;
    }
}

可能的改进

现在如果,需要指派票权到其他的账户,参加多个投票,有好的方案吗?

盲拍

这一节,我们将展示在以太上创建一个完整的盲拍合约是多么简单. 我们从一个所有人都能看到出价的公开拍卖开始,接着扩展合约成为一个在 **拍卖结束以前不能看到实际出价的盲拍**.

简单的公开拍卖 (Simple Open Auction)

通常简单的公开拍卖合约, 是每个人可以在拍卖期间提出他们的竞拍出价。为了实现竞拍人和他们竞拍内容的绑定,竞拍包括发送金额/ether。如果产生了新的最高竞拍价,前一个最高价竞拍人将会拿回他的钱。在竞拍阶段结束后,受益人人需要手动调用合约收取他的钱 (合约不会激活自己. )(合约是存在的函数,需要用户去调用它 , 他是不能调用自己的)

 pragma solidity ^0.4.11;

contract SimpleAuction {
    // Parameters of the auction. Times are either  (拍卖参数)
    // absolute unix timestamps (seconds since 1970-01-01) (自unix时间戳的绝对时间)
    // or time periods in seconds.
    address public beneficiary;
    uint public auctionStart;
    uint public biddingTime;

    // Current state of the auction.    (当前的拍卖状态)
    address public highestBidder;
    uint public highestBid;

    // Allowed withdrawals of previous bids (可以撤出之前的投标)
    mapping(address => uint) pendingReturns;

    // Set to true at the end, disallows any change (已经结束就不允许任何改变)
    bool ended;

    // Events that will be fired on changes.    (当有了改变的时候, 事件将会被触发)
    event HighestBidIncreased(address bidder, uint amount); (到了最高标)
    event AuctionEnded(address winner, uint amount);    (结束)

    // The following is a so-called natspec comment,
    // recognizable by the three slashes.   (三个斜杠(slash) 的注释是一个 natspec 的注释)
    // It will be shown when the user is asked to
    // confirm a transaction.

    /// Create a simple auction with `_biddingTime` (竞拍时间)
    /// seconds bidding time on behalf of the
    /// beneficiary address `_beneficiary`. (实际竞拍者账户) (_是private的变量(约定习惯))
    function SimpleAuction(
        uint _biddingTime,
        address _beneficiary
    ) {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingTime = _biddingTime;
    }

    /// Bid on the auction with the value sent (对拍卖的竞拍金会随着交易事务一起发送,)
    /// together with this transaction.
    /// The value will only be refunded if the  (只有没有拍得的时候, 金额才会被退回)
    /// auction is not won.
    function bid(出价)() payable {
        // No arguments are necessary, all  (不需要参数, 数据是交易的一部分)
        // information is already part of
        // the transaction. The keyword payable
        // is required for the function to
        // be able to receive Ether.

        // Revert the call if the bidding   (回滚这个调用, 如果标已经结束)
        // period is over.
        require(now <= (auctionStart + biddingTime));

        // If the bid is not higher, send the
        // money back.
        require(msg.value > highestBid);    (如果不是最高出价, 那么把保证金返回)

        if (highestBidder != 0) {
            // Sending back the money by simply using   
            // highestBidder.send(highestBid) is a security risk
            (只是用上述函数把币送回是有个安全隐患)
            // because it could execute an untrusted contract.  (因为可能执行一个 不可信任的合约)
            // It is always safer to let the recipients
            // withdraw their money themselves.
            pendingReturns[highestBidder] += highestBid;
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
        HighestBidIncreased(msg.sender, msg.value);
    }

    /// Withdraw a bid that was overbid. (出价过高的退款)
    function withdraw() returns (bool) {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            // It is important to set this to zero because the recipient
            // can call this function again as part of the receiving call
            // before `send` returns.
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)) {
                // No need to call throw here, just reset the amount owing
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    /// End the auction and send the highest bid    (结束拍卖,最高者得标)
    /// to the beneficiary(受惠者).
    function auctionEnd() {
        // It is a good guideline to structure functions that interact
        // with other contracts (i.e. they call functions or send Ether)
        // into three phases:
        // 1. checking conditions
        // 2. performing actions (potentially changing conditions)
        // 3. interacting with other contracts
        // If these phases are mixed up, the other contract could call
        // back into the current contract and modify the state or cause
        // effects (ether payout) to be performed multiple times.
        // If functions called internally include interaction with external
        // contracts, they also have to be considered interaction with
        // external contracts.

        // 1. Conditions (当前情况)
        require(now >= (auctionStart + biddingTime)); // auction did not yet end
        require(!ended); // this function has already been called

        // 2. Effects   (结果)
        ended = true;
        AuctionEnded(highestBidder, highestBid);    (处理合约中的钱)

        // 3. Interaction   (通知, 交互)
        beneficiary.transfer(highestBid);   (给标)
    }
}

盲拍 (Blind Auction )

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

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

注: 理解上是, 把hash(出价 + 混淆金) 发给合约, 等待竞拍结束. 每个人发送自己的 明文出价(cleartext), 之后由合约验证 , hash(出价+混) 是否等于之前的 hash.

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;

    event AuctionEnded(address winner, uint highestBid);

   ///修饰器(Modifier)是一个简便的途径用来验证函数输入的有效性。
   ///`onlyBefore` 应用于下面的 `bid`函数,其旧的函数体替换修饰器主体中 `_`后就是其新的函数体
    modifier onlyBefore(uint _time) { if (now >= _time) throw; _ }
    modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }

    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的时候才是有效的竞拍
   ///出价。设置 "fake"为true或发送不合适的金额将会掩没真正的竞拍出
   ///价,但是仍然需要抵押保证金。同一个地址可以放置多个竞拍。
    function bid(bytes32 _blindedBid)
        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;
        if (_values.length != length || _fake.length != length ||
                    _secret.length != length)
            throw;
        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 != sha3(value, fake, secret))
                //出价未被正常揭拍,不能取回保证金。
                continue;
            refund += bid.deposit;
            if (!fake && bid.deposit >= value)
                if (placeBid(msg.sender, value))
                    refund -= value;
            //保证发送者绝不可能重复取回保证金
            bid.blindedBid = 0;
        }
        msg.sender.send(refund);
    }

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

   ///竞拍结束后发送最高出价到竞拍人
    function auctionEnd()
        onlyAfter(revealEnd)
    {
        if (ended) throw;
        AuctionEnded(highestBidder, highestBid);
        //发送合约拥有所有的钱,因为有一些保证金退回可能失败了。
        beneficiary.send(this.balance);
        ended = true;
    }

    function () { throw; }
}
Safe Remote Purchase 安全的远程购物

contract Purchase
{
    uint public value;
    address public seller;
    address public buyer;
    enum State { Created, Locked, Inactive }
    State public state;
    function Purchase()
    {
        seller = msg.sender;
        value = msg.value / 2;
        if (2 * value != msg.value) throw;
    }
    modifier require(bool _condition)
    {
        if (!_condition) throw;
        _
    }
    modifier onlyBuyer()
    {
        if (msg.sender != buyer) throw;
        _
    }
    modifier onlySeller()
    {
        if (msg.sender != seller) throw;
        _
    }
    modifier inState(State _state)
    {
        if (state != _state) throw;
        _
    }
    event aborted();
    event purchaseConfirmed();
    event itemReceived();

   ///终止购物并收回以太。仅仅可以在合约未锁定时被卖家调用。
    function abort()
        onlySeller
        inState(State.Created)
    {
        aborted();
        seller.send(this.balance);
        state = State.Inactive;
    }

   ///买家确认购买。交易包含两倍价值的(`2 * value`)以太。
   ///这些以太会一直锁定到收货确认(confirmReceived)被调用。
    function confirmPurchase()
        inState(State.Created)
        require(msg.value == 2 * value)
    {
        purchaseConfirmed();
        buyer = msg.sender;
        state = State.Locked;
    }

    ///确认你(买家)收到了货物,这将释放锁定的以太。
    function confirmReceived()
        onlyBuyer
        inState(State.Locked)
    {
        itemReceived();
        buyer.send(value);//我们有意忽略了返回值。
        seller.send(this.balance);
        state = State.Inactive;
    }
    function() { throw; }
}

先挂起这个吧, 这些东西需要消耗太久

猜你喜欢

转载自blog.csdn.net/zz709196484/article/details/79188236