Solidity編譯器最新版本發布:改進和新功能亮點

2023-10-29 11:19 登鏈社區


編譯:登鏈翻譯計劃;來源:soliditylang.org

Solidity編譯器的最新版本v0.8.22的發布。0.8.22版本的編譯器包含了一系列的語言和編譯器改進,例如文件級事件定義、unchecked 循環增量優化、支持導入EVM匯編JSON 等等。

重要提示

本次發布廢棄了對低於 Constantinople(君士坦丁堡) 版本的 EVM 的支持,這些版本越來越難以維護。這些古老的版本在以太坊主網和測試網絡上早已過時,我們懷疑它們對其他網絡也不再相關。復雜的代碼路徑和解決方案會減慢針對新版本的功能开發和測試的速度,因此我們希望在未來的編譯器版本中停止支持它們。

新功能亮點

unchecked 循環增量

在增加循環計數器時使用 unchecked 算術運算是爲了 gas 優化[7]的常見做法。讓我們以以下循環和計數器 i 的示例來說明:

for (uint i = 0; i < array.length; ++i) {
   acc += array[i]; // i is not modified by the loop body
}

在許多情況下(詳見下文的精確條件),比較操作將確保 i 永遠不會達到其類型的最大值,因此可以安全地假設在達到最大值之前循環將停止。在這種情況下,對計數器進行安全檢查將是多余的,也是一種 gas 的浪費。這就會鼓勵用戶使用冗長的 unchecked 模式,將計數器增量包裝在循環體內的unchecked算術塊中,繞過檢查:

for (uint i = 0; i < array.length;) {
   acc += array[i];
   unchecked { i++; } // i gets incremented without overflow checks -- less gas used
}

Solidity 0.8.22 引入了一種溢出檢查優化,自動生成了對於循環計數器的 unchecked 算術增量。這個新的優化消除了在循環體中使用類似前面示例中的冗長 unchecked 增量模式的需要。

相比之下,新的優化使用戶能夠在不犧牲gas效率的情況下返回到原始的、更易讀的代碼。

新優化避免溢出檢查的精確條件如下:

  • 循環條件是形如 i < ... 的比較,其中 i 是一個局部變量(從現在开始稱爲“循環計數器”)。

  • 此比較必須在與循環計數器相同的類型上執行,即右側的類型必須可以隱式轉換爲循環計數器的類型,以使循環計數器在比較之前不會被隱式擴展。

  • 循環計數器必須是內置整數類型的局部變量。

  • 循環表達式必須是循環計數器的前綴或後綴遞增,即 i++ 或 ++i。

  • 循環計數器不能在循環條件或循環體中被修改。

爲了澄清第二個條件,考慮以下代碼片段:

for (uint8 i = 0; i < uint16(1000); ++i) {
   // loop body
}

在這種情況下, i 在比較之前被轉換爲 uint16,並且條件實際上永遠不會爲假,因此無法刪除遞增的溢出檢查。

另外,請注意, < 是唯一會觸發該優化的比較運算符。故意排除了運算符 <= 和其他運算符。此外,該運算符必須是內置的 - 用戶定義的 < 不符合條件。

該優化是直接的且總是有益的,因此即使使用通用設置 settings.optimizer.enabled 禁用了優化器的其余部分,它也會被啓用。可以通過在標准 JSON 輸入中將 settings.optimizer.details.simpleCounterForLoopUncheckedIncrement 設置爲 false 來明確關閉它。無法使用命令行界面禁用它。

調整Yul優化器以重新生成零字面量

新版本在 0.8.20 版本引入的 PUSH0 操作碼的支持基礎上進行了構建,通過將 Rematerialiser[8] 優化步驟擴展爲始終重新生成零字面量而不是將其存儲爲變量引用,從而允許使用 PUSH0 而不是 DUP 來降低gas成本。爲確保有效執行此操作,將 Rematerialiser 和 UnusedPruner[9] 步驟添加到了Yul優化器的默認清理序列中。

添加對導入 EVM 匯編 JSON 的支持(實驗性)

這個新版本添加了對導入 EVM 匯編的實驗性支持,爲外部工具在字節碼生成之前執行超級優化提供了可能性。此功能的主要目的是定義一種低級 EVM 匯編的序列化格式,使編譯器生成的匯編可以被導出、修改和重新導入,從而恢復正常的編譯過程。

重要提示:這是一個實驗性功能,目前不適用於生產環境。我們在此版本中提供此功能,以便你嘗試並提供反饋。

允許在文件級別定義事件

Solidity 0.8.22 允許你在文件級別定義事件。現在,事件定義可以放在合約範圍之外。這爲代碼組織提供了另一種選擇,無需人爲地將事件包裝在庫中。

此外,此版本還修復了一個錯誤,該錯誤導致在爲代碼發出在外部合約或接口中定義的事件時生成 NatSpec 時出錯。在上一個版本(0.8.21)中,Solidity編譯器添加了對在當前合約未繼承的合約和接口中定義的事件的限定訪問的支持,但該錯誤阻止了該功能的完全使用。

通過此錯誤修復和允許文件級別事件定義,Solidity的最新版本使用戶能夠編譯以下示例而不會出現任何錯誤:

interface I {
   event ForeignEvent();
}
contract C {
   event ForeignEvent();
}
event E();
contract D {
   function f() public {
       // Emitting a foreign event would trigger an internal error on 0.8.21
       emit I.ForeignEvent();
       emit C.ForeignEvent();
       // Emitting a file-level event. New feature.
       emit E();
   }
}

完整的更改日志

語言特性

  • 允許在文件級別定義事件。

編譯器特性

  • 代碼生成器:當計數變量不會溢出時,刪除某些for循環的冗余溢出檢查。

  • 命令行界面:添加--no-import-callback選項,防止編譯器加載未在 CLI 或標准 JSON 輸入中明確給出的源文件。

  • 命令行界面:添加實驗性的--import-asm-json選項,可以導入以--asm-json使用的格式的 EVM 匯編。

  • 命令行界面:對於在編譯 pipeline 之外產生的錯誤消息,使用適當的嚴重性和着色。

  • EVM:棄用對“homestead”、“tangerineWhistle”、“spuriousDragon”和“byzantium” EVM 版本的支持。

  • 解析器(Parser):刪除實驗性的錯誤恢復模式(--error-recovery / settings.parserErrorRecovery)。

  • SMTChecker:支持用戶定義的運算符。

  • Yul 優化器:如果支持PUSH0,優先使用零字面量而不是將零值存儲在變量中。

  • Yul 優化器:在默認的清理序列的末尾運行RematerializerUnusedPruner步驟。

Bug 修復

  • 代碼生成器:修復通過 via-IR 代碼生成器輸出的結果依賴於導入回調中發現的文件的問題。在某些情況下,不同的 AST ID 分配會改變內部調度中函數的順序,導致表面上不同但在語義上等效的字節碼。

  • NatSpec:修復在請求合約的用戶文檔或开發文檔時出現內部錯誤的問題,該合約發出了在外部合約或接口中定義的事件。

  • SMTChecker:修復編碼錯誤,導致循環在完成後展开。

  • SMTChecker:修復常量條件檢查的不一致性,當 while 或 for 循環在條件檢查之前展开時。

  • Yul 優化器:修復在 CSE 期間受編譯器生成的Yul變量名影響替換決策的問題,在某些情況下導致不同(但等效)的字節碼。

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。

標題:Solidity編譯器最新版本發布:改進和新功能亮點

地址:https://www.sgitmedia.com/article/14124.html

相關閱讀: