1. 程式人生 > >solidity學習筆記(8)—— 函式修飾符及自定義修飾符

solidity學習筆記(8)—— 函式修飾符及自定義修飾符

在Solidity中,函式修飾符規定了函式的行為、呼叫規則。在Solidity語言中預置的修飾符有如下一些:

1、函式和狀態變數可見性修飾符 public:在外部和內部均可見(建立儲存/狀態變數的訪問者函式) private:僅在當前合約中可見 external: 只有外部可見(僅對函式)- 僅僅在訊息呼叫中(通過this.fun) internal: 只有內部可見

2、狀態變數儲存位置修飾符 storage:變數儲存在區塊鏈中,狀態變數預設是storage型別; memory:變數儲臨時存在記憶體中,區域性變數預設是memory型別;

3、接受Ether修飾符 payable:允許函式在呼叫同時接收Ether

4、函式讀取狀態變數修飾符 pure:不允許修改或訪問狀態變數-這還沒有強制執行 view:不允許修改狀態變數-這還沒有強制執行 constant(for function):等同於view constant(for state variables):除了初始化之外,不允許賦值操作,類似JavaScript中的常量

自定義修飾符

函式修改器(Function Modifiers)

修改器(Modifiers)可以用來輕易的改變一個函式的行為。比如用於在函式執行前檢查某種前置條件。 修改器是一種合約屬性,可被繼承,同時還可被派生的合約重寫(override)。

OpenZeppelin庫的Ownable 合約

下面是一個 Ownable 合約的例子: 來自 OpenZeppelin Solidity 庫的 Ownable 合約。 OpenZeppelin 是主打安保和社群審查的智慧合約庫,你可以在自己的 DApps中引用。

所以Ownable 合約基本都會這麼幹:

  • 合約建立,建構函式先行,將其 owner 設定為msg.sender(其部署者)
  • 為它加上一個修飾符 onlyOwner,它會限制陌生人的訪問,將訪問某些函式的許可權鎖定在 owner 上。
  • 允許將合約所有權轉讓給他人。

看一下原始碼:

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
​
contract Ownable {
  address public owner;
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() public {
    owner = msg.sender;
  }
​
  /**
   * @dev Throws if called by any account other than the owner.
   */
​
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
​
  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
​
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }
}

我們來看一下函式修改器onlyOwner是怎麼定義和使用的? 首先:要定義一個modifier,形式與函式很像,可以有引數,但是不需要返回值; 其次:特殊 _; 是必要的,它表示使用修改符的函式體的替換位置; 第三:使用將modifier置於引數後,返回值前即可。

其他合約如何使用onlyOwner?

繼承!函式修改器是可以繼承的,只要新建的合約繼承Ownable合約,即可使用這個修改器。

########################################
####     其他合約如何使用onlyOwner?   ####
########################################
​
contract MyContract is Ownable {
  event LaughManiacally(string laughter);
​
  //注意! `onlyOwner`上場 :
  function likeABoss() external onlyOwner {
    LaughManiacally("Muahahahaha");
  }
}

帶引數的函式修改器 之前我們已經讀過一個簡單的函式修飾符了:onlyOwner。函式修飾符也可以帶引數。例如:

// 儲存使用者年齡的對映
mapping (uint => uint) public age;
// 限定使用者年齡的修飾符
modifier olderThan(uint _age, uint _userId) {
  require(age[_userId] >= _age);
  _;
}
// 必須年滿16週歲才允許開車 (至少在美國是這樣的).
// 我們可以用如下引數呼叫`olderThan` 修飾符:
function driveCar(uint _userId) public olderThan(16, _userId) {
  // 其餘的程式邏輯
}

使用修改器實現的一個防重複進入的例子。
pragma solidity ^0.4.0;
​
contract Mutex {
    bool locked;
    modifier noReentrancy() {
        if (locked) throw;
        locked = true;
        _;
        locked = false;
    }
    /// This function is protected by a mutex, which means that
    /// reentrant calls from within msg.sender.call cannot call f again.
    /// The `return 7` statement assigns 7 to the return value but still
    /// executes the statement `locked = false` in the modifier.
    function f() noReentrancy returns (uint) {
        if (!msg.sender.call()) throw;
        return 7;
    }
}

例子中,由於call()方法有可能會調回當前方法,修改器實現了防重入的檢查。