Руководство по оптимизации газа для смарт-контрактов Ethereum
Газовые сборы в основной сети Ethereum всегда были проблемой, особенно это становится очевидным в условиях перегруженности сети. В пиковые часы пользователям часто приходится платить высокие комиссии за транзакции. Поэтому оптимизация газовых сборов на этапе разработки смарт-контрактов имеет решающее значение. Оптимизация потребления газа не только эффективно снижает затраты на транзакции, но и повышает эффективность транзакций, обеспечивая пользователям более экономичный и эффективный опыт использования блокчейна.
В данной статье будет рассмотрена механика Gas-стоимости Эфирной виртуальной машины (EVM), ключевые концепции оптимизации Gas-стоимости, а также лучшие практики оптимизации Gas-стоимости при разработке смарт-контрактов. Мы надеемся, что этот материал вдохновит разработчиков и окажет практическую помощь, а также поможет обычным пользователям лучше понять, как работает система Gas-стоимости EVM, чтобы вместе справляться с вызовами экосистемы блокчейна.
Введение в механизм газа EVM
В совместимых с EVM сетях "Gas" является единицей измерения вычислительной мощности, необходимой для выполнения определенных операций.
В структуре EVM потребление газа делится на три части: выполнение операций, внешние вызовы сообщений и чтение/запись в память и хранилище.
Поскольку выполнение каждой сделки требует вычислительных ресурсов, взимается определенная плата, чтобы предотвратить бесконечные циклы и атаки отказа в обслуживании (DoS). Плата, необходимая для завершения сделки, называется "Gas fee".
С момента вступления в силу лондонского хардфорка EIP-1559( ), плата за газ рассчитывается по следующей формуле:
Gas плата = использованные единицы Gas * ( базовая ставка + приоритетная плата )
Базовая комиссия будет уничтожена, а приоритетная комиссия будет использоваться в качестве стимула, чтобы побудить валидаторов добавлять транзакции в блокчейн. Установка более высокой приоритетной комиссии при отправке транзакции может увеличить вероятность включения транзакции в следующий блок. Это похоже на «чаевые», которые пользователи платят валидаторам.
Понимание оптимизации Gas в EVM
При компиляции смарт-контрактов на Solidity контракт преобразуется в серию "операционных кодов", то есть opcodes.
Любая операция с кодом (, например, создание контракта, выполнение вызова сообщения, доступ к хранилищу аккаунта и выполнение операций на виртуальной машине ) имеет общеизвестную стоимость потребления Gas, эти затраты записаны в желтой книге Ethereum.
После нескольких изменений EIP, стоимость газа для некоторых операторов была скорректирована и может отличаться от указанных в жёлтой книге.
Основные концепции оптимизации газа
Основная идея оптимизации газа заключается в том, чтобы в блокчейне EVM приоритизировать операции с высокой стоимостью эффективности и избегать операций с дорогой стоимостью газа.
В EVM следующие операции имеют низкую стоимость:
Чтение и запись переменных в памяти
Чтение констант и неизменяемых переменных
Чтение и запись локальных переменных
Чтение переменной calldata, например, массива и структуры calldata
Внутренний вызов функции
Дорогостоящие операции включают:
Чтение и запись состояний переменных, хранящихся в смарт-контрактах
Вызов внешних функций
Циклическая операция
Оптимизация затрат на газ EVM: лучшие практики
Основываясь на вышеуказанных основных концепциях, мы подготовили список лучших практик оптимизации Gas для сообщества разработчиков. Следуя этим практикам, разработчики могут снизить потребление Gas смарт-контрактами, снизить затраты на транзакции и создать более эффективные и удобные для пользователей приложения.
1. Старайтесь минимизировать использование хранилища
В Solidity, Storage( хранение) является ограниченным ресурсом, его потребление газа гораздо выше, чем у Memory( памяти). Каждый раз, когда смарт-контракт считывает или записывает данные из хранилища, возникают высокие затраты на газ.
Согласно определению в желтой книге Ethereum, стоимость операций хранения более чем в 100 раз превышает стоимость операций с памятью. Например, инструкции OPcodesmload и mstore потребляют всего 3 единицы Gas, в то время как операции хранения, такие как sload и sstore, даже в самых идеальных условиях требуют как минимум 100 единиц.
Методы ограничения использования хранения включают:
Храните непостоянные данные в памяти
Уменьшение количества изменений в хранилище: сохраняя промежуточные результаты в памяти и распределяя результаты переменным хранения только после завершения всех вычислений.
2. Упаковка переменных
Количество хранилищ, используемых в смарт-контрактах, таких как Storage slot(, а также способ, которым разработчики представляют данные, будут значительно влиять на потребление Gas.
Компилятор Solidity упаковывает последовательные переменные хранения в процессе компиляции и использует 32-байтовый слот хранения в качестве базовой единицы хранения переменных. Упаковка переменных означает разумное размещение переменных, чтобы несколько переменных могли поместиться в одном слоте хранения.
С помощью этой настройки разработчики могут сэкономить 20 000 единиц газа. Хранение неиспользуемого слота требует 20 000 газа, но теперь нужно всего два слота.
Поскольку каждое хранилище слотов будет потреблять Газ, упаковка переменных оптимизирует использование Газа за счет уменьшения необходимого количества хранилищ слотов.
![Оптимизация газа смарт-контрактов Ethereum: десять лучших практик])https://img-cdn.gateio.im/webp-social/moments-30f0bc370a7b9ca65f3d623c31262b76.webp(
) 3. Оптимизация типов данных
Переменная может быть представлена различными типами данных, но стоимость операций с разными типами данных также различна. Выбор подходящего типа данных помогает оптимизировать использование Gas.
Например, в 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 (, но их синтаксис и структура совершенно разные.
В большинстве случаев отображение более эффективно и менее затратно, но массивы обладают итерабельностью и поддерживают упаковку типов данных. Поэтому рекомендуется при управлении списками данных в первую очередь использовать отображение, если не требуется итерация или можно оптимизировать потребление Gas за счет упаковки типов данных.
![Оптимизация Gas для смарт-контрактов Ethereum: 10 лучших практик])https://img-cdn.gateio.im/webp-social/moments-5f3d7e103e47c886f50599cffe35c707.webp(
) 6. Используйте calldata вместо memory
Переменные, объявленные в параметрах функции, могут храниться в calldata или memory. Основное различие между ними заключается в том, что memory может быть изменен функцией, тогда как calldata является неизменяемым.
Запомните этот принцип: если параметры функции являются только для чтения, следует предпочесть использование calldata вместо memory. Это позволит избежать ненужных операций копирования из calldata функции в memory.
7. Используйте ключевые слова Constant/Immutable по возможности
Постоянные/неизменяемые переменные не будут храниться в хранилище контракта. Эти переменные вычисляются во время компиляции и хранятся в байт-коде контракта. Поэтому их стоимость доступа гораздо ниже, чем у хранилища, и рекомендуется использовать ключевые слова Constant или Immutable, когда это возможно.
8. Используйте Unchecked, чтобы гарантировать отсутствие переполнения/недостатка
Когда разработчики могут быть уверены, что арифметические операции не приведут к переполнению или недополнению, они могут использовать ключевое слово unchecked, введенное в Solidity v0.8.0, чтобы избежать избыточной проверки переполнения или недополнения, тем самым экономя стоимость газа.
Кроме того, компиляторы версии 0.8.0 и выше больше не требуют использования библиотеки SafeMath, так как сам компилятор уже встроил функции защиты от переполнения и недополнения.
9. Оптимизация модификатора
Код модификатора встраивается в измененную функцию, и каждый раз при использовании модификатора его код копируется. Это увеличивает размер байт-кода и повышает потребление газа. Можно уменьшить размер байт-кода и снизить стоимость газа, перестроив логику в внутреннюю функцию, что позволит повторно использовать эту внутреннюю функцию в модификаторе.
10. Оптимизация короткого замыкания
Для операторов || и && логические операции будут подвергаться короткому оцениванию, то есть если первое условие уже может определить результат логического выражения, второе условие не будет оцениваться.
Чтобы оптимизировать потребление газа, следует размещать условия с низкой вычислительной стоимостью в начале, так это может позволить пропустить дорогостоящие вычисления.
Дополнительные общие рекомендации
1. Удалить ненужный код
Если в смарт-контракте есть неиспользуемые функции или переменные, рекомендуется их удалить. Это самый прямой способ снизить стоимость развертывания контракта и сохранить небольшой размер контракта.
Вот несколько полезных советов:
Используйте самые эффективные алгоритмы для вычислений. Если в смарт-контрактах используются результаты некоторых вычислений напрямую, то следует исключить эти избыточные вычислительные процессы. По сути, любые неиспользуемые вычисления должны быть удалены.
В Ethereum разработчики могут получить вознаграждение в виде Gas, освободив место в хранилище. Если переменная больше не нужна, следует использовать ключевое слово delete для её удаления или установить её в значение по умолчанию.
Оптимизация циклов: избегайте высокозатратных операций цикла, по возможности объединяйте циклы и выносите повторяющиеся вычисления за пределы тела цикла.
( 2. Использование предкомпилированных смарт-контрактов
Предварительно скомпилированные контракты предоставляют сложные библиотечные функции, такие как операции шифрования и хеширования. Поскольку код не выполняется на EVM, а выполняется локально на клиентском узле, требуется меньше газа. Использование предварительно скомпилированных контрактов может сократить количество вычислительных затрат, необходимых для выполнения смарт-контрактов, что позволяет сэкономить газ.
Примеры предкомпилированных контрактов включают алгоритм цифровой подписи на основе эллиптической кривой )ECDSA### и хэш-алгоритм SHA2-256. Используя эти предкомпилированные контракты в смарт-контрактах, разработчики могут снизить затраты на газ и повысить эффективность работы приложений.
3. Использование встроенного ассемблерного кода
Встраиваемая сборка ( in-line assembly ) позволяет разработчикам писать низкоуровневый, но эффективный код, который может выполняться EVM напрямую, без необходимости использования дорогих операций Solidity. Встраиваемая сборка также позволяет более точно контролировать использование памяти и хранилища, что дополнительно снижаетGas-расходы. Кроме того, встраиваемая сборка может выполнять некоторые сложные операции, которые сложно реализовать только с помощью Solidity, предоставляя больше гибкости для оптимизации расхода Gas.
Однако использование встроенного ассемблера также может представлять собой риск и содержать
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
13 Лайков
Награда
13
4
Поделиться
комментарий
0/400
DaoGovernanceOfficer
· 20ч назад
*вздох* еще один пост о Газ, который игнорирует исследование масштабирования l2...
Посмотреть ОригиналОтветить0
ApeShotFirst
· 20ч назад
Газ费 высокие, что я, наверное, разорился.
Посмотреть ОригиналОтветить0
BottomMisser
· 20ч назад
Оптимизация газа? Лучше подождать медвежий рынок.
Посмотреть ОригиналОтветить0
Rekt_Recovery
· 20ч назад
прощай, плата за газ... всё ещё восстанавливаюсь от ПТСР 2021, если честно
Полное руководство по оптимизации Gas смарт-контрактов Ethereum: Падение стоимости транзакции и повышение эффективности
Руководство по оптимизации газа для смарт-контрактов Ethereum
Газовые сборы в основной сети Ethereum всегда были проблемой, особенно это становится очевидным в условиях перегруженности сети. В пиковые часы пользователям часто приходится платить высокие комиссии за транзакции. Поэтому оптимизация газовых сборов на этапе разработки смарт-контрактов имеет решающее значение. Оптимизация потребления газа не только эффективно снижает затраты на транзакции, но и повышает эффективность транзакций, обеспечивая пользователям более экономичный и эффективный опыт использования блокчейна.
В данной статье будет рассмотрена механика Gas-стоимости Эфирной виртуальной машины (EVM), ключевые концепции оптимизации Gas-стоимости, а также лучшие практики оптимизации Gas-стоимости при разработке смарт-контрактов. Мы надеемся, что этот материал вдохновит разработчиков и окажет практическую помощь, а также поможет обычным пользователям лучше понять, как работает система Gas-стоимости EVM, чтобы вместе справляться с вызовами экосистемы блокчейна.
Введение в механизм газа EVM
В совместимых с EVM сетях "Gas" является единицей измерения вычислительной мощности, необходимой для выполнения определенных операций.
В структуре EVM потребление газа делится на три части: выполнение операций, внешние вызовы сообщений и чтение/запись в память и хранилище.
Поскольку выполнение каждой сделки требует вычислительных ресурсов, взимается определенная плата, чтобы предотвратить бесконечные циклы и атаки отказа в обслуживании (DoS). Плата, необходимая для завершения сделки, называется "Gas fee".
С момента вступления в силу лондонского хардфорка EIP-1559( ), плата за газ рассчитывается по следующей формуле:
Gas плата = использованные единицы Gas * ( базовая ставка + приоритетная плата )
Базовая комиссия будет уничтожена, а приоритетная комиссия будет использоваться в качестве стимула, чтобы побудить валидаторов добавлять транзакции в блокчейн. Установка более высокой приоритетной комиссии при отправке транзакции может увеличить вероятность включения транзакции в следующий блок. Это похоже на «чаевые», которые пользователи платят валидаторам.
Понимание оптимизации Gas в EVM
При компиляции смарт-контрактов на Solidity контракт преобразуется в серию "операционных кодов", то есть opcodes.
Любая операция с кодом (, например, создание контракта, выполнение вызова сообщения, доступ к хранилищу аккаунта и выполнение операций на виртуальной машине ) имеет общеизвестную стоимость потребления Gas, эти затраты записаны в желтой книге Ethereum.
После нескольких изменений EIP, стоимость газа для некоторых операторов была скорректирована и может отличаться от указанных в жёлтой книге.
Основные концепции оптимизации газа
Основная идея оптимизации газа заключается в том, чтобы в блокчейне EVM приоритизировать операции с высокой стоимостью эффективности и избегать операций с дорогой стоимостью газа.
В EVM следующие операции имеют низкую стоимость:
Дорогостоящие операции включают:
Оптимизация затрат на газ EVM: лучшие практики
Основываясь на вышеуказанных основных концепциях, мы подготовили список лучших практик оптимизации Gas для сообщества разработчиков. Следуя этим практикам, разработчики могут снизить потребление Gas смарт-контрактами, снизить затраты на транзакции и создать более эффективные и удобные для пользователей приложения.
1. Старайтесь минимизировать использование хранилища
В Solidity, Storage( хранение) является ограниченным ресурсом, его потребление газа гораздо выше, чем у Memory( памяти). Каждый раз, когда смарт-контракт считывает или записывает данные из хранилища, возникают высокие затраты на газ.
Согласно определению в желтой книге Ethereum, стоимость операций хранения более чем в 100 раз превышает стоимость операций с памятью. Например, инструкции OPcodesmload и mstore потребляют всего 3 единицы Gas, в то время как операции хранения, такие как sload и sstore, даже в самых идеальных условиях требуют как минимум 100 единиц.
Методы ограничения использования хранения включают:
2. Упаковка переменных
Количество хранилищ, используемых в смарт-контрактах, таких как Storage slot(, а также способ, которым разработчики представляют данные, будут значительно влиять на потребление Gas.
Компилятор Solidity упаковывает последовательные переменные хранения в процессе компиляции и использует 32-байтовый слот хранения в качестве базовой единицы хранения переменных. Упаковка переменных означает разумное размещение переменных, чтобы несколько переменных могли поместиться в одном слоте хранения.
С помощью этой настройки разработчики могут сэкономить 20 000 единиц газа. Хранение неиспользуемого слота требует 20 000 газа, но теперь нужно всего два слота.
Поскольку каждое хранилище слотов будет потреблять Газ, упаковка переменных оптимизирует использование Газа за счет уменьшения необходимого количества хранилищ слотов.
![Оптимизация газа смарт-контрактов Ethereum: десять лучших практик])https://img-cdn.gateio.im/webp-social/moments-30f0bc370a7b9ca65f3d623c31262b76.webp(
) 3. Оптимизация типов данных
Переменная может быть представлена различными типами данных, но стоимость операций с разными типами данных также различна. Выбор подходящего типа данных помогает оптимизировать использование Gas.
Например, в 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 (, но их синтаксис и структура совершенно разные.
В большинстве случаев отображение более эффективно и менее затратно, но массивы обладают итерабельностью и поддерживают упаковку типов данных. Поэтому рекомендуется при управлении списками данных в первую очередь использовать отображение, если не требуется итерация или можно оптимизировать потребление Gas за счет упаковки типов данных.
![Оптимизация Gas для смарт-контрактов Ethereum: 10 лучших практик])https://img-cdn.gateio.im/webp-social/moments-5f3d7e103e47c886f50599cffe35c707.webp(
) 6. Используйте calldata вместо memory
Переменные, объявленные в параметрах функции, могут храниться в calldata или memory. Основное различие между ними заключается в том, что memory может быть изменен функцией, тогда как calldata является неизменяемым.
Запомните этот принцип: если параметры функции являются только для чтения, следует предпочесть использование calldata вместо memory. Это позволит избежать ненужных операций копирования из calldata функции в memory.
7. Используйте ключевые слова Constant/Immutable по возможности
Постоянные/неизменяемые переменные не будут храниться в хранилище контракта. Эти переменные вычисляются во время компиляции и хранятся в байт-коде контракта. Поэтому их стоимость доступа гораздо ниже, чем у хранилища, и рекомендуется использовать ключевые слова Constant или Immutable, когда это возможно.
8. Используйте Unchecked, чтобы гарантировать отсутствие переполнения/недостатка
Когда разработчики могут быть уверены, что арифметические операции не приведут к переполнению или недополнению, они могут использовать ключевое слово unchecked, введенное в Solidity v0.8.0, чтобы избежать избыточной проверки переполнения или недополнения, тем самым экономя стоимость газа.
Кроме того, компиляторы версии 0.8.0 и выше больше не требуют использования библиотеки SafeMath, так как сам компилятор уже встроил функции защиты от переполнения и недополнения.
9. Оптимизация модификатора
Код модификатора встраивается в измененную функцию, и каждый раз при использовании модификатора его код копируется. Это увеличивает размер байт-кода и повышает потребление газа. Можно уменьшить размер байт-кода и снизить стоимость газа, перестроив логику в внутреннюю функцию, что позволит повторно использовать эту внутреннюю функцию в модификаторе.
10. Оптимизация короткого замыкания
Для операторов || и && логические операции будут подвергаться короткому оцениванию, то есть если первое условие уже может определить результат логического выражения, второе условие не будет оцениваться.
Чтобы оптимизировать потребление газа, следует размещать условия с низкой вычислительной стоимостью в начале, так это может позволить пропустить дорогостоящие вычисления.
Дополнительные общие рекомендации
1. Удалить ненужный код
Если в смарт-контракте есть неиспользуемые функции или переменные, рекомендуется их удалить. Это самый прямой способ снизить стоимость развертывания контракта и сохранить небольшой размер контракта.
Вот несколько полезных советов:
Используйте самые эффективные алгоритмы для вычислений. Если в смарт-контрактах используются результаты некоторых вычислений напрямую, то следует исключить эти избыточные вычислительные процессы. По сути, любые неиспользуемые вычисления должны быть удалены.
В Ethereum разработчики могут получить вознаграждение в виде Gas, освободив место в хранилище. Если переменная больше не нужна, следует использовать ключевое слово delete для её удаления или установить её в значение по умолчанию.
Оптимизация циклов: избегайте высокозатратных операций цикла, по возможности объединяйте циклы и выносите повторяющиеся вычисления за пределы тела цикла.
( 2. Использование предкомпилированных смарт-контрактов
Предварительно скомпилированные контракты предоставляют сложные библиотечные функции, такие как операции шифрования и хеширования. Поскольку код не выполняется на EVM, а выполняется локально на клиентском узле, требуется меньше газа. Использование предварительно скомпилированных контрактов может сократить количество вычислительных затрат, необходимых для выполнения смарт-контрактов, что позволяет сэкономить газ.
Примеры предкомпилированных контрактов включают алгоритм цифровой подписи на основе эллиптической кривой )ECDSA### и хэш-алгоритм SHA2-256. Используя эти предкомпилированные контракты в смарт-контрактах, разработчики могут снизить затраты на газ и повысить эффективность работы приложений.
3. Использование встроенного ассемблерного кода
Встраиваемая сборка ( in-line assembly ) позволяет разработчикам писать низкоуровневый, но эффективный код, который может выполняться EVM напрямую, без необходимости использования дорогих операций Solidity. Встраиваемая сборка также позволяет более точно контролировать использование памяти и хранилища, что дополнительно снижаетGas-расходы. Кроме того, встраиваемая сборка может выполнять некоторые сложные операции, которые сложно реализовать только с помощью Solidity, предоставляя больше гибкости для оптимизации расхода Gas.
Однако использование встроенного ассемблера также может представлять собой риск и содержать