您好,登錄后才能下訂單哦!
本篇內容介紹了“Solidity錯誤處理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
錯誤處理是指在程序發生錯誤時的處理方式,Solidity處理錯誤和我們常見的語言不一樣,Solidity是通過回退狀態的方式來處理錯誤。發生異常時會撤消當前調用(及其所有子調用)所改變的狀態,同時給調用者返回一個錯誤標識。注意捕捉異常是不可能的,因此沒有try ... catch...。
為什么Solidity處理錯誤要這樣設計呢? 我們可以把區塊鏈理解為是全球共享的分布式事務性數據庫。全球共享意味著參與這個網絡的每一個人都可以讀寫其中的記錄。如果想修改這個數據庫中的內容,就必須創建一個事務,事務意味著要做的修改(假如我們想同時修改兩個值)只能被完全的應用或者一點都沒有進行。 學習過數據庫的同學,應該理解事務的含義,如果你對事務一詞不是很理解,建議你搜索一下“數據庫事務“。 Solidity錯誤處理就是要保證每次調用都是事務性的。
Solidity提供了兩個函數assert和require來進行條件檢查,如果條件不滿足則拋出異常。assert函數通常用來檢查(測試)內部錯誤,而require函數來檢查輸入變量或合同狀態變量是否滿足條件以及驗證調用外部合約返回值。 另外,如果我們正確使用assert,有一個Solidity分析工具就可以幫我們分析出智能合約中的錯誤,幫助我們發現合約中有邏輯錯誤的bug。
除了可以兩個函數assert和require來進行條件檢查,另外還有兩種方式來觸發異常:
revert函數可以用來標記錯誤并回退當前調用
使用throw關鍵字拋出異常(從0.4.13版本,throw關鍵字已被棄用,將來會被淘汰。)
當子調用中發生異常時,異常會自動向上“冒泡”。 不過也有一些例外:send,和底層的函數調用call, delegatecall,callcode,當發生異常時,這些函數返回false。
注意:在一個不存在的地址上調用底層的函數call,delegatecall,callcode 也會返回成功,所以我們在進行調用時,應該總是優先進行函數存在性檢查。
在下面通過一個示例來說明如何使用require來檢查輸入條件,以及assert用于內部錯誤檢查:
pragma solidity ^0.4.0; contract Sharer { function sendHalf(address addr) public payable returns (uint balance) { require(msg.value % 2 == 0); // 僅允許偶數 uint balanceBeforeTransfer = this.balance; addr.transfer(msg.value / 2); // 如果失敗,會拋出異常,下面的代碼就不是執行 assert(this.balance == balanceBeforeTransfer - msg.value / 2); return this.balance; } }
我們實際運行下,看看異常是如何發生的:
首先打開Remix,貼入代碼,點擊創建合約。如下圖:
運行測試1:附加1wei (奇數)去調用sendHalf,這時會發生異常,如下圖:
運行測試2:附加2wei 去調用sendHalf,運行正常。
運行測試3:附加2wei以及sendHalf參數為當前合約本身,在轉賬是發生異常,因為合約無法接收轉賬,錯誤提示上圖類似。
在下述場景中自動產生assert類型的異常:
如果越界,或負的序號值訪問數組,如i >= x.length 或 i < 0時訪問x[i]
如果序號越界,或負的序號值時訪問一個定長的bytesN。
被除數為0, 如5/0 或 23 % 0。
對一個二進制移動一個負的值。如:5<<i; i為-1時。
整數進行可以顯式轉換為枚舉時,如果將過大值,負值轉為枚舉類型則拋出異常
如果調用未初始化內部函數類型的變量。
如果調用assert的參數為false
在下述場景中自動產生require類型的異常:
調用throw
如果調用require的參數為false
如果你通過消息調用一個函數,但在調用的過程中,并沒有正確結束(gas不足,沒有匹配到對應的函數,或被調用的函數出現異常)。底層操作如call,send,delegatecall或callcode除外,它們不會拋出異常,但它們會通過返回false來表示失敗。
如果在使用new創建一個新合約時出現第3條的原因沒有正常完成。
如果調用外部函數調用時,被調用的對象不包含代碼。
如果合約沒有payable修飾符的public的函數在接收以太幣時(包括構造函數,和回退函數)。
如果合約通過一個public的getter函數(public getter funciton)接收以太幣。
如果**.transfer()**執行失敗
當發生require類型的異常時,Solidity會執行一個回退操作(指令0xfd)。 當發生assert類型的異常時,Solidity會執行一個無效操作(指令0xfe)。 在上述的兩種情況下,EVM都會撤回所有的狀態改變。是因為期望的結果沒有發生,就沒法繼續安全執行。必須保證交易的原子性(一致性,要么全部執行,要么一點改變都沒有,不能只改變一部分),所以需要撤銷所有操作,讓整個交易沒有任何影響。
注意assert類型的異常會消耗掉所有的gas, 而require從大都會版本(Metropolis, 即目前主網所在的版本)起不會消耗gas。
“Solidity錯誤處理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。