跳到主要內容

【開發智能合約 — Solidity系列】實作篇Ep.5 - 錯誤處理的機制(Error Handling)

圖片來源

 

Solidity語言的錯誤檢查提供了Require()、Revert()、Assert(),這三種方便的API調用,而這三種用途分別不同,畢竟牽涉到瓦斯費的問題,因此才會與過往的程式語言有些許的差異,

Require

require()通常會被使用在輸入值的驗證檢查,因為它的特性主要是能夠退回剩餘的Gas fee,我們也知道瓦斯費在區塊鏈的成本是昂貴的,因此這些檢查都有助於不必要的浪費,主要使用方式為:

require(判斷式, 訊息)

...
contract Example {
...
function withdraw(uint amount) public pure {
uint total = 100;
/// @dev 提款的數量必須低於總額度
/// @notice 使用require(), 當條件不滿足時將退回剩下的瓦斯費,所以通常會放在前面
require(amount <= total, "amount must less then total");
...
}
}

Revert

revert()顧名思義為撤銷的意思,也就是通常不符合某些條件時則進行撤銷,與reqiure一樣是會退回剩餘的Gas fee,那看到這邊可能心裡會產生一些疑問,比如說為什麼不用require就好了呢? 兩者語意事實上是有差異的。

  • require表述的是「必須要滿足什麼條件」。
  • revert則表述「當什麼條件未被滿足」時進行撤回。
/// @dev 自訂錯誤類型: 資金不足
/// @param requested 要求的資金
/// @param available 可用的資金
error NotEnoughFunds(uint requested, uint available);
function ... {
/// @dev 提款的金額不能大於存款
/// @notice 若提出的金額超過存款總額,則退回撤銷並退回狀態。
if (amount > total) {
revert NotEnoughFunds(amount, total);
}
}

另外revert使用的方式有以下三種:

  • revert CustomError(…)
  • revert(”message”)
  • revert()

剛開始可能會有些霧裡看花,這麼多不同的承接方式與參數,但撰寫一段時間過後就會相當熟練,且在合適的時機使用正確的方式。

Assert

assert()跟require()一樣,算是進行檢核的機制,必須滿足某些條件才能繼續執行,但最大的差異在於當條件不滿足時,會耗盡Gas fee,因此通常用來處理比較嚴重且不易發生的錯誤,例如邊界值、特殊條件…等程式內部錯誤,也是最不常被使用的錯誤處理方法。

/// @dev 提款的額度必須是正整數
assert(amount > 0);

Try … Catch

相信這種語法如果有在開發其他程式的朋友應該非常熟悉,沒錯,Solidity亦提供這種錯誤處理機制,但值得注意的是在智能合約的世界中僅適合外部調用,白話來說就是A合約去嘗試使用B合約的功能,語法結構主要為:

try ...使用A合約進行什麼操作 {
...成功之後的處理
} catch ...什麼類型的錯誤 {
...進行什麼處理
} catch ...什麼類型的錯誤 {
...進行什麼處理
}

而錯誤的捕捉類型又分為以下四種方式,分別說明:

contract Example {
...
}
contract Runner {
Example public example;
constructor() {
example = new Example();
}
function exec() public view {
uint errorCount = 0;
try example.withdraw(101) {
// 提款成功之後...
} catch Error(string memory /*reason*/) {
// 這種錯誤類型主要是處理帶有錯誤訊息的錯誤處理函數: require(..., "錯誤訊息")、revert("撤銷訊息")
errorCount++;
} catch Panic(uint /*errorCode*/) {
// 這種錯誤類型主要處理assert(...)這種內部錯誤
errorCount++;
} catch (bytes memory /*lowLevelData*/) {
// 這種錯誤通常發生在更低階的處理,像是在解譯(decode)的階段
errorCount++;
} catch {
// 如果不想知道錯誤訊息或者原因時,可以直接用catch { ... }進行錯誤的對應處理。
}
}
}

結語

原來一個簡單的錯誤處理背後其實並不簡單…,與「金錢」有關的產品或服務最重要的莫過於嚴謹的審查機制,因此很多錯誤都是不能被容忍的,故而錯誤處理的機制就顯得非常重要,處理方式也相較於大部分程式語言有所不同,主要是因為納入了Gas fee的緣故,以此為鑑,當開發者進行開發智能合約時的錯誤處理也要非常小心,哪個使用情境要用哪一種錯誤處理的技巧並且不浪費Gas fee的狀況下,真的是對於智能合約開發者來說是一大挑戰,相信我們只要讀懂這些錯誤處理的概念後,未來開發時就會特別注意。

今天的範例都在這裡「📦 solidity-remix-toturial/Ep5」歡迎自行取用。

📚 更多關於Solidity的文章請看這裡…

喜歡撰寫文章的你,不妨來了解一下:

Web3.0時代下為創作者、閱讀者打造的專屬共贏平台 — 為什麼要加入?

歡迎加入一起練習寫作,賺取知識,累積財富!

資源參考

留言

這個網誌中的熱門文章

java西元民國轉換_各種不同格式

C#資料庫操作(新增、修改、刪除、查詢)

【Excel好好玩】 自己的資產自己管!善用Google Sheet來幫我們評估貸款

這次介紹的主題是關於Excel的貸款還款計畫試算,我們人生中總會遇到需要大筆金額的花費,但當資金不夠時就得進行貸款,而貸款之前如果我們能夠審慎評估,並分析自己的還款能力之後在進行凍作,相信風險會小很多,因此就自己動動手來使用Google Sheet進行試算吧! 基本資料 ● 貸款總額: 1000000 ● 貸款期數: 84月 ● 年利率: 2.11% ● 月利率: 0.18% P.S 月利率 = 年利率 / 12 重要函式 PMT : 這是Google Sheet內建的重要年金計算公式,我們可以善用這個公式來計算固定利率及期數的固定攤還本息。因為PMT函式計算出的結果為負數,所以前面加上-號轉成正數。 動手做 首先我們在Excel表上列出我們的基本資料 圖片來源 其中月利率的部分就使用公式「=B4/12」 接著我們填上第一列的期數跟餘額 圖片來源 =B2 =B3 使用關鍵PMT函數來計算本息的部分 因為PMT函式計算出的結果為負數,所以前面加上-號轉成正數。 -PMT(貸款利率(月利率), 貸款期數, 貸款總額) =-PMT($B$5,$B$3,$B$2) 圖片來源 計算利息 利息 = 貸款餘額 x 月利率 =B8*$B$5 圖片來源 計算本金 本金 = 本息 - 利息 =C8-D8 圖片來源 製作第二列餘額的部分 餘額的部分 = 上一期的餘額 - 上一期的本金 圖片來源 接著拖曳該兩列往下拉,即可查看每一期的利息與本金 圖片來源 結語 雖然市面上已經有很多貸款銀行都提供了試算功能,但如果我們想要進一步管理自己的資產時,就需要將每一期的金額給計算出來,因此才會將公式運用在Excel表,讓我們的資產管理表能夠結合負債,進一步評估我們理財行動的下一步,希望這樣的經驗可以幫助到正在理財道路上打拼的夥伴,讓我們透過有效的管理,幫助荷包長大吧! 喜歡撰寫文章的你,不妨來了解一下: Web3.0時代下為創作者、閱讀者打造的專屬共贏平台 — 為什麼要加入? 歡迎加入一起練習寫作,賺取知識,累積財富!