Руководство по оптимизации Gas для смарт-контрактов: 10 основных практик для Падения стоимости транзакции
Проблема с Gas-стоимостью на основной сети Ethereum всегда была в центре внимания, особенно в периоды перегрузки сети. В часы пик пользователи часто должны платить высокие транзакционные расходы. Поэтому оптимизация Gas-расходов на этапе разработки смарт-контрактов имеет решающее значение. Оптимизация потребления Gas не только может эффективно снизить стоимость транзакции, но и повысить эффективность транзакций, предоставляя пользователям более экономичный и эффективный опыт использования блокчейна.
В данной статье будет рассмотрена механика Gas-стоимости Ethereum Virtual Machine (EVM), основные концепции оптимизации Gas-стоимости, а также лучшие практики оптимизации Gas-стоимости при разработке смарт-контрактов. Надеемся, что этот материал вдохновит разработчиков и окажет им практическую помощь, а также поможет обычным пользователям лучше понять, как работает Gas-стоимость в EVM, и совместно справляться с вызовами в экосистеме блокчейна.
Введение в механизм газовых сборов EVM
В совместимых с EVM сетях «Gas» — это единица измерения вычислительной мощности, необходимой для выполнения определенных операций.
В структуре EVM потребление газа в основном делится на три части: выполнение операций, вызовы внешних сообщений, а также чтение и запись в память и хранилище.
Каждое выполнение транзакции требует вычислительных ресурсов, поэтому взимается определенная плата для предотвращения бесконечных циклов и атак отказа в обслуживании ( DoS ). Плата, необходимая для завершения транзакции, называется "Gas fee".
С тех пор как EIP-1559 вступил в силу, стоимость газа рассчитывается по следующей формуле:
Базовая плата будет уничтожена, а приоритетная плата будет использоваться в качестве стимула, поощряя валидаторов добавлять транзакции в блокчейн. Установка более высокой приоритетной платы при отправке транзакции может увеличить вероятность того, что транзакция будет включена в следующий блок. Это похоже на «чаевые», которые пользователи платят валидаторам.
Понимание оптимизации Gas в EVM
При компиляции смарт-контрактов на Solidity контракт преобразуется в серию "операционных кодов", то есть opcodes.
Любая последовательность операций с кодом (, например, создание смарт-контракта, выполнение вызова сообщения, доступ к хранилищу аккаунта и выполнение операций на виртуальной машине ) имеет признанную стоимость транзакции Gas, эти затраты зафиксированы в желтой книге Ethereum.
После нескольких изменений EIP, некоторые коды операций были скорректированы, что может отличаться от желтой книги.
Основные концепции оптимизации газа
Основная идея оптимизации Gas заключается в приоритете выбора операций с высокой стоимостью эффективности на EVM блокчейне, избегая операций с дорогими затратами на Gas.
В EVM следующие операции имеют низкую стоимость:
Чтение и запись переменных в памяти
Чтение констант и неизменяемых переменных
Чтение и запись локальных переменных
Чтение переменной calldata, например массива и структур calldata
Внутренний вызов функции
Стоимость транзакции较高的操作包括:
Чтение и запись состояния переменных, хранящихся в смарт-контрактах
Вызов внешних функций
Циклическая операция
Лучшие практики оптимизации затрат на EVM Gas
Основываясь на вышеупомянутых основных концепциях, мы подготовили для сообщества разработчиков список лучших практик по оптимизации Gas-расходов. Следуя этим практикам, разработчики могут снизить потребление Gas смарт-контрактов, снизить стоимость транзакции и создать более эффективные и удобные для пользователя приложения.
1. Постарайтесь минимизировать использование хранилища
В Solidity хранилище ( является ограниченным ресурсом, его расход газа значительно выше, чем у памяти ). Каждый раз, когда смарт-контракт читает или записывает данные в хранилище, возникают высокие расходы газа.
Согласно определению, данному в желтой книге Ethereum, стоимость операций хранения превышает стоимость операций с памятью более чем в 100 раз. Например, команды OPcodesmload и mstore расходуют всего 3 единицы газа, тогда как операции хранения, такие как sload и sstore, даже в самых идеальных условиях, требуют как минимум 100 единиц.
Способы ограничения использования хранения включают:
Храните непостоянные данные в памяти
Падение количества изменений в хранении: путем сохранения промежуточных результатов в памяти, и только после завершения всех вычислений, результаты распределяются по переменным хранения.
( 2. Упаковка переменных
Количество хранилищ, используемых в смарт-контрактах, и способ, которым разработчики указывают данные для Storage slot), будут сильно влиять на потребление Gas.
Компилятор Solidity будет упаковывать последовательные переменные хранения в процессе компиляции и использовать 32-байтный слот хранения в качестве базовой единицы хранения переменных. Упаковка переменных означает разумное распределение переменных, позволяющее нескольким переменным помещаться в один слот хранения.
С помощью этого изменения разработчики могут сэкономить 20 000 единиц Gas. ### Хранение неиспользуемого хранилища требует 20 000 Gas (, но теперь требуется только два хранилища.
Поскольку каждый слот хранения потребляет Газ, упаковка переменных оптимизирует использование Газа, сокращая необходимое количество слотов хранения.
![Десять лучших практик оптимизации газа для смарт-контрактов Ethereum])https://img-cdn.gateio.im/webp-social/moments-995905cb414526d4d991899d0c2e6443.webp(
) 3. Оптимизация типов данных
Переменная может быть представлена несколькими типами данных, но стоимость операций для разных типов данных также различна. Выбор подходящего типа данных помогает оптимизировать использование газа.
Например, в Solidity целые числа могут быть разделены на различные размеры: uint8, uint16, uint32 и т.д. Поскольку EVM выполняет операции в 256 битах, использование uint8 означает, что EVM сначала должен преобразовать его в uint256, а это преобразование потребует дополнительного расхода газа.
На первый взгляд, использование uint256 дешевле, чем uint8. Однако, если использовать упаковку переменных для оптимизации, ситуация меняется. Если разработчик может упаковать четыре переменные uint8 в один слот хранения, то общая стоимость их итерации будет ниже, чем стоимость четырех переменных uint256. Таким образом, смарт-контракты могут читать и записывать один слот хранения, и за одно действие помещать четыре переменные uint8 в память/хранение.
4. Используйте переменные фиксированного размера вместо динамических переменных
Если данные можно ограничить до 32 байт, рекомендуется использовать тип данных bytes32 вместо bytes или strings. Обычно переменные фиксированного размера потребляют меньше газа, чем переменные переменного размера. Если длину байтов можно ограничить, старайтесь выбирать минимальную длину от bytes1 до bytes32.
5. Отображение и массивы
Списки данных Solidity могут быть представлены двумя типами данных: массивы ( Arrays ) и отображения ### Mappings (, но их синтаксис и структура совершенно разные.
В большинстве случаев отображение более эффективно и имеет более низкие затраты, но массивы обладают итерируемостью и поддерживают упаковку типов данных. Поэтому рекомендуется при управлении списками данных отдавать предпочтение отображению, если не требуется итерация или можно оптимизировать потребление газа за счет упаковки типов данных.
![Десять лучших практик оптимизации газа для смарт-контрактов Ethereum])https://img-cdn.gateio.im/webp-social/moments-9c566626ab499ef65d6f5089a2876ad3.webp(
) 6. Используйте calldata вместо memory
Переменные, объявленные в параметрах функции, могут храниться в calldata или memory. Основное различие между ними заключается в том, что memory может быть изменен функцией, тогда как calldata неизменяем.
Помните этот принцип: если параметры функции являются только для чтения, следует в первую очередь использовать calldata, а не memory. Это поможет избежать ненужных операций копирования из calldata функции в memory.
7. Используйте ключевые слова Constant/Immutable, когда это возможно.
Переменные Constant/Immutable не хранятся в хранилище контракта. Эти переменные вычисляются на этапе компиляции и хранятся в байт-коде контракта. Поэтому их стоимость доступа значительно ниже, чем у хранения, рекомендуется использовать ключевые слова Constant или Immutable, когда это возможно.
8. Используйте Unchecked, чтобы убедиться, что переполнение/недостаток не произойдет.
Когда разработчики могут гарантировать, что арифметические операции не приведут к переполнению или недостатку, они могут использовать ключевое слово unchecked, введенное в Solidity v0.8.0, чтобы избежать лишних проверок на переполнение или недостаток, тем самым экономя стоимость транзакции.
Кроме того, компиляторы версии 0.8.0 и выше больше не требуют использования библиотеки SafeMath, поскольку сам компилятор уже включает функции защиты от переполнения и недополнения.
9. Оптимизация модификатора
Код модификатора встроен в изменённую функцию, и каждый раз, когда используется модификатор, его код копируется. Это увеличивает размер байт-кода и повышает расход газа.
Путем реконструкции логики в внутреннюю функцию _checkOwner(), разрешается повторное использование этой внутренней функции в модификаторе, что может уменьшить размер байт-кода и Падение стоимости транзакции.
![Десять лучших практик оптимизации Gas для смарт-контрактов Ethereum]###https://img-cdn.gateio.im/webp-social/moments-a141884dcdcdc56faff12eee2601b7b7.webp(
) 10. Оптимизация короткого замыкания
Для || и && операторов логические операции будут подвергаться краткому оцениванию, то есть если первое условие уже может определить результат логического выражения, второе условие не будет оцениваться.
Чтобы оптимизировать потребление газа, условия с низкой стоимостью вычислений должны быть размещены в начале, это может позволить пропустить вычисления с высокой стоимостью.
Общие дополнительные рекомендации
1. Удалить ненужный код
Если в смарт-контракте существуют неиспользуемые функции или переменные, рекомендуется их удалить. Это самый прямой способ снизить стоимость транзакции и сохранить небольшой объем контракта.
Вот некоторые полезные советы:
Используйте наиболее эффективные алгоритмы для вычислений. Если в смарт-контракте используются результаты некоторых вычислений напрямую, то следует исключить эти избыточные вычислительные процессы. По сути, любые неиспользуемые вычисления должны быть удалены.
В Ethereum разработчики могут получать награды в виде Gas, освобождая пространство для хранения. Если переменная больше не нужна, следует удалить ее с помощью ключевого слова delete или установить ее в значение по умолчанию.
Оптимизация циклов: избегайте операций с высокими затратами в циклах, по возможности объединяйте циклы и выносите повторяющиеся вычисления за пределы тела цикла.
( 2. Использование предкомпилированных смарт-контрактов
Предварительно скомпилированные контракты предоставляют сложные библиотечные функции, такие как операции шифрования и хеширования. Поскольку код не выполняется на EVM, а выполняется локально на клиентском узле, требуется меньше газа. Использование предварительно скомпилированных контрактов может сэкономить газ за счет сокращения вычислительных затрат, необходимых для выполнения смарт-контрактов.
Примеры предсоставленных контрактов включают алгоритм цифровой подписи на основе эллиптической кривой )ECDSA### и хеш-алгоритм SHA2-256. Используя эти предсоставленные контракты в смарт-контрактах, разработчики могут Падение стоимость транзакции и повысить эффективность работы приложений.
3. Использование встроенного ассемблера
Встроенная сборка ( in-line assembly ) позволяет разработчикам писать низкоуровневый, но эффективный код, который может быть выполнен непосредственно EVM, без необходимости использования дорогостоящих операций Solidity. Встроенная сборка также позволяет более точно контролировать использование памяти и хранения, что дополнительно снижает Стоимость транзакции. Кроме того, встроенная сборка может выполнять некоторые функции, которые сложно реализовать только с помощью Solidity.
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
11 Лайков
Награда
11
4
Поделиться
комментарий
0/400
SilentObserver
· 07-20 19:53
Газ так дорог, что я плачу от бедности555
Посмотреть ОригиналОтветить0
ConfusedWhale
· 07-20 19:53
Днем так устаешь, а как же играть ночью?
Посмотреть ОригиналОтветить0
NightAirdropper
· 07-20 19:48
eth это рост для неудачников, который происходит из-за Газ.
10 основных практик для оптимизации Gas-расходов смарт-контрактов Падение стоимости транзакции Ethereum
Руководство по оптимизации Gas для смарт-контрактов: 10 основных практик для Падения стоимости транзакции
Проблема с Gas-стоимостью на основной сети Ethereum всегда была в центре внимания, особенно в периоды перегрузки сети. В часы пик пользователи часто должны платить высокие транзакционные расходы. Поэтому оптимизация Gas-расходов на этапе разработки смарт-контрактов имеет решающее значение. Оптимизация потребления Gas не только может эффективно снизить стоимость транзакции, но и повысить эффективность транзакций, предоставляя пользователям более экономичный и эффективный опыт использования блокчейна.
В данной статье будет рассмотрена механика Gas-стоимости Ethereum Virtual Machine (EVM), основные концепции оптимизации Gas-стоимости, а также лучшие практики оптимизации Gas-стоимости при разработке смарт-контрактов. Надеемся, что этот материал вдохновит разработчиков и окажет им практическую помощь, а также поможет обычным пользователям лучше понять, как работает Gas-стоимость в EVM, и совместно справляться с вызовами в экосистеме блокчейна.
Введение в механизм газовых сборов EVM
В совместимых с EVM сетях «Gas» — это единица измерения вычислительной мощности, необходимой для выполнения определенных операций.
В структуре EVM потребление газа в основном делится на три части: выполнение операций, вызовы внешних сообщений, а также чтение и запись в память и хранилище.
Каждое выполнение транзакции требует вычислительных ресурсов, поэтому взимается определенная плата для предотвращения бесконечных циклов и атак отказа в обслуживании ( DoS ). Плата, необходимая для завершения транзакции, называется "Gas fee".
С тех пор как EIP-1559 вступил в силу, стоимость газа рассчитывается по следующей формуле:
Газовая плата = единицы газа * (базовая плата + приоритетная плата)
Базовая плата будет уничтожена, а приоритетная плата будет использоваться в качестве стимула, поощряя валидаторов добавлять транзакции в блокчейн. Установка более высокой приоритетной платы при отправке транзакции может увеличить вероятность того, что транзакция будет включена в следующий блок. Это похоже на «чаевые», которые пользователи платят валидаторам.
Понимание оптимизации Gas в EVM
При компиляции смарт-контрактов на Solidity контракт преобразуется в серию "операционных кодов", то есть opcodes.
Любая последовательность операций с кодом (, например, создание смарт-контракта, выполнение вызова сообщения, доступ к хранилищу аккаунта и выполнение операций на виртуальной машине ) имеет признанную стоимость транзакции Gas, эти затраты зафиксированы в желтой книге Ethereum.
После нескольких изменений EIP, некоторые коды операций были скорректированы, что может отличаться от желтой книги.
Основные концепции оптимизации газа
Основная идея оптимизации Gas заключается в приоритете выбора операций с высокой стоимостью эффективности на EVM блокчейне, избегая операций с дорогими затратами на Gas.
В EVM следующие операции имеют низкую стоимость:
Стоимость транзакции较高的操作包括:
Лучшие практики оптимизации затрат на EVM Gas
Основываясь на вышеупомянутых основных концепциях, мы подготовили для сообщества разработчиков список лучших практик по оптимизации Gas-расходов. Следуя этим практикам, разработчики могут снизить потребление Gas смарт-контрактов, снизить стоимость транзакции и создать более эффективные и удобные для пользователя приложения.
1. Постарайтесь минимизировать использование хранилища
В Solidity хранилище ( является ограниченным ресурсом, его расход газа значительно выше, чем у памяти ). Каждый раз, когда смарт-контракт читает или записывает данные в хранилище, возникают высокие расходы газа.
Согласно определению, данному в желтой книге Ethereum, стоимость операций хранения превышает стоимость операций с памятью более чем в 100 раз. Например, команды OPcodesmload и mstore расходуют всего 3 единицы газа, тогда как операции хранения, такие как sload и sstore, даже в самых идеальных условиях, требуют как минимум 100 единиц.
Способы ограничения использования хранения включают:
( 2. Упаковка переменных
Количество хранилищ, используемых в смарт-контрактах, и способ, которым разработчики указывают данные для Storage slot), будут сильно влиять на потребление Gas.
Компилятор Solidity будет упаковывать последовательные переменные хранения в процессе компиляции и использовать 32-байтный слот хранения в качестве базовой единицы хранения переменных. Упаковка переменных означает разумное распределение переменных, позволяющее нескольким переменным помещаться в один слот хранения.
С помощью этого изменения разработчики могут сэкономить 20 000 единиц Gas. ### Хранение неиспользуемого хранилища требует 20 000 Gas (, но теперь требуется только два хранилища.
Поскольку каждый слот хранения потребляет Газ, упаковка переменных оптимизирует использование Газа, сокращая необходимое количество слотов хранения.
![Десять лучших практик оптимизации газа для смарт-контрактов Ethereum])https://img-cdn.gateio.im/webp-social/moments-995905cb414526d4d991899d0c2e6443.webp(
) 3. Оптимизация типов данных
Переменная может быть представлена несколькими типами данных, но стоимость операций для разных типов данных также различна. Выбор подходящего типа данных помогает оптимизировать использование газа.
Например, в Solidity целые числа могут быть разделены на различные размеры: uint8, uint16, uint32 и т.д. Поскольку EVM выполняет операции в 256 битах, использование uint8 означает, что EVM сначала должен преобразовать его в uint256, а это преобразование потребует дополнительного расхода газа.
На первый взгляд, использование uint256 дешевле, чем uint8. Однако, если использовать упаковку переменных для оптимизации, ситуация меняется. Если разработчик может упаковать четыре переменные uint8 в один слот хранения, то общая стоимость их итерации будет ниже, чем стоимость четырех переменных uint256. Таким образом, смарт-контракты могут читать и записывать один слот хранения, и за одно действие помещать четыре переменные uint8 в память/хранение.
4. Используйте переменные фиксированного размера вместо динамических переменных
Если данные можно ограничить до 32 байт, рекомендуется использовать тип данных bytes32 вместо bytes или strings. Обычно переменные фиксированного размера потребляют меньше газа, чем переменные переменного размера. Если длину байтов можно ограничить, старайтесь выбирать минимальную длину от bytes1 до bytes32.
5. Отображение и массивы
Списки данных Solidity могут быть представлены двумя типами данных: массивы ( Arrays ) и отображения ### Mappings (, но их синтаксис и структура совершенно разные.
В большинстве случаев отображение более эффективно и имеет более низкие затраты, но массивы обладают итерируемостью и поддерживают упаковку типов данных. Поэтому рекомендуется при управлении списками данных отдавать предпочтение отображению, если не требуется итерация или можно оптимизировать потребление газа за счет упаковки типов данных.
![Десять лучших практик оптимизации газа для смарт-контрактов Ethereum])https://img-cdn.gateio.im/webp-social/moments-9c566626ab499ef65d6f5089a2876ad3.webp(
) 6. Используйте calldata вместо memory
Переменные, объявленные в параметрах функции, могут храниться в calldata или memory. Основное различие между ними заключается в том, что memory может быть изменен функцией, тогда как calldata неизменяем.
Помните этот принцип: если параметры функции являются только для чтения, следует в первую очередь использовать calldata, а не memory. Это поможет избежать ненужных операций копирования из calldata функции в memory.
7. Используйте ключевые слова Constant/Immutable, когда это возможно.
Переменные Constant/Immutable не хранятся в хранилище контракта. Эти переменные вычисляются на этапе компиляции и хранятся в байт-коде контракта. Поэтому их стоимость доступа значительно ниже, чем у хранения, рекомендуется использовать ключевые слова Constant или Immutable, когда это возможно.
8. Используйте Unchecked, чтобы убедиться, что переполнение/недостаток не произойдет.
Когда разработчики могут гарантировать, что арифметические операции не приведут к переполнению или недостатку, они могут использовать ключевое слово unchecked, введенное в Solidity v0.8.0, чтобы избежать лишних проверок на переполнение или недостаток, тем самым экономя стоимость транзакции.
Кроме того, компиляторы версии 0.8.0 и выше больше не требуют использования библиотеки SafeMath, поскольку сам компилятор уже включает функции защиты от переполнения и недополнения.
9. Оптимизация модификатора
Код модификатора встроен в изменённую функцию, и каждый раз, когда используется модификатор, его код копируется. Это увеличивает размер байт-кода и повышает расход газа.
Путем реконструкции логики в внутреннюю функцию _checkOwner(), разрешается повторное использование этой внутренней функции в модификаторе, что может уменьшить размер байт-кода и Падение стоимости транзакции.
![Десять лучших практик оптимизации Gas для смарт-контрактов Ethereum]###https://img-cdn.gateio.im/webp-social/moments-a141884dcdcdc56faff12eee2601b7b7.webp(
) 10. Оптимизация короткого замыкания
Для || и && операторов логические операции будут подвергаться краткому оцениванию, то есть если первое условие уже может определить результат логического выражения, второе условие не будет оцениваться.
Чтобы оптимизировать потребление газа, условия с низкой стоимостью вычислений должны быть размещены в начале, это может позволить пропустить вычисления с высокой стоимостью.
Общие дополнительные рекомендации
1. Удалить ненужный код
Если в смарт-контракте существуют неиспользуемые функции или переменные, рекомендуется их удалить. Это самый прямой способ снизить стоимость транзакции и сохранить небольшой объем контракта.
Вот некоторые полезные советы:
Используйте наиболее эффективные алгоритмы для вычислений. Если в смарт-контракте используются результаты некоторых вычислений напрямую, то следует исключить эти избыточные вычислительные процессы. По сути, любые неиспользуемые вычисления должны быть удалены.
В Ethereum разработчики могут получать награды в виде Gas, освобождая пространство для хранения. Если переменная больше не нужна, следует удалить ее с помощью ключевого слова delete или установить ее в значение по умолчанию.
Оптимизация циклов: избегайте операций с высокими затратами в циклах, по возможности объединяйте циклы и выносите повторяющиеся вычисления за пределы тела цикла.
( 2. Использование предкомпилированных смарт-контрактов
Предварительно скомпилированные контракты предоставляют сложные библиотечные функции, такие как операции шифрования и хеширования. Поскольку код не выполняется на EVM, а выполняется локально на клиентском узле, требуется меньше газа. Использование предварительно скомпилированных контрактов может сэкономить газ за счет сокращения вычислительных затрат, необходимых для выполнения смарт-контрактов.
Примеры предсоставленных контрактов включают алгоритм цифровой подписи на основе эллиптической кривой )ECDSA### и хеш-алгоритм SHA2-256. Используя эти предсоставленные контракты в смарт-контрактах, разработчики могут Падение стоимость транзакции и повысить эффективность работы приложений.
3. Использование встроенного ассемблера
Встроенная сборка ( in-line assembly ) позволяет разработчикам писать низкоуровневый, но эффективный код, который может быть выполнен непосредственно EVM, без необходимости использования дорогостоящих операций Solidity. Встроенная сборка также позволяет более точно контролировать использование памяти и хранения, что дополнительно снижает Стоимость транзакции. Кроме того, встроенная сборка может выполнять некоторые функции, которые сложно реализовать только с помощью Solidity.