Solidity

圖書館如何改變狀態?

  • January 29, 2021

我有關於圖書館的非常有趣的案例。

情況1:

我在官方的 Solidity 文件中閱讀了以下內容:

如果庫函式不修改狀態(即如果它們是視圖或純函式),則只能直接呼叫庫函式(即不使用 DELEGATECALL),因為假定庫是無狀態的

我確信他們的意思是使用.call地址上的 來呼叫庫,他們說這只有在庫的功能是pure/view. 讓我在a), b), c)我不明白的地方重新表述。

**a)**在複製的句子中,它說:if they do not modify the state。我不確定圖書館是如何改變狀態的。它沒有自己的,它所能做的就是改變傳遞變數的值。

**b)**我嘗試將它與 一起使用addr.call,但我沒有指定函式 aspure/view並且它仍然讓我這樣做。有趣的是為什麼它讓我在文件中說它應該恢復。

**c)**為什麼我想用 呼叫庫.call?這只是違背了圖書館的全部目的。

**D) ** 似乎如果我internal在庫上使用函式,庫程式碼最終會出現在合約的編譯版本中。這有什麼好處?如果是這樣,我會使用另一個契約而不是圖書館。

案例二:

在文件中,它如何傳遞引用類型確實是一個糟糕的例子。假設我有一個圖書館:

// Let's say this was written by third-party and it's put on github.

library libraryContract {
  
  function libraryTest(){

  }

}

// I can import the above here.

// import "libraryContract.sol";

contract myContract {
  
  function contractTest(){
     // I call it. This will work. Now, let's say in this contract, I
     // have a variable called `uint x = 0;`. and what libraryContract 
     // should be doing is change the value of the passed argument. 
     // If I pass `x` here directly, and change the argument in 
     //`libraryTest`, It still doesn't work since it's not passed by 
     //reference or something. Another case is What If I want my library 
     //to be changing the struct's properties, but library doesn't see 
     //the definiton of struct. 
     libraryContract.test(); 
  }

}

a)在複製的句子中,它說:如果他們不修改狀態。我不確定圖書館是如何改變狀態的。它沒有自己的,它所能做的就是改變傳遞變數的值。

庫可以通過委託呼叫更改呼叫合約的狀態。在這種情況下,函式的執行就像它是直接寫在呼叫合約中一樣。這意味著它理論上可以修改呼叫合約狀態的任何部分,只要相應的變數已在庫中聲明(但未初始化,因為庫沒有自己的狀態)。文件的意思是,如果您嘗試直接呼叫這樣的函式,它將失敗,因為它不打算更改/修改自己的儲存(因為不存在這樣的儲存),而是呼叫合約上的相應儲存.

b) I tried using it with addr.call, but I didn't specify functions as pure/view and it still let me do this. It's interesting why it let me since in the docs, it says it should revert.

將函式標記為pure/view不是強制性的,因此只要函式實際上不嘗試修改狀態,事務就不會恢復。

c) Why would I ever want to call libraries with the .call ? This just defeats the whole purpose of libraries.

用於修改呼叫合約的狀態(通過delegatecall),但它也可以表現得像具有靜態方法的類。例如,假設您總是發現自己在合約中需要一些熟悉的常量或方法(uint piuint days_in_year function n_squared(uint n)等)。您可以將它們分解到庫中,以避免必須將它們包含在您編寫的每個契約中。然後它們只在區塊鏈上儲存一次,其他合約call在需要時只儲存它們。

似乎如果我在庫上使用內部函式,庫程式碼最終會出現在合約的編譯版本中

一個應用程序是可重用程式碼。例如SafeMath使用內部函式。這樣,當你這樣做時a.add(b),它會在使用delegatecall. 如果delegatecall要使用 a,計算最終將非常昂貴。

然而,在未來,由於免費功能,這種對庫的使用可能會變得不那麼普遍。


“狀態問題”的一個簡單範例是:

library L {
   function f() external {
       assembly {
           sstore(0, 1)
       }
   }
}

因此,如果沒有呼叫保護,那麼您將寫入庫的狀態。

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