как библиотека может изменить состояние?

У меня есть очень интересные дела о библиотеках.

ДЕЛО 1:

В официальных документах Solidity я прочитал следующее:

Библиотечные функции можно вызывать только напрямую (т. е. без использования DELEGATECALL), если они не изменяют состояние (т. е. если они являются представлениями или чистыми функциями), поскольку предполагается, что библиотеки не имеют состояния.

Я уверен, что они имеют в виду вызывать библиотеки с использованием .callпо адресу, и они говорят, что это было бы возможно только в том случае, если бы функция библиотек была pure/view. Позвольте мне перефразировать в том, a), b), c)что я не понимаю.

а) В скопированном предложении говорится: if they do not modify the state. Я не уверен, как библиотека вообще меняет состояние. у него нет своего собственного, и все, что он может сделать, это изменить значение переданной переменной.

б) Я пытался использовать его с addr.call, но я не указал функции as pure/view, и он все еще позволял мне это делать. Интересно, почему он позволил мне, так как в документах говорится, что он должен вернуться.

c) Зачем мне когда-либо вызывать библиотеки с помощью .call? Это просто побеждает всю цель библиотек.

**D) ** Похоже, если я использую internalфункции в библиотеках, код библиотеки попадает в скомпилированную версию контракта. Любая причина, почему это хорошо? если это так, я бы использовал другой контракт вместо библиотеки.

Случай 2:

В документах это действительно плохой пример того, как он передает ссылочный тип. Допустим, у меня есть библиотека:

// 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(); 
   }

}

Библиотеки после развертывания ничем не отличаются от любого другого контракта. Насколько я знаю, ничто не мешает любому пользователю вызывать функции. Внутренние функции предназначены для вызова из одного и того же контракта, что делает их вызываемыми из другого контракта, что противоречит цели быть внутренними. Библиотеки хороши для организации кода, но у них есть некоторые ограничения. Если документы Solidity неясны, я бы посоветовал обратиться к разработчикам Solidity.

Ответы (3)

а) В скопированном предложении говорится: если они не изменяют состояние. Я не уверен, как библиотека вообще меняет состояние. у него нет своего собственного, и все, что он может сделать, это изменить значение переданной переменной.

Библиотека может изменить состояние вызывающего контракта посредством вызова делегата. В этом случае функция выполняется так, как если бы она была написана непосредственно в вызывающем контракте. Это означает, что теоретически он может изменить любую часть состояния вызывающего контракта, если соответствующие переменные были объявлены в библиотеке (но не инициализированы, поскольку библиотека не имеет собственного состояния). Документы говорят о том, что если вы попытаетесь вызвать такую ​​функцию напрямую, она потерпит неудачу, поскольку она не предназначена для изменения/модификации своего собственного хранилища (поскольку такого хранилища не существует), а скорее соответствующее хранилище в вызывающем контракте. .

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 pi, uint days_in_year function n_squared(uint n), и т.д.). Вы можете перенести их в библиотеку, чтобы не включать их в каждый контракт, который вы пишете. Затем они сохраняются в блокчейне только один раз, а остальные заключают контракты только callс ними, когда они им нужны.

Спасибо Саймон. Здесь у меня тоже есть пара моментов.
1). Вы говорите: not initialised. Это означает, что единственное, что я могу поместить в библиотеку, — это struct, потому что, если я добавляю целые числа, массив или что-то еще, это означает, что они инициализируются по умолчанию. 3). Похоже, тот пример, который вы привели, n_squaredтоже можно сделать, просто загрузив контракт вместо библиотеки, а затем используя ее функции. Кроме того, я мог бы вызвать метод контракта со своим собственным delegatecall. Итак, я все еще не вижу общей картины, может быть

Похоже, если я использую внутренние функции в библиотеках, код библиотеки попадает в скомпилированную версию контракта.

Одним из приложений для этого является повторно используемый код. Например, SafeMath использует внутренние функции. Таким образом, когда вы это делаете a.add(b), он выполняет вычисления без использования файла delegatecall. delegatecallЕсли использовать a , вычисления в конечном итоге будут довольно дорогими.

Однако в будущем такое использование библиотек, вероятно, станет менее распространенным из-за бесплатных функций.


Простым примером «государственной проблемы» может быть:

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

Так что если бы не было защиты вызовов, то вы бы писали в состояние библиотеки.

Библиотеки не имеют состояния, они могут хранить только «постоянные» значения. Таким образом, даже если в библиотеке используется delegatecall, он не сможет изменить состояние контракта вызывающего абонента.

Например, когда я пытался создать библиотеку ниже, это дает эту ошибку:

из солидности: TypeError: библиотека не может иметь непостоянные переменные состояния

library LibraryContract {

  uint storedTime;  

  function setTime(uint _time) public {
    storedTime = _time;
  }
}

Обновление: оказывается, что это ограничение снимается при использовании так, как упоминается в этой статье: https://dev.to/mudgen/solidity-libraries-can-t-have-state-variables-oh-yes-they-can-3ke9 .