iT邦幫忙

0

Day 18:錯誤處理與回退(require / assert / revert)

  • 分享至 

  • xImage
  •  

在 Solidity 智能合約中,「錯誤處理」不只是 debug 的工具,更是安全設計的關鍵。
因為在鏈上,每一次交易都要付 Gas,而錯誤會讓交易中斷、狀態回退(revert)。
如果錯誤處理寫錯,不但會浪費使用者的 Gas,還可能讓整個系統無法繼續運作。

今天要學的就是三個核心關鍵字:
require ,assert ,revert,了解它們的差異、應用時機與安全陷阱。

🧩 Solidity 的錯誤處理基本邏輯

在智能合約執行過程中,只要發生錯誤,整筆交易會:
1. 回復到執行前的狀態(狀態回退)
2. 使用掉當下的 Gas(除非錯誤前有 require 檢查)
3. 拋出錯誤訊息(可自訂或預設)

⚙️ 三種主要錯誤控制關鍵字比較
關鍵字 用途 回退行為 常見應用
require(condition, message)/驗證外部輸入是否合理/✅ 回退狀態/驗證參數、權限、餘額檢查
assert(condition)/驗證內部邏輯不應出錯/✅ 回退狀態 + 消耗所有 Gas/檢查內部不變量(invariant)
revert(message)/主動中斷執行(等同 require false)/✅ 回退狀態/自訂錯誤流程與訊息

📘 範例 1:使用 require 驗證外部輸入
pragma solidity ^0.8.0;

contract Bank {
mapping(address => uint) balance;

function deposit() public payable {
    require(msg.value > 0, "Deposit must be positive");
    balance[msg.sender] += msg.value;
}

function withdraw(uint amount) public {
    require(amount <= balance[msg.sender], "Not enough funds");
    balance[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
}

}

🔍 分析
• require 是針對「使用者輸入」或「外部條件」的防線。
• 若失敗:狀態不會被更新、Gas 退還剩餘部分。
• 適用於權限、金額、地址、參數驗證等。

📗 範例 2:使用 assert 驗證邏輯正確性
function internalMath(uint x, uint y) public pure returns (uint) {
uint result = x + y;
assert(result >= x); // 保證不會溢位
return result;
}

🔍 分析
• assert 用來檢查「理論上永遠應該為真」的條件。
• 一旦失敗,表示程式邏輯錯誤(不是輸入錯)。
• 會消耗完所有 Gas,因為這是開發者錯誤。

✅ 建議用法
• 檢查內部狀態、數學不變量(例如總供給量、合約 invariant)
• 不要拿來取代 require 驗證使用者行為!

📙 範例 3:使用 revert() 主動回退與自訂錯誤訊息
function transfer(address to, uint amount) public {
if (balance[msg.sender] < amount) {
revert("Insufficient funds");
}
balance[msg.sender] -= amount;
balance[to] += amount;
}

🔍 分析
• revert() 通常與條件搭配,用於複雜邏輯的中途退出。
• 行為與 require(false, message) 一樣,但靈活度更高。
• 可在巢狀 if / loop 中使用,控制流程更乾淨。

⚡ 常見錯誤與安全風險
問題 範例 結果
忘記錯誤處理/沒有檢查 call() 的成功與否/攻擊者可導致 DoS 或錯誤付款
用 assert 檢查外部輸入/assert(amount > 0)/錯誤類型錯,浪費 Gas
無訊息的 revert/revert();/難以 debug、審計不便
沒有檢查回傳值/_target.call(data);/攻擊者可用 revert 鎖死邏

錯誤處理與 Gas 的關係
•require / revert:若失敗,會退還尚未使用的 Gas。
•assert:會消耗全部 Gas(因為認為是程式錯誤)。

🔹 最佳實踐

永遠用 require 檢查外部輸入,
用 assert 保護內部邏輯。

這樣不僅節省 Gas,也能讓審計更容易定位問題。

錯誤處理是 Solidity 程式的第一道防線。
很多安全事故不是因為密碼學錯誤,而是「忘了檢查條件」。
我認為這一章最值得記住的是這句話:

require 是為了使用者錯誤,assert 是為了開發者錯誤。

只要每個條件都能在設計階段被明確檢查出來,
你的智能合約就能減少 70% 的潛在漏洞。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言