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()方法有可能會調回當前方法,修改器實現了防重入的檢查。