У меня есть простой контракт, который удаляет последний элемент массива:
pragma solidity^0.4.11;
contract GasRefundTest {
uint[] myArray = [1, 2];
function deleteLastElem() public returns(bytes32) {
myArray.length--;
}
}
Стоимость транзакции для вызова deleteLastElem()
составляет 17182 газа.
Когда я меняю его на:
pragma solidity^0.4.11;
contract GasRefundTest {
uint[] myArray = [1, 2];
function deleteLastElem() public returns(bytes32) {
delete myArray[1];
myArray.length--;
}
}
стоимость сделки становится 22480 газа.
Я думал, что удаление слотов для хранения должно привести к возврату газа, вместо этого я вижу увеличение количества газа.
Кто-нибудь может объяснить, что здесь происходит.
Уменьшение размера массива динамического размера уже обнуляет элементы, которые были «удалены».
Таким образом, версия вашего кода, которая сначала выполняет a delete myArray[1]
, просто выполняет дополнительную запись в хранилище, которая в любом случае будет выполнена.
Интересные вещи, которые стоит попробовать:
// This doesn't take more gas depending on how big you make the array.
myArray.length = 3; // or 300 or 3000
myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
...
// This takes more gas the more elements you're removing, because it has to zero
// out more positions in storage.
myArray.length = 9; // vs. 1
РЕДАКТИРОВАТЬ
Я должен отметить, что этот последний пример немного сбивает с толку. Компенсация за газ есть , но она ограничена половиной потребленного газа.
myArray.length
и вместо этого оставить свою собственную переменную, указывающую, сколько элементов допустимо. Затем вы можете реализовать любую логику, которую хотите, когда обнуляете вещи.Чтобы объяснить на высоком уровне, вы выполняете 2 операции вместо 1, поэтому требуется больше газа. Весь код, который вы пишете, компилируется в низкоуровневые команды виртуальной машины Ethereum (EVM), которые затем интерпретируются ею. Для каждой такой команды определена определенная цена газа, посмотрите на это .
Теперь, во втором случае, вы используете delete
. Из документов ,
delete a присваивает начальное значение типа a
Важно отметить, что удаление a действительно ведет себя как присваивание a, т. е. оно сохраняет новый объект в a.
Таким образом, вы ставите его 0
первым, прежде чем уменьшать длину массива. Чисто ради интереса можно попробовать использовать myArray[1] = 0;
вместо него и посмотреть, как это повлияет на используемый газ.
foo = 6; foo = 0;
это «2 операции вместо 1», но потребляет меньше газа, чем просто foo = 6;
)myArray.length--
побочный эффект первого выполнения . ничего вам не даст.
delete myArray[myArray.length - 1];
delete
foo = 6; foo = 0;
Извините, в своем примере
я предполагал , что foo
это еще не0
так .foo = 6
. Моя точка зрения заключалась в том, что «2 операции дороже, чем 1» не соответствует действительности из-за возмещения расходов на газ. Возможно, более наглядным примером будет foo = 6; bar = 0;
потребление меньшего количества газа, чем просто foo = 6
(опять же, где bar
раньше было ненулевое значение).gas_consumed = max(21000, gas_consumed - min(gas_consumed / 2, gas_refund))
.x = 5; x = 0;
в цикле будет стоить 20 000 (стоимость записи ненулевого значения там, где ранее был ноль) + 5000 (стоимость записи нуля) газа и добавит 15 000 к возврату газа. При этом не было бы никакой выгоды.delete
больше не будет обязательно устанавливать позицию в 0, а в любое начальное значение.
Роман Фролов
Медведев1088