Tengo un contrato simple que elimina el último elemento de la matriz:
pragma solidity^0.4.11;
contract GasRefundTest {
uint[] myArray = [1, 2];
function deleteLastElem() public returns(bytes32) {
myArray.length--;
}
}
El costo de transacción para llamar deleteLastElem()
es 17182 gas.
Cuando lo cambio a:
pragma solidity^0.4.11;
contract GasRefundTest {
uint[] myArray = [1, 2];
function deleteLastElem() public returns(bytes32) {
delete myArray[1];
myArray.length--;
}
}
el costo de transacción se convierte en 22480 gas.
Pensé que eliminar las ranuras de almacenamiento debería dar como resultado un reembolso de gasolina, en cambio, veo un aumento de gasolina.
¿Alguien puede explicar qué está pasando aquí?
Reducir el tamaño de una matriz de tamaño dinámico ya pone a cero los elementos que se "eliminaron".
Entonces, la versión de su código que primero hace a delete myArray[1]
solo está haciendo una escritura adicional en el almacenamiento que está a punto de realizarse de todos modos.
Cosas divertidas para probar:
// 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
EDITAR
Debo señalar que este último ejemplo es un poco confuso. El reembolso del gas entra en vigor allí, pero está limitado a la mitad del gas consumido.
myArray.length
y, en su lugar, mantener su propia variable que indique cuántos elementos son válidos. Luego, podría implementar la lógica que desee sobre cuándo poner a cero las cosas.Para explicar en el nivel alto, está haciendo 2 operaciones en lugar de 1, por lo tanto, requiere más gas. Todo el código que escribe se compila en comandos de Ethereum Virtual Machine (EVM) de bajo nivel, que luego son interpretados por ella. Para cada comando de este tipo hay un precio de gas particular definido, mire esto .
Ahora, en el segundo caso, usas delete
. De los documentos ,
delete a asigna el valor inicial del tipo a un
Es importante tener en cuenta que eliminar a realmente se comporta como una asignación a a, es decir, almacena un nuevo objeto en a.
Por lo tanto, está poniendo 0
allí primero, antes de disminuir la longitud de una matriz. Simplemente por interés, puede intentar usar en su myArray[1] = 0;
lugar y ver cómo esto afecta el gas utilizado.
foo = 6; foo = 0;
es "2 operaciones en lugar de 1" pero consume menos gas que solo foo = 6;
)myArray.length--
" delete myArray[myArray.length - 1];
. delete
no te gana nada.foo = 6; foo = 0;
ejemplo que nofoo
lo estaba ya .
0
foo = 6
. Mi punto era simplemente que "2 operaciones son más caras que 1" no es exacto debido a los reembolsos de gasolina. Quizás un ejemplo más claro sería foo = 6; bar = 0;
consumir menos gas que solo foo = 6
(de nuevo, donde bar
antes era distinto de cero).gas_consumed = max(21000, gas_consumed - min(gas_consumed / 2, gas_refund))
.x = 5; x = 0;
un bucle costaría 20000 (costo de escribir un valor distinto de cero donde antes había un cero) + 5000 (costo de escribir un cero) en gasolina y agregaría 15000 al reembolso de gasolina. No se obtendría ninguna ganancia haciendo eso.delete
ya no establecería la posición en 0 necesariamente, sino en el valor inicial.
Román Frólov
medvedev1088