NOTA: Esta respuesta incluye solo datos experimentales
Lea la respuesta de @ medvedev1088 antes, porque mi respuesta es solo la adición y algunos datos de las pruebas.
De mis pruebas en remix obtuve estos datos:
true
- bool
struct
cuesta 58211 gas; 20k + 7 * 5k = 55k gasolina;true
- bool
struct
cuesta 100807 gas; 20k + 15 * 5k = 95k gasolina;true
- bool
struct
cuesta 186505 gas; 20k + 31 * 5k = 175k gasolina;true
- bool
struct
cuesta 206811 gas; 2 * 20k + 31 * 5k = 195k gasolina;A partir de estos datos, está claro que la cantidad máxima de booleanos que puede almacenar en una ranura es 32 .
[Actualización 1]
Es posible que haya notado discrepancias en los números de esas líneas. Esos desajustes en realidad son causados por algunas tarifas más pequeñas pagadas por diferentes códigos de operación (que se ejecutan para cada nuevo bool en nuestro struct
). Permítanme enumerar los más costosos:
SLOAD
cuesta 200 gasolinaEXP
cuesta 60 gasolinaEjecuté la transacción en rinkeby. Eche un vistazo a GETH Trace para TxHash .
memory ex
.SLOAD
cuesta 200 de gasolina + EXP
= 60 de gasolina + un montón de pequeñas tarifas para otros códigos de operación. Actualizaré la respuesta más tarde.Probé este contrato simple:
pragma solidity 0.4.20;
contract Test {
struct Example {
bool v1;
bool v2;
bool v3;
bool v4;
bool v5;
bool v6;
bool v7;
bool v8;
}
Example example;
function test() public {
Example memory ex = Example({
v1: true,
v2: true,
v3: true,
v4: true,
v5: true,
v6: true,
v7: true,
v8: true
});
example = ex;
}
}
En el ensamblaje generado hay 8 SSTORE
operaciones y todas apuntan a la misma ranura de almacenamiento. El gas para test()
es ~76k que es 21k + 20k + 5k * 7
. Esto confirma que el bytecode generado primero escribe en la ranura y luego lo actualiza 7 veces.
Agregar más bools a la estructura agrega 5k de gas a test()
. Como señaló @Roman Frolov en su respuesta, hasta 32 bools pueden caber en una sola ranura.
Tenga en cuenta que un bool es un uint8 debajo del capó, esto significa que está usando 8 bits mientras que solo necesita 1 bit.
Es más eficiente empaquetar varios valores booleanos en un uint256 y extraerlos con una máscara. Puede almacenar 256 valores booleanos en un solo uint256 (en una estructura, puede ajustar el tamaño del uint para que coincida con lo que necesita).
Puedes usar el siguiente patrón
function getBoolean(uint256 _packedBools, uint256 _boolNumber)
public view returns(bool)
{
uint256 flag = (_packedBools >> _boolNumber) & uint256(1);
return (flag == 1 ? true : false);
}
function setBoolean(
uint256 _packedBools,
uint256 _boolNumber,
bool _value
) public returns(uint256) {
if (_value)
_packedBools = _packedBools | uint256(1) << _boolNumber;
return _packedBools;
else
_packedBools = _packedBools & ~(uint256(1) << _boolNumber);
return _packedBools;
}
Los resultados son diferentes en Solidity 0.6 y en ejecución en EVM posterior a Estambul (Estambul incluyó la actualización de la lógica de consumo de gas para las operaciones de almacenamiento). Usando el mismo contrato de muestra que medvedev1088 sugerido en una respuesta anterior .
el consumo de gas es mucho menor: 21512 gas para configurar 8 bools.
Jitendra Kumar. Balla