Возможно, вы встречали несколько советов по 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, смарт-контрактах аудита и многом другом.
__________________