Solidity

__init 和 __init_unchained 之間的區別

  • March 5, 2022

我正在學習使用用於 ERC721 和 ERC1155 合約的 openzeppelin 庫開發可升級的智能合約。但是,我不明白 unchained 函式是什麼意思。更具體地說,init 和 init_unchained 函式之間的區別是什麼。以下 2 個函式顯示它們在 Openzeppelin 提供的 ERC1155 可升級合約中被呼叫

function __ERC1155_init(string memory uri_) internal onlyInitializing {
       __ERC1155_init_unchained(uri_);
   }

function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
       _setURI(uri_);
   }

OpenZeppelin 的文件中,有以下部分:

初始化函式不像建構子那樣被編譯器線性化。因此,每個 __{ContractName}_init 函式都嵌入了對所有父初始化器的線性化呼叫。因此,呼叫其中兩個 init 函式可能會初始化同一個合約兩次。

每個合約中的 __{ContractName}_init_unchained 函式是初始化函式減去對父初始化函式的呼叫,可以用來避免雙重初始化問題,但不建議手動執行此操作。我們希望能夠在升級外掛的未來版本中對此進行安全檢查。

這基本上意味著多重繼承不能很好地與初始化程序一起使用。

通常,一個_<CONTRACT_NAME>_init_unchained方法定義了派生合約的初始化,但不包括初始化它派生的父合約(您必須在合約中顯式初始化這些父合約),而一個_<CONTRACT_NAME>_init方法定義派生合約的初始化以及所有父合約它源自。在您的情況下,未連結的方法恰好不需要父初始化。

在某些具有多重繼承的情況下,您定義的派生契約可能會發生衝突,其中兩個父契約共享一個它們都派生自的父契約。在這種情況下,_<CONTRACT_NAME>_init對沖突合約的兩個初始化程序中都存在的共享父合約的呼叫將導致嘗試初始化共享父合約兩次,從而導致錯誤。OpenZeppelin 的可升級合約在過去幾年中已經有了很大的改進,以盡量減少此類碰撞的可能性。考慮使用合約嚮導並勾選“可升級性”複選框來展示編寫具有多重繼承的智能合約,而不會遇到此類問題。

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