olidity語言開發以太坊智慧合約中的繼承
我們已經探索了很多主題,在編寫智慧合約時我們發現經常使用相同的模式:例如,智慧合約具有在建構函式中設定的所有者,然後生成修改器以便僅讓所有者使用一些功能。如果我們制定實施這些功能的基礎合約並在未來的智慧合約中重複使用它們那該怎麼辦?你一定猜得到,我們將使用繼承。
在Solidity中,繼承與經典的面向物件程式語言非常相似。你首先編寫基本智慧合約並告知你的新智慧合約將從基礎合約繼承。
你還必須通過複製包含多型的程式碼來了解Solidity支援多重繼承。所有函式呼叫都是虛擬函式,這意味著會是呼叫派生函式最多的函式,除非明確給出了合約名稱。當某一個智慧合約從多個合約繼承時,只在區塊鏈上建立一個智慧合約,並將所有基礎合約中的程式碼複製到建立的智慧合約中。
讓我們寫下我們的基本智慧合約:它將讓我們輕鬆地為我們的合約新增所有權。我們將其命名為Ownable
。OpenZeppelin的員工寫了很多可以在智慧合約中使用的可重用程式碼。這些程式碼段可通過其工具或其Github儲存庫獲得。
這是程式碼:
pragma solidity ^0.4.11;/** * @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; /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() { 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) onlyOwner { require(newOwner != address(0)); owner = newOwner; } }
我們經常寫的另一種模式是破壞我們的合約並將合約中儲存的資金轉移給所有者或另一個地址的能力。重要的是我們不希望任何人能夠破壞我們的合約,所以我們的Destructible
應該繼承Ownable
。繼承是使用智慧合約名稱後面的is
關鍵字完成的。
必須注意,它是Solidity,預設情況下是函式,或者可以從派生類訪問。與其他程式語言一樣,你可以指定從外部或派生合約中可以訪問的內容。函式可以指定為external
,public
,internal
,private
,預設為public
。
external
:外部函式是智慧合約介面的一部分,這意味著可以從其他合約和交易中呼叫它們。external
函式f不能在內部呼叫(即f()不起作用,但this.f()起作用)。當外部函式接收大量資料時,它們有時會更有效。public
:公共函式是智慧合約介面的一部分,可以在內部呼叫,也可以通過訊息呼叫。對於公共狀態變數,會生成自動getter函式(見下文)。internal
:這些函式和狀態變數只能在內部訪問(即從當前合約或從中派生的合約中),而其他情況不使用它。private
:私有函式和狀態變數僅對定義它們的智慧合約可見,而不是在派生合約中可見。
下面是我們的第二份智慧合約:
pragma solidity ^0.4.11;/** * @title Destructible * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner. */contract Destructible is Ownable { function Destructible() payable { } /** * @dev Transfers the current balance to the owner and terminates the contract. */ function destroy() onlyOwner { selfdestruct(owner); } function destroyAndSend(address _recipient) onlyOwner { selfdestruct(_recipient); } }
現在使用這兩個基本合約,我們將寫一個簡單的BankAccount
智慧合約,人們可以匯款,業主可以提取。
pragma solidity ^0.4.11; contract BankAccount is Ownable, Destructible { function store() public payable { } function withdraw(uint amount) public onlyOwner { if (this.balance >= amount) { msg.sender.transfer(amount); } } }
請注意,我們需要從兩個智慧合約繼承。繼承的順序很重要。判斷順序的一個簡單規則是按照“最類似基類”到“最多派生”的順序指定基類。
以下是我們將部署的整個程式碼:
pragma solidity ^0.4.11;/** * @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; /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() { 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) onlyOwner { require(newOwner != address(0)); owner = newOwner; } }/** * @title Destructible * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner. */contract Destructible is Ownable { function Destructible() payable { } /** * @dev Transfers the current balance to the owner and terminates the contract. */ function destroy() onlyOwner { selfdestruct(owner); } function destroyAndSend(address _recipient) onlyOwner { selfdestruct(_recipient); } } contract BankAccount is Ownable, Destructible { function store() public payable { } function withdraw(uint amount) public onlyOwner { if (this.balance >= amount) { msg.sender.transfer(amount); } } }
我們現在可以部署我們的銀行賬戶bank account
智慧合約了。