如果我更改第三方契約的版本編譯指示以使其可以使用更新的 Solidity 編譯器導入,會出現什麼問題?
將依賴合約中的編譯器版本更改為與主合約相同的版本會有什麼後果?
我有一個主契約,它繼承了一些其他契約來與他們的方法和屬性進行互動。所以我這樣做:
pragma solidity 0.8.7; import "../dependencies/C1.sol"; // uses pragma solidity 0.6.12; import "../dependencies/C2.sol"; // uses pragma solidity ^0.8.0; contract MainC is C1, C2 {}
依賴合約從 開始
pragma solidity 0.6.12;
和結束pragma solidity ^0.8.0;
。為了ParserError
在編譯期間解決問題,我決定為所有依賴合約分配相同的solidity 版本pragma solidity 0.8.7;
。它是否對依賴合約的功能有影響,並且由於與作者指定的不同的solidity版本,將來是否有機會收到錯誤?
我知道 Chainlink 合約提供了使用具有不同版本可靠性的智能合約的機會。但其他一些項目(例如 AAVE)卻沒有。
我訪問了How to handle multiple solidity versions以及How to import and compile contracts of different versions solidity,據說
pragma solidity ^0.6.12;
在這種情況下使用。但是在version pragma 的solidity docs中提到:帶有上述行的源文件不能使用 0.5.2 版本之前的編譯器編譯,並且它也不能在 0.6.0 版本開始的編譯器上工作(這第二個條件是使用 ^ 添加的)。
而我需要該版本
0.8.7
及更高版本,因為安全數學和本機能夠通過使用而不是編寫自己的函式來執行從string
to的顯式轉換。bytes32``bytes32(<string>)
在大多數情況下,契約將無法編譯。許多項目在它們的編譯指示中使用插入符運算符 (
^
),因為程式碼通常應該仍然可以工作,直到編譯器的下一個突破性版本,並且所有賭注都結束了。在某些情況下,契約可能會在發生重大更改後生效,幾乎沒有更改。如果是這樣,你大部分時間都是安全的。問題是您是否認為“大部分時間”足夠好。鑑於智能合約中的安全漏洞非常普遍,我認為任何旨在持有大量資金的合約都是不可接受的。
為了降低風險,如果您打算這樣做,您應該仔細查看契約來源。仔細查看編譯器中的重大更改列表,尤其是名為“語義的無聲更改”的部分:
每個重大版本都可能引入一些語義更改,使程式碼在特定情況下表現不同。例如;
- 0.8.0 中添加的未經檢查的算術使任何依賴上溢/下溢的程式碼在執行時恢復。一些庫可能會故意將其作為氣體優化的一種形式,尤其是在進行位操作時。這樣的程式碼可以編譯,但如果你不將它包裝在
unchecked
.a**b**c
用來表示(a**b)**c
。這與大多數其他程式語言不同且違反直覺,因此a**(b**c)
在 0.8.0 中更改為。如果庫依賴它,它的計算就會出錯。assert()
並恢復由編譯器發出,用於使用INVALID
終止執行並消耗所有氣體的指令。由於高gas成本和未經檢查的算法的引入(這使得這種還原作為一種驗證形式更加常見)它被更改並Panic()
返回錯誤。但在極少數情況下,留下一些可用的氣體實際上會產生安全隱患,並使某些形式的攻擊成為可能。這是 OpenZeppelin 決定切換回舊行為的一個案例:在 MinimalForwarder #2864 中使用無效的操作碼。如果庫有這樣的程式碼,使用更新的編譯器而不解決它會打開一個微妙的漏洞。如您所見,如果您不小心,有些事情可能會咬住您。如果項目有一個好的測試套件,你應該執行它。如果通過,您可以更有信心在較新的編譯器版本上執行不會引入任何意外的行為變化。儘管如此,它仍然不是 100% 的保證,並且始終建議通過查看 Solidity 文件中的更改列表進行一些手動審查,以作為額外的預防措施。
如果您不想花費所有精力,最好尋找按原樣使用第三方契約的方法。請參閱我在如何從 0.8.x Solidity 合約中導入 Aave 和 Uniswap 合約中的回答,以獲取有關您可以做什麼的一些提示。