區塊鏈研究實驗室| 在Solidity智慧合約中使用Enums之前要三思

買賣虛擬貨幣

想象一下,你正在寫一個Solidity智慧合約,其中一個屬性可以被描述為型別或狀態。換句話說,來自一組有限的選項。你馬上對自己說:“太好了,我只會使用列舉型別來表示這個狀態變數。”一方面,這種方法有一些好處,比如增加可讀性。另一方面,它很容易讓你走上一條可能導致問題的棘手道路。

好吧,如果列舉(ENUM)成員僅封裝在一個合約中並且從未在其他檔案中提及過,那麼一切都可以。然而DAPP通常由幾個相互連線的合約組成。當相同的列舉(ENUM)出現時,我要討論的問題會出現:

  1. 列舉成員出現在多個合約中

  2. 在DApp生命週期中進行修改

例如您有2份合約。第一個是儲存非常重要的資訊。您還宣告瞭一個帶有列舉定義的介面以引用它。

contract IStorage {    
    enum RecordState {StateA, StateB}
functionsetState(address user, RecordState newStatepublic;
}

contractStorageisIStorage

    mapping(address=>RecordState) public states;

constructor() public {}

functionsetState(address user, RecordState newStatepublic{
       states[user] = newState;   
    }
}

每個使用者的記錄都用一個包含兩個可能選項的列舉來表示:statea和stateb。setState函式可以更改使用者的狀態。還有另一個合約,終端使用者應該與之互動(為了簡單起見,我在儲存合約中省略了訪問控制修改器)。

contract StorageUser {
  IStorage public recordStorage;

constructor(IStorage _recordStorage) public {        
    recordStorage = _recordStorage;
  }

functionchangeStateA() public{        
    recordStorage.setState(msg.sender, IStorage.RecordState.StateA);        
  }

functionchangeStateB() public{
    recordStorage.setState(msg.sender, IStorage.RecordState.StateB);        
  }   
}

然後將這些合同部署到區塊鏈。

一切都很好:你呼叫changeStateA或changeStateB,並透過自己的setState函式相應地修改儲存合約的資料。 但是有一天你意識到你需要一個全新的狀態選項來實現一些全新的功能。你稱之為Statec(哇!多好的名字啊!)。首先,透過在IStorage中新增新的列舉成員來修改原始碼…

enum RecordState {StateA, StateB, StateC}

和StorageUser的新方法。

functionchangeStateC() public
  recordStorage.setState(msg.sender, IStorage.RecordState.StateC); 
}

此外,作為一個負責任的開發人員,您編寫呼叫新方法的測試並報告成功。您的計劃是僅重新部署StorageUser合同,並且您不希望重新部署儲存,因此很多重要資料都採用對映形式,很難遷移。因此,StorageUser將使用當前儲存作為其建構函式引數進行重新部署。你呼叫新的changeStateC函式......它失敗了。

失敗的根源

你看,更新後的StorageUser知道RecordState列舉的3個成員,但舊的Storage沒有關於新的StateC選項的線索。它無法將setState函式引數StateC轉換為其列舉版本,因此失敗。

更重要的是,您的測試可能會欺騙您,因為他們使用了兩個合約的更新版本。

實際上,你甚至可以在官方檔案中看到關於這個問題的警告。從整數顯式轉換在執行時檢查該值是否在列舉範圍內,否則將導致失敗的斷言。

要吸取的教訓

首先,在如上所述的情況下,用普通整數替換列舉更好。是的,它們看起來不那麼好但結果結構更可靠和可擴充套件。

其次,不要拋棄使用列舉欄位的整個想法。 如果這樣的領域只在一個合約內,那絕對是安全的。 如果您可以確保在修改的情況下完全重新部署使用列舉的所有合約,這也是安全的。 請記住,當列舉首次從IStorage匯入到StorageUser合約時出現問題,並且只有在修改初始成員後才重新部署後者。

只是不要忘記,如果你真的想在合約中使用列舉,最好三思而後行。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;