錯誤和 Revert 語句

2022-05-16 10:47 更新

Solidity 中的錯誤提供了一種方便且高效的方式來向用戶解釋操作失敗的原因。它們可以在合約內(nèi)部和外部定義(包括接口和庫)。

它們必須與revert 語句一起使用, 這會導(dǎo)致當(dāng)前調(diào)用中的所有更改都被還原并將錯誤數(shù)據(jù)傳遞回調(diào)用者。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

/// Insufficient balance for transfer. Needed `required` but only
/// `available` available.
/// @param available balance available.
/// @param required requested amount to transfer.
error InsufficientBalance(uint256 available, uint256 required);

contract TestToken {
    mapping(address => uint) balance;
    function transfer(address to, uint256 amount) public {
        if (amount > balance[msg.sender])
            revert InsufficientBalance({
                available: balance[msg.sender],
                required: amount
            });
        balance[msg.sender] -= amount;
        balance[to] += amount;
    }
    // ...
}

錯誤不能被重載或覆蓋,而是被繼承。只要范圍不同,就可以在多個地方定義相同的錯誤。錯誤實(shí)例只能使用revert語句創(chuàng)建。

該錯誤會創(chuàng)建數(shù)據(jù),然后通過還原操作將其傳遞給調(diào)用者,以返回到鏈外組件或在try/catch 語句中捕獲它。請注意,錯誤只能在來自外部調(diào)用時(shí)被捕獲,在內(nèi)部調(diào)用或同一函數(shù)內(nèi)部發(fā)生的還原無法被捕獲。

如果不提供任何參數(shù),則錯誤只需要四個字節(jié)的數(shù)據(jù),您可以使用上面的NatSpec進(jìn)一步解釋錯誤背后的原因,它沒有存儲在鏈上。這使得它同時(shí)成為一個非常便宜和方便的錯誤報(bào)告功能。

更具體地說,錯誤實(shí)例以與函數(shù)調(diào)用相同名稱和類型的函數(shù)相同的方式進(jìn)行 ABI 編碼,然后將其用作revert操作碼中的返回?cái)?shù)據(jù)。這意味著數(shù)據(jù)包含一個 4 字節(jié)選擇器,后跟ABI 編碼數(shù)據(jù)。選擇器由錯誤類型簽名的 keccak256-hash 的前四個字節(jié)組成。

筆記

合同可能會因同名的不同錯誤或什至在調(diào)用者無法區(qū)分的不同位置定義的錯誤而恢復(fù)。對于外部,即 ABI,只有錯誤的名稱是相關(guān)的,而不是定義它的合同或文件。

如果您可以定義 ,該語句將等效于 . 但是請注意,這是一個內(nèi)置類型,不能在用戶提供的代碼中定義。require(condition, "description");if (!condition) revert Error("description")error Error(string)Error

同樣,失敗assert或類似的情況將恢復(fù)為內(nèi)置類型的錯誤Panic(uint256)。

筆記

錯誤數(shù)據(jù)應(yīng)該只用于給出失敗的指示,而不是作為控制流的手段。原因是內(nèi)部調(diào)用的還原數(shù)據(jù)默認(rèn)通過外部調(diào)用鏈傳播回來。這意味著內(nèi)部調(diào)用可以“偽造”恢復(fù)看起來可能來自調(diào)用它的合約的數(shù)據(jù)。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號