09月23, 2019

require( ) vs. modifier( ) vs. assert( ) vs. event( ) in Solidity

modifier 把function执行前的检查逻辑抽出来,在程序执行前执行一次检查。 包含 1,2,3

require 在0.4.10 solidity加入,用在function参数检查,确认input或合约state V满足条件,用来验证用户的输入。 require(false)不会扣除全部gas,仅扣除已经发生的部分。

throw 用在function逻辑判断,business logic (已弃用!)。

assert 在0.4.10 solidity加入,不检查不变量,发生回滚revert时会把全部gas扣除。

revert 标记错误并混滚当前调用。

operator

event 是和外部通信的方式,可以用来记录变量信息,实现打印。

-- 1 pre-conditions 2 post-conditions 3 state changes


以下代码实现了可重用的log方法,只要调用log()方法就可以打印不同类型的变量值。

使用方法为:log(string name, var value)

pragma solidity ^0.4.21;

//通过log函数重载,对不同类型的变量trigger不同的event,实现solidity打印效果,使用方法为:log(string name, var value)

contract Console {
    event LogUint(string, uint);
    function log(string s , uint x) internal {
    emit LogUint(s, x);
    }

    event LogInt(string, int);
    function log(string s , int x) internal {
    emit LogInt(s, x);
    }

    event LogBytes(string, bytes);
    function log(string s , bytes x) internal {
    emit LogBytes(s, x);
    }

    event LogBytes32(string, bytes32);
    function log(string s , bytes32 x) internal {
    emit LogBytes32(s, x);
    }

    event LogAddress(string, address);
    function log(string s , address x) internal {
    emit LogAddress(s, x);
    }

    event LogBool(string, bool);
    function log(string s , bool x) internal {
    emit LogBool(s, x);
    }
}

使用时只需要将Console.sol import进程序且继承Console就好(注意第3行和第41行

pragma solidity ^0.4.21;

import "browser/Console.sol";

contract SimpleAuction is Console {
    // Parameters of the auction. Times are either
    // absolute unix timestamps (seconds since 1970-01-01)
    // or time periods in seconds.
    address public beneficiary;  //受益人
    uint public auctionEnd; //竞拍终止时间

    // 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.
    // 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`.
    /// 初始化拍卖对象:受益人地址、拍卖持续时间
    function SimpleAuction(
        uint _biddingTime,
        address _beneficiary
    ) public {
        beneficiary = _beneficiary;
        auctionEnd = now + _biddingTime;
        log("time now", now);
    }

    /// Bid on the auction with the value sent
    /// together with this transaction.
    /// The value will only be refunded if the
    /// auction is not won.
    ///对竞拍投标,payable代表该交易可以获取ether,只有没有竞拍成功的交易款才会退回
    function bid() public 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 <= auctionEnd);

        // If the bid is not higher, send the
        // money back.
        //如果投标金额未超过当前最高金额,则终止
        require(msg.value > highestBid);

        if (highestBid != 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; //新的最高出价
        emit HighestBidIncreased(msg.sender, msg.value); //触发最高出价增加事件
    }

    /// Withdraw a bid that was overbid.
    /// 取回被淘汰的竞拍
    function withdraw() public 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; //在send方法被执行之前,将待退还的钱置为0 *这个很重要* 因为如果不置为0的话,可以重复发起withdraw交易,send需要时间,在交易没确认之前,重复发起可能就要退N倍的钱

            if (!msg.sender.send(amount)) { //用户自己取回退回的款项时,如果出错不用调用throw方法,而是将被置0的待退款金额恢复
                // 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() public {
        // 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 >= auctionEnd); // auction did not yet end
        require(!ended); // this function has already been called

        // 2. Effects
        ended = true;
        emit AuctionEnded(highestBidder, highestBid);

        // 3. Interaction
        beneficiary.transfer(highestBid);
    }
}

log方法执行后可以在这里找到打印出的变量信息 alt

本文链接:https://harry.ren/post/rvsmvsavsev.html

-- EOF --

Comments