【以太坊】深入理解智慧合約(合約調合約)
一、前言
關於智慧合約的描述,大家在網上百度能查到一大堆。看來看去也能看個似懂非懂,但是稍微具體點呢,智慧合約到底都能幹什麼,可以轉賬提現嗎?可以合約呼叫合約嗎?可以釋出多個合約嗎?
關於智慧合約的疑問真的很多,只能一邊開發一邊總結了。以下是我最近關於智慧合約的一些新理解。
二、深入理解智慧合約
1、一條鏈上可以釋出多個智慧合約。
這些智慧合約不是相互覆蓋的關係,而是可以並存的關係。
但是在發代幣和儲存資料方面,最好只能有一個合約來宣告。因為如果有兩個合約都有發代幣的內容的話,那麼部署第二個發代幣合約之後,會新發一個幣種,造成資料混亂等問題。
這部分,博主剛開始一直以為一條鏈上只能有一個智慧合約,後來開發中才意識到,原來可以釋出多個合約。只要我們保持發幣和資料儲存部分只有一份就好,其他的邏輯方面的合約可以隨便發。
2、智慧合約也是個賬戶
智慧合約也是個賬戶,沒有私鑰,但是可以收到別人打過來的代幣,作為中轉賬戶使用
收款:外部給智慧合約轉賬為了接收Ether,(fallback)回退函式必須標記為payable。
如果沒有這樣的函式,合約不能通過常規transactions接收Ether。
這部分,博主這邊的需求是智慧合約接收使用者傳送的以太幣,並且轉換成其他幣種返回給使用者。剛開始根本沒想到,智慧合約能作為中轉賬號。很神奇。
3、智慧合約提現:(前提必須是合約的操作者)
因為智慧合約沒有私鑰,所以不能像普通賬戶一樣的轉賬操作。但是在智慧合約中,如果操作者是合約釋出者的話,可以通過內建的transfer方法來進行轉賬提現:
//這裡的address指的是你要提現的賬戶地址
//value代表了你要提現的金額
address.transfer(value);
提現部分,剛開始連想都不敢想。沒有私鑰也能提現轉賬?transfer前面的地址可以任意變換嗎?但是實際操作測試發現,是的,一切都可以實現。
4、智慧合約的fallback方法
為什麼會說道fallback()呢,因為我們接收以太幣的函式必須是fallback()函式:
//要接收以太幣,合約裡面必須要有payable關鍵字
//當我們使用address.send(ether to send)向某個合約直接轉帳時,由於這個行為沒有傳送任何資料,所以接收合約總是會呼叫fallback函式
function () external payable {
require(msg.sender != address(0));
require(msg.value != 0);
xxxxxxxxxxx
}
但是我們根據上面我給的連結可以看到,fallback()函式為了防止外部攻擊和合約漏洞,規定了此函式只能消耗2300gas。超過2300gas函式就會執行失敗。我們都知道,隨便一個轉賬都要消耗2w+的gas,這2300個gas怎麼可能會夠呢。
後面我們在查詢資料時候才發現,fallback()函式僅對使用send()方式的有2300gas的限制,對使用call()方式或者其他的操作沒有這樣的限制。好傢伙,原來fallback()也沒有想象中那麼恐怖。
5、智慧合約呼叫另一個智慧合約(重要!!!)
這部分才是遇到的重中之重,剛開始以為只是簡單的傳入地址就可以呼叫,但是在實際測試中
,並沒有那麼簡單。
(1)如果兩個合約寫在一起
(2)兩個合約不在一起
就像我們平時釋出需求,不可能一次都不修改合約的內容。但是合約本身的定義就是不可篡改的,那麼我們只有通過多釋出幾個合約來實現我們的需求了。
下面是示例程式碼:加入我們要在A合約中呼叫B合約的test方法
//先引入介面,interface就是個外部合約,你給了地址才能調他的方法。介面的名字是隨意的
interface test{
//這裡面的方法一定要是我們呼叫的B合約中的test方法,引數什麼的也都保持一致。
//因為是interface,所以函式必須宣告為external
function test(address _to, uint256 _value) external returns (bool);
}
//引入介面之後,開始引入我們的A合約
contract xxxxx is Pausable{
using SafeMath for uint256;
uint256 public weiRaised;
//因為solidity是靜態語言,所以在我們需要使用某個變數的時候,必須要先宣告一下
test test;
function () external payable {
xxxx
//這裡使用例項化過的B合約,直接呼叫它的test方法
require(token.test(msg.xxx, xxx));
xxxxx
}
constructor(address xxx, uint256 xxx, address xx) public {
//此處的_token是B合約的地址
token = test(_token);
}
}
大致步驟:
1、引入介面,介面中寫入B合約的方法以及引數。
2、在A合約中申明一個靜態變數,例項化B合約之後使用
3、在A合約的建構函式中例項化B合約(傳入B合約的地址)
4、在A合約中直接呼叫B合約中的test方法
interface就是個外部合約,你給了地址才能調他的方法。這裡的介面通過傳入地址呼叫。介面中的實現類要和傳入地址合約的實現類完全相同。這樣在傳入地址之後,就能直接呼叫傳入地址合約中的方法。
三、智慧合約消耗gas計算
1、估算智慧合約消耗的gas部分:
通過以下網址即可:http://remix.ethereum.org remix
(1)把自己的合約拷貝進去
(2)右邊的compile欄目下–》detail按鈕左邊有個下拉框,選擇自己的合約–》點選detail查詢
-》搜尋GASESTIMATES,然後會看到一個數組。上面的是部署合約和執行合約消耗的gas,下面的是具體方法消耗的gas數量
2、關於合約方法消耗gas多少的問題
以上就是這段時間對於智慧合約的新理解了。果然是紙上得來終覺淺,還是自己實踐起來理解的最快。這裡是我平時開發記錄的筆記,可能總結的不夠全面,大家可以通過給出的連結來學習(PS:有些連結需要翻牆的)。個人認為,智慧合約之間的相互呼叫最值得學習,這部分網上的資料太少了。
加油!
end