Топ-10 найкращих практик оптимізації газу в смарт-контрактах Ethereum

Середній1/3/2025, 11:25:57 AM
Ця стаття досліджує проблеми з оплатою газу в основній мережі Ethereum та методи оптимізації. Вона зосереджена на механізмі газу EVM, основних концепціях оптимізації витрат газу та найкращих практиках розробки смартконтрактів. Серед них зменшення обсягу зберігання, упаковка змінних, оптимізація типів даних та використання змінних фіксованого розміру.

Дотримуючись цих практик, розробники можуть зменшити споживання газу в смартконтрактах, знизити витрати на транзакції та створити більш ефективні та зручні додатки.

Комісії за газ на головній мережі Ethereum завжди були основною проблемою, особливо під час періодів перевантаження мережі. Під час піків, користувачам часто доводиться платити надзвичайно високі комісії за транзакції. Тому оптимізація витрат на газ на етапі розробки смарт-контрактів є важливою. Оптимізація газу може не тільки ефективно зменшити витрати на транзакції, але й покращити їх ефективність, надаючи користувачам економічніший та ефективніший досвід використання блокчейну.

Ця стаття розкриє механізм плати за газ в Ethereum Virtual Machine (EVM), основні концепції, пов'язані з оптимізацією плати за газ, та найкращі практики для оптимізації плати за газ при розробці смартконтрактів. Сподіваємося, що цей контент надихне та допоможе розробникам, а також допоможе звичайним користувачам краще розібратися, як працює система плати за газ EVM, спільно вирішуючи проблеми в екосистемі блокчейну.

Огляд механізму витрат на газ EVM

У мережах, сумісних з EVM, «газ» вказує на одиницю, яка використовується для вимірювання обчислювальної потужності, необхідної для виконання певних операцій.

На діаграмі нижче показана структура EVM. На діаграмі споживання газу поділено на три частини: виконання операцій, зовнішні виклики повідомлень та читання/запис в пам'ять та сховище.

Джерело: Офіційний веб-сайт Ethereum[1]

З моменту активації EIP-1559 (London Hard Fork), вартість газу обчислюється за наступною формулою:

Вартість газу = одиниці використаного газу * (базова комісія + пріоритетна комісія)

Базова комісія спалюється, а пріоритетна комісія служить стимулом для заохочення валідаторів включити транзакцію в блокчейн. Встановлення комісії з вищим пріоритетом під час надсилання транзакції збільшує ймовірність включення транзакції до наступного блоку. Це схоже на «чайові», які користувачі платять валідаторам.

1. Розуміння оптимізації газу в EVM

При компіляції розумного контракту з Solidity контракт перетворюється на набір "операційних кодів", або опкодів.

Кожен опкод (такий як створення контракту, здійснення викликів повідомлень, доступ до сховища облікового запису та виконання операцій на віртуальній машині) має пов'язану вартість споживання газу, яка документується в Ethereum Yellow Paper[2].

Після багаторазових модифікацій EIP витрати на газ для деяких кодів операцій були скориговані, які можуть відрізнятися від значень у Жовтій книзі. Для отримання детальної інформації про останню вартість операційних кодів, будь ласка, зверніться до цього джерела[3].

2. Основні концепції оптимізації газу

Основна концепція оптимізації газу полягає в тому, щоб надавати пріоритет вартісним операціям на блокчейні EVM і уникати операцій, які призводять до високих витрат на газ.

У EVM наступні операції є відносно недорогими:

  • [ ] Читання та запис змінних пам'яті
  • [ ] Читання постійних та незмінних змінних
  • [ ] Читання та запис локальних змінних
  • [ ] Читання змінних calldata, таких як масиви calldata та структури
  • [ ] Внутрішні виклики функцій

Високі витрати включають в себе:

  • Читання та запис змінних стану, збережених у сховищі контракту
  • [ ] Зовнішні виклики функцій
  • [ ] Операції з циклом

Найкращі практики оптимізації витрат на газ EVM

На основі вищезазначених основних концепцій ми склали список найкращих практик оптимізації витрат на газ для розробницької спільноти. Дотримуючись цих практик, розробники можуть зменшити споживання газу у смарт-контрактів, знизити витрати на транзакції та створити більш ефективні та зручні для користувачів додатки.

1. Мінімізувати використання сховища

У Solidity зберігання є обмеженим ресурсом, і його споживання газу значно вище, ніж у пам'яті. Кожного разу, коли смарт-контракт зчитує зберігання або записує у нього, він зазнає високих витрат газу.

Згідно з визначенням у Жовтій книзі Ethereum, вартість операцій зберігання вище, ніж пам'яті більше, ніж у 100 разів. Наприклад, опкоди, такі як sload та sstore, коштують принаймні 100 одиниць газу у найкращому випадку, тоді як операції з пам'яттю, такі як mload та mstore, споживають лише 3 одиниці газу.

Способи обмеження використання сховища включають:

  • [ ] Зберігати тимчасові дані в пам'яті
  • [ ] Зменшити кількість змін у сховищі: Зберігаючи проміжні результати в пам'яті і призначаючи кінцевий результат змінним у сховищі лише після завершення всіх обчислень.

2. Упакування змінних

Кількість використаних слотів зберігання в розумних контрактах та спосіб представлення даних розробниками можуть суттєво впливати на споживання газу.

Компілятор Solidity упаковує послідовні змінні зберігання під час процесу компіляції, використовуючи 32-байтові слоти зберігання як основну одиницю для зберігання змінних. Упаковка змінних відноситься до практики розташування змінних таким чином, щоб кілька змінних помістилися в один слот зберігання.

Ліворуч - менш ефективна реалізація, яка використовує 3 слоти зберігання; праворуч - більш ефективна реалізація.

Зробивши це налаштування, розробники можуть зекономити 20 000 одиниць газу (оскільки зберігання не використовуваного слоту зберігання коштує 20 000 газу), але тепер потрібно лише два слоти зберігання.

Оскільки кожен слот зберігання споживає газ, упаковка змінних оптимізує використання газу шляхом зменшення кількості необхідних слотів зберігання.

3. Оптимізація типів даних

Змінну можна представити за допомогою різних типів даних, але витрати на операції варіюються в залежності від типу. Вибір відповідного типу даних допомагає оптимізувати використання газу.

Наприклад, у Solidity цілі числа можуть бути поділені на різні розміри: uint8, uint16, uint32 тощо. Оскільки EVM працює з 256-бітними блоками, використання uint8 означає, що спочатку EVM повинна перетворити його на uint256, і це призводить до додаткових витрат на газ при конвертації.

Ми можемо порівняти витрати газу uint8 та uint256 за допомогою коду на діаграмі. Функція UseUint() споживає 120,382 одиниць газу, тоді як функція UseUInt8() споживає 166,111 одиниць газу.

Сам по собі використання uint256 дешевше, ніж uint8. Однак, якщо ми застосуємо раніше запропоновану оптимізацію упаковування змінних, це робить різницю. Якщо розробники можуть упакувати чотири змінні uint8 в один сховищний слот, загальна вартість ітерації над ними буде нижчою, ніж використання чотирьох змінних uint256. У цьому випадку смарт-контракт може прочитати та записати сховищний слот один раз та завантажити всі чотири змінні uint8 в пам'ять/сховище за одну операцію.

4. Використовуйте змінні фіксованого розміру замість динамічних змінних

Якщо дані можуть бути обмежені до 32 байтів, рекомендується використовувати тип даних bytes32 замість bytes або strings. Загалом, змінні фіксованого розміру споживають менше газу, ніж змінні динамічного розміру. Якщо можлива обмеження довжини байтів, спробуйте вибрати найменшу довжину від bytes1 до bytes32.

5. Відображення проти Масивів

У Solidity списки даних можна представити за допомогою двох типів даних: Масиви та Картографування, кожен з власним синтаксисом та структурою.

У більшості випадків відображення є більш ефективним і економічним, тоді як масиви є ітерабельними і підтримують упаковку типів даних. Тому рекомендується віддавати перевагу використанню відображень при керуванні списками даних, якщо необхідна ітерація або споживання газу може бути оптимізовано за допомогою упаковки типу даних.

6. Використовуйте calldata замість пам'яті

Змінні, оголошені в параметрах функції, можуть бути збережені як у calldata, так і в пам'яті. Основна різниця полягає в тому, що пам'ять може бути змінена функцією, тоді як calldata є незмінним.

Пам'ятайте про цей принцип: якщо параметри функції є тільки для читання, краще використовувати calldata замість пам'яті. Це уникне непотрібних операцій копіювання даних з calldata в пам'ять функції.

Приклад 1: Використання пам'яті

При використанні ключового слова memory значення масиву копіюються з закодованого calldata в пам'ять під час декодування ABI. Вартість виконання цього блоку коду становить 3 694 одиниці газу.

Приклад 2: Використання calldata

При зчитуванні значень безпосередньо з calldata проміжна операція пам'яті пропускається. Ця оптимізація знижує вартість виконання лише до 2 413 газових блоків, що призводить до підвищення ефективності газу на 35%.

7. Використовуйте ключові слова Constant/Immutable, якщо це можливо

Константні / незмінні змінні не зберігаються в сховищі контракту. Ці змінні обчислюються на етапі компіляції та зберігаються в байткоді контракту. Таким чином, вартість доступу до них набагато нижча порівняно зі змінними сховища. Рекомендується використовувати ключові слова Constant або Immutable, якщо це можливо.

8. Використовуйте Unchecked, коли переповнення / недоповнення не є проблемою

Коли розробники можуть бути впевнені, що арифметичні операції не призведуть до переповнення або недостатку, вони можуть використовувати ключове слово безперевірки, введене в Solidity v0.8.0, щоб уникнути непотрібних перевірок переповнення або недостатку, тим самим зекономивши витрати на газ.

На схемі нижче, умовно обмежений i

Крім того, версії компілятора 0.8.0 та вище більше не потребують використання бібліотеки SafeMath, оскільки сам компілятор тепер містить вбудований захист від переповнення та недоповнення.

9. Оптимізуйте модифікатор

Код модифікаторів вбудовується в функції, які вони модифікують. Кожного разу, коли використовується модифікатор, його код дублюється, що збільшує розмір байткоду та збільшує споживання газу. Ось один спосіб оптимізації витрат газу на модифікатори:

Перед оптимізацією:

Після оптимізації:

У цьому прикладі, рефакторінгом логіки внутрішньої функції _checkOwner(), яка може бути використана в модифікаторі, розмір байткоду зменшується, а витрати на газ знижуються.

10. Оптимізація короткого замикання

Для операторів || (OR) та && (AND), логічні операції оцінюються зі скороченням, що означає, що якщо перша умова достатня для визначення результату логічного виразу, друга умова не буде оцінена.

Для оптимізації споживання газу, умови з меншими витратами обчислень слід розміщувати спочатку, щоб потенційно дорогі обчислення можна було пропустити.

Загальні рекомендації

1. Видаліть невикористаний код

Якщо у контракті є невикористані функції або змінні, рекомендується їх видалити. Це найпряміший спосіб зменшити витрати на розгортання контракту та зберегти його розмір малим.

Ось кілька практичних рекомендацій:

Використовуйте найбільш ефективні алгоритми для обчислень. Якщо контракт безпосередньо використовує певні результати обчислень, зайві обчислення слід видалити. Практично будь-які невикористані обчислення слід видаляти. У Ethereum розробники можуть отримувати газові винагороди, випускаючи простір для зберігання. Якщо змінна більше не потрібна, її слід видалити за допомогою ключового слова delete або встановити значення за замовчуванням.

Оптимізація циклу: Уникайте операцій з високою вартістю циклу, спробуйте об'єднати цикли та виносити повторні обчислення з тіла циклу.

2. Використовуйте попередньо скомпільовані контракти

Попередньо скомпільовані контракти надають складні бібліотечні функції, такі як криптографія та хеш-операції. Оскільки код не виконується на EVM, а працює локально на вузлі клієнта, потрібно менше газу. Використання попередньо скомпільованих контрактів може заощадити газ, зменшивши обчислювальне навантаження, необхідне для виконання смартконтракту.

Приклади попередньо скомпільованих контрактів включають алгоритм цифрового підпису на еліптичних кривих (ECDSA) та хеш-функцію SHA2-256. Використовуючи ці попередньо скомпільовані контракти в смарт-контрактах, розробники можуть знизити витрати на газ та покращити ефективність застосунку.

Для повного списку попередньо скомпільованих контрактів, які підтримує мережа Ethereum, дивіться це посилання [4].

3. Використовуйте Inline Assembly

Inline assembly дозволяє розробникам писати низькорівневий, але ефективний код, який може бути безпосередньо виконаний EVM, не використовуючи дорогі опкоди Solidity. Inline assembly також дозволяє отримати більш точний контроль над використанням пам'яті та сховища, додатково зменшуючи витрати на газ. Крім того, inline assembly може виконувати складні операції, які важко реалізувати лише за допомогою Solidity, пропонуючи більшу гнучкість для оптимізації споживання газу.

Ось приклад використання вбудованої зборки для збереження газу:

Як видно з прикладу вище, другий випадок, який використовує вбудовану збірку, має вищу ефективність газу порівняно зі стандартним випадком.

Однак використання вбудованої збірки також може спричинити ризики та призвести до помилок. Тому використовувати його слід обережно і рекомендується тільки досвідченим розробникам.

4. Використовуйте рішення на рівні 2

Рішення верхнього рівня можуть зменшити обсяг даних, які потрібно зберігати та обчислювати на головній мережі Ethereum.

Рішення другого рівня, такі як rollups, sidechains та state channels, відвантажують обробку транзакцій з основного ланцюжка Ethereum, що дозволяє здійснювати швидкі та дешеві транзакції.

Об'єднавши велику кількість транзакцій разом, ці рішення знижують кількість транзакцій у ланцюжку, що в свою чергу знижує вартість газу. Використання рішень 2-го рівня також покращує масштабованість Ethereum, дозволяючи більшій кількості користувачів та додатків брати участь в мережі без перевантаження.

5. Використовуйте інструменти та бібліотеки оптимізації

Існує кілька інструментів оптимізації, таких як оптимізатор solc, оптимізатор збірки Truffle та компілятор Solidity від Remix.

Ці інструменти можуть допомогти мінімізувати розмір байт-коду, видалити невикористаний код і зменшити кількість операцій, необхідних для виконання смарт-контрактів. У поєднанні з іншими бібліотеками оптимізації газу, такими як "solmate", розробники можуть ефективно знизити витрати на газ і підвищити ефективність смарт-контрактів.

Висновок

Оптимізація витрат газу є важливим кроком для розробників, оскільки вона не тільки зменшує витрати на транзакції, але й покращує ефективність смартконтрактів на мережах, сумісних з EVM. Пріоритет відводиться витратам на операції, зменшенню використання пам'яті, використанню вбудованого збору, а також виконанню інших кращих практик, про які говориться в цій статті, розробники можуть ефективно знизити витрати газу на контрактах.

Однак важливо зауважити, що під час процесу оптимізації розробники повинні виявляти обережність, щоб уникнути введення уразливостей безпеки. Під час оптимізації коду та зменшення споживання газу, вбудована безпека смартконтракту ніколи не повинна бути пожертвована.

[1] https://ethereum.org/uk/developers/docs/gas/
[2] https://ethereum.github.io/yellowpaper/paper.pdf
[3] https://www.evm.codes/
[4] https://www.evm.codes/precompiled

Відмова від відповідальності:

  1. Ця стаття взята з [ PANewslab]. Авторські права належать оригінальному авторові [CertiK]. Якщо у вас є які-небудь зауваження щодо перепублікації, будь ласка, зв'яжіться Gate Learnкоманда, команда якнайшвидше розгляне це відповідно до відповідних процедур.
  2. Відмова від відповідальності: Погляди та думки, висловлені в цій статті, представляють лише особисті погляди автора й не становлять жодної інвестиційної поради.
  3. Інші мовні версії статті перекладені командою вивчення воріт. Якщо не зазначено інше, перекладена стаття не може бути скопійована, розповсюджена або узята за основу.

Топ-10 найкращих практик оптимізації газу в смарт-контрактах Ethereum

Середній1/3/2025, 11:25:57 AM
Ця стаття досліджує проблеми з оплатою газу в основній мережі Ethereum та методи оптимізації. Вона зосереджена на механізмі газу EVM, основних концепціях оптимізації витрат газу та найкращих практиках розробки смартконтрактів. Серед них зменшення обсягу зберігання, упаковка змінних, оптимізація типів даних та використання змінних фіксованого розміру.

Дотримуючись цих практик, розробники можуть зменшити споживання газу в смартконтрактах, знизити витрати на транзакції та створити більш ефективні та зручні додатки.

Комісії за газ на головній мережі Ethereum завжди були основною проблемою, особливо під час періодів перевантаження мережі. Під час піків, користувачам часто доводиться платити надзвичайно високі комісії за транзакції. Тому оптимізація витрат на газ на етапі розробки смарт-контрактів є важливою. Оптимізація газу може не тільки ефективно зменшити витрати на транзакції, але й покращити їх ефективність, надаючи користувачам економічніший та ефективніший досвід використання блокчейну.

Ця стаття розкриє механізм плати за газ в Ethereum Virtual Machine (EVM), основні концепції, пов'язані з оптимізацією плати за газ, та найкращі практики для оптимізації плати за газ при розробці смартконтрактів. Сподіваємося, що цей контент надихне та допоможе розробникам, а також допоможе звичайним користувачам краще розібратися, як працює система плати за газ EVM, спільно вирішуючи проблеми в екосистемі блокчейну.

Огляд механізму витрат на газ EVM

У мережах, сумісних з EVM, «газ» вказує на одиницю, яка використовується для вимірювання обчислювальної потужності, необхідної для виконання певних операцій.

На діаграмі нижче показана структура EVM. На діаграмі споживання газу поділено на три частини: виконання операцій, зовнішні виклики повідомлень та читання/запис в пам'ять та сховище.

Джерело: Офіційний веб-сайт Ethereum[1]

З моменту активації EIP-1559 (London Hard Fork), вартість газу обчислюється за наступною формулою:

Вартість газу = одиниці використаного газу * (базова комісія + пріоритетна комісія)

Базова комісія спалюється, а пріоритетна комісія служить стимулом для заохочення валідаторів включити транзакцію в блокчейн. Встановлення комісії з вищим пріоритетом під час надсилання транзакції збільшує ймовірність включення транзакції до наступного блоку. Це схоже на «чайові», які користувачі платять валідаторам.

1. Розуміння оптимізації газу в EVM

При компіляції розумного контракту з Solidity контракт перетворюється на набір "операційних кодів", або опкодів.

Кожен опкод (такий як створення контракту, здійснення викликів повідомлень, доступ до сховища облікового запису та виконання операцій на віртуальній машині) має пов'язану вартість споживання газу, яка документується в Ethereum Yellow Paper[2].

Після багаторазових модифікацій EIP витрати на газ для деяких кодів операцій були скориговані, які можуть відрізнятися від значень у Жовтій книзі. Для отримання детальної інформації про останню вартість операційних кодів, будь ласка, зверніться до цього джерела[3].

2. Основні концепції оптимізації газу

Основна концепція оптимізації газу полягає в тому, щоб надавати пріоритет вартісним операціям на блокчейні EVM і уникати операцій, які призводять до високих витрат на газ.

У EVM наступні операції є відносно недорогими:

  • [ ] Читання та запис змінних пам'яті
  • [ ] Читання постійних та незмінних змінних
  • [ ] Читання та запис локальних змінних
  • [ ] Читання змінних calldata, таких як масиви calldata та структури
  • [ ] Внутрішні виклики функцій

Високі витрати включають в себе:

  • Читання та запис змінних стану, збережених у сховищі контракту
  • [ ] Зовнішні виклики функцій
  • [ ] Операції з циклом

Найкращі практики оптимізації витрат на газ EVM

На основі вищезазначених основних концепцій ми склали список найкращих практик оптимізації витрат на газ для розробницької спільноти. Дотримуючись цих практик, розробники можуть зменшити споживання газу у смарт-контрактів, знизити витрати на транзакції та створити більш ефективні та зручні для користувачів додатки.

1. Мінімізувати використання сховища

У Solidity зберігання є обмеженим ресурсом, і його споживання газу значно вище, ніж у пам'яті. Кожного разу, коли смарт-контракт зчитує зберігання або записує у нього, він зазнає високих витрат газу.

Згідно з визначенням у Жовтій книзі Ethereum, вартість операцій зберігання вище, ніж пам'яті більше, ніж у 100 разів. Наприклад, опкоди, такі як sload та sstore, коштують принаймні 100 одиниць газу у найкращому випадку, тоді як операції з пам'яттю, такі як mload та mstore, споживають лише 3 одиниці газу.

Способи обмеження використання сховища включають:

  • [ ] Зберігати тимчасові дані в пам'яті
  • [ ] Зменшити кількість змін у сховищі: Зберігаючи проміжні результати в пам'яті і призначаючи кінцевий результат змінним у сховищі лише після завершення всіх обчислень.

2. Упакування змінних

Кількість використаних слотів зберігання в розумних контрактах та спосіб представлення даних розробниками можуть суттєво впливати на споживання газу.

Компілятор Solidity упаковує послідовні змінні зберігання під час процесу компіляції, використовуючи 32-байтові слоти зберігання як основну одиницю для зберігання змінних. Упаковка змінних відноситься до практики розташування змінних таким чином, щоб кілька змінних помістилися в один слот зберігання.

Ліворуч - менш ефективна реалізація, яка використовує 3 слоти зберігання; праворуч - більш ефективна реалізація.

Зробивши це налаштування, розробники можуть зекономити 20 000 одиниць газу (оскільки зберігання не використовуваного слоту зберігання коштує 20 000 газу), але тепер потрібно лише два слоти зберігання.

Оскільки кожен слот зберігання споживає газ, упаковка змінних оптимізує використання газу шляхом зменшення кількості необхідних слотів зберігання.

3. Оптимізація типів даних

Змінну можна представити за допомогою різних типів даних, але витрати на операції варіюються в залежності від типу. Вибір відповідного типу даних допомагає оптимізувати використання газу.

Наприклад, у Solidity цілі числа можуть бути поділені на різні розміри: uint8, uint16, uint32 тощо. Оскільки EVM працює з 256-бітними блоками, використання uint8 означає, що спочатку EVM повинна перетворити його на uint256, і це призводить до додаткових витрат на газ при конвертації.

Ми можемо порівняти витрати газу uint8 та uint256 за допомогою коду на діаграмі. Функція UseUint() споживає 120,382 одиниць газу, тоді як функція UseUInt8() споживає 166,111 одиниць газу.

Сам по собі використання uint256 дешевше, ніж uint8. Однак, якщо ми застосуємо раніше запропоновану оптимізацію упаковування змінних, це робить різницю. Якщо розробники можуть упакувати чотири змінні uint8 в один сховищний слот, загальна вартість ітерації над ними буде нижчою, ніж використання чотирьох змінних uint256. У цьому випадку смарт-контракт може прочитати та записати сховищний слот один раз та завантажити всі чотири змінні uint8 в пам'ять/сховище за одну операцію.

4. Використовуйте змінні фіксованого розміру замість динамічних змінних

Якщо дані можуть бути обмежені до 32 байтів, рекомендується використовувати тип даних bytes32 замість bytes або strings. Загалом, змінні фіксованого розміру споживають менше газу, ніж змінні динамічного розміру. Якщо можлива обмеження довжини байтів, спробуйте вибрати найменшу довжину від bytes1 до bytes32.

5. Відображення проти Масивів

У Solidity списки даних можна представити за допомогою двох типів даних: Масиви та Картографування, кожен з власним синтаксисом та структурою.

У більшості випадків відображення є більш ефективним і економічним, тоді як масиви є ітерабельними і підтримують упаковку типів даних. Тому рекомендується віддавати перевагу використанню відображень при керуванні списками даних, якщо необхідна ітерація або споживання газу може бути оптимізовано за допомогою упаковки типу даних.

6. Використовуйте calldata замість пам'яті

Змінні, оголошені в параметрах функції, можуть бути збережені як у calldata, так і в пам'яті. Основна різниця полягає в тому, що пам'ять може бути змінена функцією, тоді як calldata є незмінним.

Пам'ятайте про цей принцип: якщо параметри функції є тільки для читання, краще використовувати calldata замість пам'яті. Це уникне непотрібних операцій копіювання даних з calldata в пам'ять функції.

Приклад 1: Використання пам'яті

При використанні ключового слова memory значення масиву копіюються з закодованого calldata в пам'ять під час декодування ABI. Вартість виконання цього блоку коду становить 3 694 одиниці газу.

Приклад 2: Використання calldata

При зчитуванні значень безпосередньо з calldata проміжна операція пам'яті пропускається. Ця оптимізація знижує вартість виконання лише до 2 413 газових блоків, що призводить до підвищення ефективності газу на 35%.

7. Використовуйте ключові слова Constant/Immutable, якщо це можливо

Константні / незмінні змінні не зберігаються в сховищі контракту. Ці змінні обчислюються на етапі компіляції та зберігаються в байткоді контракту. Таким чином, вартість доступу до них набагато нижча порівняно зі змінними сховища. Рекомендується використовувати ключові слова Constant або Immutable, якщо це можливо.

8. Використовуйте Unchecked, коли переповнення / недоповнення не є проблемою

Коли розробники можуть бути впевнені, що арифметичні операції не призведуть до переповнення або недостатку, вони можуть використовувати ключове слово безперевірки, введене в Solidity v0.8.0, щоб уникнути непотрібних перевірок переповнення або недостатку, тим самим зекономивши витрати на газ.

На схемі нижче, умовно обмежений i

Крім того, версії компілятора 0.8.0 та вище більше не потребують використання бібліотеки SafeMath, оскільки сам компілятор тепер містить вбудований захист від переповнення та недоповнення.

9. Оптимізуйте модифікатор

Код модифікаторів вбудовується в функції, які вони модифікують. Кожного разу, коли використовується модифікатор, його код дублюється, що збільшує розмір байткоду та збільшує споживання газу. Ось один спосіб оптимізації витрат газу на модифікатори:

Перед оптимізацією:

Після оптимізації:

У цьому прикладі, рефакторінгом логіки внутрішньої функції _checkOwner(), яка може бути використана в модифікаторі, розмір байткоду зменшується, а витрати на газ знижуються.

10. Оптимізація короткого замикання

Для операторів || (OR) та && (AND), логічні операції оцінюються зі скороченням, що означає, що якщо перша умова достатня для визначення результату логічного виразу, друга умова не буде оцінена.

Для оптимізації споживання газу, умови з меншими витратами обчислень слід розміщувати спочатку, щоб потенційно дорогі обчислення можна було пропустити.

Загальні рекомендації

1. Видаліть невикористаний код

Якщо у контракті є невикористані функції або змінні, рекомендується їх видалити. Це найпряміший спосіб зменшити витрати на розгортання контракту та зберегти його розмір малим.

Ось кілька практичних рекомендацій:

Використовуйте найбільш ефективні алгоритми для обчислень. Якщо контракт безпосередньо використовує певні результати обчислень, зайві обчислення слід видалити. Практично будь-які невикористані обчислення слід видаляти. У Ethereum розробники можуть отримувати газові винагороди, випускаючи простір для зберігання. Якщо змінна більше не потрібна, її слід видалити за допомогою ключового слова delete або встановити значення за замовчуванням.

Оптимізація циклу: Уникайте операцій з високою вартістю циклу, спробуйте об'єднати цикли та виносити повторні обчислення з тіла циклу.

2. Використовуйте попередньо скомпільовані контракти

Попередньо скомпільовані контракти надають складні бібліотечні функції, такі як криптографія та хеш-операції. Оскільки код не виконується на EVM, а працює локально на вузлі клієнта, потрібно менше газу. Використання попередньо скомпільованих контрактів може заощадити газ, зменшивши обчислювальне навантаження, необхідне для виконання смартконтракту.

Приклади попередньо скомпільованих контрактів включають алгоритм цифрового підпису на еліптичних кривих (ECDSA) та хеш-функцію SHA2-256. Використовуючи ці попередньо скомпільовані контракти в смарт-контрактах, розробники можуть знизити витрати на газ та покращити ефективність застосунку.

Для повного списку попередньо скомпільованих контрактів, які підтримує мережа Ethereum, дивіться це посилання [4].

3. Використовуйте Inline Assembly

Inline assembly дозволяє розробникам писати низькорівневий, але ефективний код, який може бути безпосередньо виконаний EVM, не використовуючи дорогі опкоди Solidity. Inline assembly також дозволяє отримати більш точний контроль над використанням пам'яті та сховища, додатково зменшуючи витрати на газ. Крім того, inline assembly може виконувати складні операції, які важко реалізувати лише за допомогою Solidity, пропонуючи більшу гнучкість для оптимізації споживання газу.

Ось приклад використання вбудованої зборки для збереження газу:

Як видно з прикладу вище, другий випадок, який використовує вбудовану збірку, має вищу ефективність газу порівняно зі стандартним випадком.

Однак використання вбудованої збірки також може спричинити ризики та призвести до помилок. Тому використовувати його слід обережно і рекомендується тільки досвідченим розробникам.

4. Використовуйте рішення на рівні 2

Рішення верхнього рівня можуть зменшити обсяг даних, які потрібно зберігати та обчислювати на головній мережі Ethereum.

Рішення другого рівня, такі як rollups, sidechains та state channels, відвантажують обробку транзакцій з основного ланцюжка Ethereum, що дозволяє здійснювати швидкі та дешеві транзакції.

Об'єднавши велику кількість транзакцій разом, ці рішення знижують кількість транзакцій у ланцюжку, що в свою чергу знижує вартість газу. Використання рішень 2-го рівня також покращує масштабованість Ethereum, дозволяючи більшій кількості користувачів та додатків брати участь в мережі без перевантаження.

5. Використовуйте інструменти та бібліотеки оптимізації

Існує кілька інструментів оптимізації, таких як оптимізатор solc, оптимізатор збірки Truffle та компілятор Solidity від Remix.

Ці інструменти можуть допомогти мінімізувати розмір байт-коду, видалити невикористаний код і зменшити кількість операцій, необхідних для виконання смарт-контрактів. У поєднанні з іншими бібліотеками оптимізації газу, такими як "solmate", розробники можуть ефективно знизити витрати на газ і підвищити ефективність смарт-контрактів.

Висновок

Оптимізація витрат газу є важливим кроком для розробників, оскільки вона не тільки зменшує витрати на транзакції, але й покращує ефективність смартконтрактів на мережах, сумісних з EVM. Пріоритет відводиться витратам на операції, зменшенню використання пам'яті, використанню вбудованого збору, а також виконанню інших кращих практик, про які говориться в цій статті, розробники можуть ефективно знизити витрати газу на контрактах.

Однак важливо зауважити, що під час процесу оптимізації розробники повинні виявляти обережність, щоб уникнути введення уразливостей безпеки. Під час оптимізації коду та зменшення споживання газу, вбудована безпека смартконтракту ніколи не повинна бути пожертвована.

[1] https://ethereum.org/uk/developers/docs/gas/
[2] https://ethereum.github.io/yellowpaper/paper.pdf
[3] https://www.evm.codes/
[4] https://www.evm.codes/precompiled

Відмова від відповідальності:

  1. Ця стаття взята з [ PANewslab]. Авторські права належать оригінальному авторові [CertiK]. Якщо у вас є які-небудь зауваження щодо перепублікації, будь ласка, зв'яжіться Gate Learnкоманда, команда якнайшвидше розгляне це відповідно до відповідних процедур.
  2. Відмова від відповідальності: Погляди та думки, висловлені в цій статті, представляють лише особисті погляди автора й не становлять жодної інвестиційної поради.
  3. Інші мовні версії статті перекладені командою вивчення воріт. Якщо не зазначено інше, перекладена стаття не може бути скопійована, розповсюджена або узята за основу.
今すぐ始める
登録して、
$100
のボーナスを獲得しよう!