Solidity

恢復 Solidity v0.8 中算術溢出的原因

  • October 18, 2021
function nice(uint8 x) public returns(uint8 z) {
   uint8 z = 0;
   z = z + 240;
   require(z = z + x, "overflow");
}

在 0.8 更新之前,我一直在將此程式碼與 Solidity 一起使用。如果發生溢出,事務將通過消息恢復overflow

現在,我要升級到 0.8。如果我使用相同的程式碼,我的測試案例將失敗,因為它們不再收到overfow回复消息。如果我按照編譯器的建議刪除require並離開z = z + x,我不知道它將返回什麼消息。我想要實現的是使用 0.8 並且仍然得到overflow恢復消息。

注意我不想使用unchecked.

一點解釋

首先,您應該熟悉“未經檢查的算術”的概念,它是v0.8 重大更改列表的一部分:

算術運算在下溢和上溢時恢復。您可以使用unchecked { … }來使用之前的包裝行為。

重要的是,上溢和下溢使用 REVERT 操作碼而不是 INVALID 操作碼:

失敗的斷言和其他內部檢查(如除以零或算術溢出)不使用無效操作碼,而是使用恢復操作碼。

如果您是Hardhat的使用者,在測試您的合約時,您將在終端中收到以下 JavaScript/TypeScript 錯誤:

錯誤:處理事務時出現 VM 異常:使用緊急程式碼 0x11 恢復(算術運算在未檢查塊之外下溢或溢出)

看起來 Solidity 選擇了十六進制數字 0x11 作為與算術上溢和下溢相關的恐慌程式碼。

程式碼更新

unchecked不幸的是,如果不將程式碼包裝在一個塊中,就無法實現您想要的。

首先你這樣做,然後你做SafeMath所做的事情:檢查總和是否大於x; 如果不是,則操作已超出最大 uint8。

function nice(uint8 x) public  returns(uint8 z){
   uint8 z = 0;
   z = z + 240;
   unchecked {
       z = z + x;
       require(z >= x, "Your custom message here");
   }
}

建議

當您現在可以定義自定義錯誤時,為什麼還要使用還原原因?

error Overflow(uint8 z, uint8 x);

function nice(uint8 x) public  returns(uint8 z){
   uint8 z = 0;
   z = z + 240;
   unchecked {
       z = z + x;
       if (z < x) {
           revert Overflow(x, z);
       }
   }
}

我認為這是 Solidity 開發的天賜之物。與還原原因字元串相比,自定義錯誤更容易處理、更高效、更優雅。

Solidity 0.8 包括以下關於算術上溢/下溢的更改:

算術運算在下溢和上溢時恢復。您可以使用 unchecked { … } 來使用之前的包裝行為。

在完全評估 require 語句之前,會觸發 Solidity 0.8 算術異常。我相信如果不使用unchecked. 但好消息是,在 Solidity 0.8 中,您甚至不再需要該 require 語句,但您需要調整測試以擷取拋出的算術 Solidity 異常,而不是“溢出”錯誤。

引用自:https://ethereum.stackexchange.com/questions/94351