以太坊虛擬機

回滾與例外

回滾是 EVM 說「停下,並當作這一切都沒發生過」的方式。當合約遇到一個它拒絕在其下繼續的狀況——餘額不足、授權檢查失敗、數學錯誤——它可以回滾,這會立即中止執行,並倒回當前呼叫框架中所做的每一項狀態變更,彷彿這次呼叫從未執行。這種全有或全無的行為,正是讓交易具有原子性的關鍵:它要嘛完全成功,要嘛把世界原封不動地留在它原本的樣子。

做這件事的乾淨方式,是 REVERT 操作碼(0xFD,由 EIP-140 引入)。REVERT 停止執行、倒回當前框架的狀態變更、把任何剩餘的 gas 退還給呼叫者,並交回一段記憶體作為錯誤資料。Solidity 的 require、revert 與自訂錯誤全都編譯成 REVERT,並把錯誤資料編碼成標準形狀:帶訊息的 require 用 Error(string)、除以零或陣列越界這類內部失敗用 Panic(uint256)、應用層特定的失敗則用 ABI 編碼的自訂錯誤(比字串更省 gas)。

並非每種失敗都是優雅的回滾。無效操作碼、堆疊下溢,或——最常見的——耗盡 gas,會觸發例外性中止,它同樣會回滾狀態,卻是耗光所有剩餘 gas 而非退還。這種不對稱是刻意的:gas 耗盡的失敗已讓網路做了實打實的工作,因此不退款;而明確的 REVERT 標誌著一次乾淨、可預期的拒絕,會退還未用的 gas。

回滾的語意以呼叫框架為界,理解這點對跨合約呼叫至為要緊。一個低階 CALL 呼叫到一份會回滾的合約,並不會自動向上冒泡——它只是回傳 false,由呼叫者選擇是否跟著回滾。Solidity 的高階外部呼叫預設確實會重新拋出,但 try/catch 讓合約能刻意捕捉被呼叫者的回滾並繼續,這正是「先試試這個,失敗就退回備案」這類模式的建構方式。

回滾仍要花 gas——你為回滾點之前所做的工作付費,只有未用的餘額會退還。「失敗就免費」是迷思;一筆在回滾前跑了大量邏輯的失敗交易,仍可能所費不貲。

又稱
revert回滾