Я много читал об обновлении смарт-контрактов, и кажется, что основная преобладающая практика заключается в том, что, как правило, хорошей идеей является отделение логики контракта от хранилища контрактов, поэтому можно обновить один и не нужно менять другой.
Мой вопрос заключается в следующем: увеличивает ли тот факт, что один контракт должен вызывать другой контракт, количество газа, которое тратится по этой логике. Например, предположим, что у меня есть контракт, который ищет число X, а затем добавляет его к числу 5.
В одном случае контракт хранится в самом X, поэтому он может напрямую искать его. В другом случае отдельный контракт отвечает за хранение X, в результате чего один контракт выполняет вызов функции для получения X. Стоит ли один больше газа? Если да, то можно ли сказать, сколько еще?
Спасибо!
Да, но рекомендуется учитывать компромиссы, связанные с увеличением стоимости газа, с возможностью модернизации, которую он обеспечивает для вашего приложения.
Большинство обновляемых контрактов будут включать библиотеки и код операции DELEGATECALL, а некоторые затраты описаны в части документации Solidity по библиотекам :
Библиотеки можно рассматривать как неявные базовые контракты контрактов, которые их используют. Они не будут явно видны в иерархии наследования, но вызовы библиотечных функций выглядят так же, как вызовы функций явных базовых контрактов (Lf(), если L — имя библиотеки). Кроме того, внутренние функции библиотек видны во всех контрактах, как если бы библиотека была базовым контрактом. Конечно, вызовы внутренних функций используют внутреннее соглашение о вызовах, что означает, что все внутренние типы могут передаваться, а типы памяти будут передаваться по ссылке, а не копироваться. Чтобы реализовать это в EVM, код внутренних библиотечных функций (и всех вызываемых из них функций) будет подтянут в вызывающий контракт, а вместо DELEGATECALL будет использоваться обычный вызов JUMP.
По сути, когда все находится в контракте, он может использовать ссылки, избегать копий и использовать код операции JUMP.
Когда задействованы внешние контракты, DELEGATECALL намного дороже, чем JUMP (в настоящее время 700 газа против 10 газа), и есть другие затраты, такие как копирование данных.
Но важно также профилировать конкретный вариант использования и сравнивать. Для простого примера, приведенного выше, стоимость CALL/DELEGATECALL была бы огромной. Но в других случаях эти дополнительные затраты на газ могут иметь гораздо меньшее влияние в целом.
Я бы сказал да, немного, но в большинстве случаев это не так уж важно. Помимо единовременных затрат на развертывание, для каждой транзакции будет выполняться дополнительный код. Это не бесплатно, но в большинстве случаев дополнительный код не будет особенно дорогим в эксплуатации.
Посмотрите стоимость газа за операцию (без гарантии): https://docs.google.com/spreadsheets/d/15wghZr-Z6sRSMdmRmhls9dVXTOpxKy8Y64oy9MvDZEQ/edit#gid=0 .
Базовая эвристика заключается в том, что коды операций изменения состояния (например, SSTORE) довольно высоки по сравнению с кодами операций вычисления, которые не изменяют блокчейн. Как правило, можно добавить дополнительные недорогие служебные шаги (например, поиск адреса контракта и формирование сообщения) без значительного увеличения общей стоимости изменения состояния. Смена состояния в любом случае обойдется дорого.
Операции чтения часто обрабатываются постоянными функциями или локальными вызовами, которые вообще не используют газ . Таким образом, проблемы транзакционных издержек обычно ограничиваются транзакциями, которые приведут к изменению состояния. Таким образом, создание/вставка, обновление и удаление имеют свою стоимость (львиная доля таких операций, как SSTORE). Чтения обычно бесплатны независимо от сложности. Также учтите, что многие системы используют офчейн-хранилище, питаемое генераторами событий, которые сохраняют копию «официальных» фактов из соображений производительности. Еще один пример ситуации, в которой вообще имеет значение только стоимость обновлений.
Чтобы поэкспериментировать с конкретным примером и сравнить затраты, вы можете закодировать репрезентативные функции в обоих направлениях и сравнить фактическое потребление газа. Компилятор Solidity Realtime покажет байт-код после компиляции. Вы можете пройтись по исходному коду, чтобы увидеть, какие фактические шаги являются «дорогостоящими», и соответствующим образом оптимизировать.
В качестве примечания: остерегайтесь скрытых затрат на дополнительную сложность. Хотя обновляемые контракты выгодны во многих отношениях, существует ряд компромиссов, подобных инь-ян, которые необходимо учитывать для каждого варианта использования. Например, возможность обновления в некоторых случаях может снизить надежность и потенциально может стать новым источником ошибок.
Надеюсь, это полезно.
Роб Хитченс
эт