Solidity

智能合約太聰明了:不同版本的 geth 或 solidity 的智能合約的不同行為

  • October 30, 2019

最近我正在學習如何在乙太坊上部署和呼叫智能合約。我正在製定一個非常簡單的契約,如下所示:

pragma solidity >=0.4.24 <0.6.0;
contract TestContract{

  uint public a;

  constructor() public 
  { 
      a = 2;
  }

  function addNumber(uint b) public
  {
      a = a + b;
  }

  function read() public view returns (uint)
  {
      return a;
  }
}

我首先嘗試在我的私有鏈上部署合約,geth 是從目前主預設 go-ethereum 原始碼編譯而來的。雖然可以成功部署合約,但是addNumber通過web3呼叫函式會拋出以下錯誤gas required exceeds allowance (1726103387) or always failing transaction。我不知道為什麼會這樣,因為我的私鏈正在挖礦,而且我的賬戶有足夠的乙太幣給這麼小的合約程式碼。

然後我在舊版本的 go-ethereum 上部署了合約,一開始部署和呼叫函式addNumber看起來都很好,web3 呼叫沒有返回任何錯誤,但後來我發現函式addNumber實際上並沒有增加(b = 1在我的測試中case),a儘管呼叫了很多次,但仍為 0。我還檢查了 geth 中的相應交易,並了解到它們已經在開采的區塊中退出。

然後我改為使用solidity ^0.4.0 編譯合約程式碼(同時刪除建構子和關鍵字視圖,因為solidity ^0.4.0 不支持它們),並部署在鏈上。在這種情況下,該合約適用於兩個版本的 go-ethereum。即,a每當呼叫= 1的函式addNumber時都會增加b

所以我的問題是:

  1. 為什麼呼叫addNumber最新版本的 go-ethereum 會引發錯誤:所需的氣體超過限額(1726103387)或總是失敗的交易。
  2. 為什麼同一個合約在不同版本的 go-ethereum 和solidity 中表現完全不同。
  3. 在我看來,智能合約“太聰明了”。有什麼想法可以在不同版本的 go-ethereum 和solidity 之間進行選擇嗎?

你的合約中的任何內容都不應該燃燒接近 300 萬個 gas,所以你可以很確定這是一個讓合約恢復的恐慌性 gas 消耗。很多時候,所有剩餘的氣體都會被破壞以使 evm 中止,並且再多的氣體也無法解決最初的問題。

然後我改用solidity ^0.4.0編譯合約程式碼

你在球場上。

問題是 EVM 更改。你沒有說什麼版本的 Geth 和什麼版本的 Solidity,但這些都是關鍵因素。

一般來說,我不喜歡^在編譯指示中,因為它沒有明確,從快速瀏覽程式碼,正在使用什麼編譯器,或者應該使用什麼編譯器來複製結果。而且,事情是這樣的……

硬分叉是協議更改。對於拜占庭,這些更改影響了界面。添加了預期長度,以支持函式簽名中的字元串和其他可變長度參數。因此,有必要遷移到支持該功能的更新編譯器。

在實踐中,這意味著如果您使用 < 0.4.2.(4?) 的編譯器編譯程式碼,那麼您必須使用低於某個版本(拜占庭之前)的 geth、ganache-cli 等,否則它將無法工作。同樣,如果 geth、ganache-cli 是更新的,那麼您必須使用更新的編譯器進行編譯。

希望能幫助到你。

ps 作為一種風格,我傾向於在頂級合約中使用精確的編譯指示,因為這樣可以消除歧義,並且^在繼承的模組中,為了方便並儘量避免修補解決良好的庫。

就像是

pragma solidity 0.5.8;

contract MyContract {

  using SafeMath for uint;

即使 SafeMath 包含^or &gt;= &lt;=,毫無疑問它是用 0.5.8 編譯和測試的。

引用自:https://ethereum.stackexchange.com/questions/77071