Возможно, вы встречали несколько советов по Solidity, которые помогут улучшить ваши навыки программирования и сэкономить немного газа, но сегодня я хочу больше сосредоточиться на том, как понимание виртуальной машины Ethereum может эффективно сэкономить вам затраты на газ для ваших смарт-контрактов.

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



Совет № 1: Холодный доступ против теплого доступа

Gcoldsload: 2100 газ

Gwarmaccess: 100 газа

Вот у нас есть первые ОПКОДЫ: первый указывает, сколько стоит доступ к переменной в первый раз (или холодный доступ), а второй указывает, сколько стоит доступ к переменной во второй раз и далее (теплый доступ). ). Как вы можете видеть, разница в цене довольно велика, поэтому понимание этого может существенно повлиять на стоимость транзакций вашего смарт-контракта. Давайте посмотрим пример.





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

Совет № 2: Нулевые и ненулевые значения и возврат газа

Gsset = 20 000 газа

Rsclear = {скидка на цену исполнения}

Изменение значения с 0 на ненулевое в блокчейне Ethereum обходится дорого, как мы видим в цене Gsset, но изменение значения с ненулевого на 0 может дать вам возмещение в виде газа в соответствии с кодом операции Rsclear. Чтобы не воспользоваться возвратом средств, установлено, что вы можете получить возврат только в размере не более 20 % от общей стоимости транзакции.

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





  • В первом примере контракта ZeroToNonZero, от ненулевого до ненулевого (5 000 газа*) + от нуля до ненулевого (20 000 газа) = 25 000 газа.

  • Во втором примере контракта NonZeroToZero: от нуля до нуля (5000 газа*) + от нуля до ненулевого значения (20 000 газа) — возврат (4800 газа) = 21 200 газа.

*2100 (Gcolssload) + 2900 (Gsreset) = 5000 газа

Совет №3: Порядок переменных состояния имеет значение

Хранилище похоже на структуру данных «ключ-значение», в которой хранятся значения переменных состояния смарт-контракта Solidity.

Вы можете представить хранилище как массив, который поможет визуализировать это. Каждое пространство в этом «массиве» хранилища называется слотом и содержит 32 байта (256 бит) данных, и каждая переменная состояния, объявленная в смарт-контракте, будет занимать слот в зависимости от позиции ее объявления и ее типа.

Не все типы данных занимают все 32 байта каждого слота, поскольку некоторые типы данных (bool, uint8, адрес…) занимают меньше этого размера.

Хитрость здесь в том, что если две/три или более переменных вместе занимают 32 байта или меньше, компилятор Solidity попытается упаковать их вместе в один слот, но эти переменные должны быть определены рядом друг с другом.





Здесь мы используем типы данных bool (1 байт), адрес (20 байт) и uint256 (32 байта). Итак, зная размер этих переменных, вы можете легко понять, что в первом примере контракта TwoSlots, поскольку у нас есть bool и адрес вместе (1 + 20 = 21 байт, что меньше 32 байтов), они будут занимать один слот. В контракте ThreeSlots, поскольку bool и uint256 не могут находиться в одном слоте (1 + 32 = 33 байта, что больше емкости слота), всего мы будем использовать три слота.

Почему это так важно?

Код операции SLOAD стоит 2100 газа и используется для чтения из слотов хранилища, поэтому, если вы сможете хранить переменные в меньшем количестве слотов, вы в конечном итоге сэкономите некоторое количество газа.

Совет №4: uint256 дешевле, чем uint8

Из совета №3 мы узнали, что uint256 (256 бит = 32 байта) сам по себе занимает слот, а также мы узнали, что uint8 меньше 32 байтов. Итак, хотя очевидно, что 8 бит меньше, чем 256 бит, почему uint256 дешевле?

Чтобы понять это, важно знать, что если переменная не заполняет собой весь слот и если этот слот не заполнен какой-либо другой переменной, EVM заполнит остальные оставшиеся биты «0». чтобы иметь возможность манипулировать им.

Это добавление «0», выполняемое EVM, будет стоить газа, а это означает, что для экономии газа транзакций лучше использовать uint256 вместо uint8.

__________________

Надеемся, что, узнав об этих советах по снижению затрат на газ в ваших смарт-контрактах, вы также узнали немного о том, как работает EVM.

__________________

В Твиттере @TheBlockChainer вы найдете больше ежедневных обновлений о смарт-контрактах, безопасности Web3, Solidity, смарт-контрактах аудита и многом другом.

__________________