1. 程式人生 > >【以太坊】深入理解智慧合約(合約調合約)

【以太坊】深入理解智慧合約(合約調合約)

一、前言

      關於智慧合約的描述,大家在網上百度能查到一大堆。看來看去也能看個似懂非懂,但是稍微具體點呢,智慧合約到底都能幹什麼,可以轉賬提現嗎?可以合約呼叫合約嗎?可以釋出多個合約嗎?

關於智慧合約的疑問真的很多,只能一邊開發一邊總結了。以下是我最近關於智慧合約的一些新理解。

二、深入理解智慧合約

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