I have a struct with the following variables:
struct contract {
address customer;
uint8 tokentype; // 5 token types
uint8 size; // 5 sizes
bool gender; // 2 types
bool active; // 2 types
}
I'm not a computer scientist, but I think bools are 2 bits, and when I have 5 cases, I suppose that's 5 bits.
To save on gas and memory, I could store them as a uint instead of separate variables, so that each digit slot would reflect one item: {tokentype, size, gender, active} –> {digit4, digit3, digit2, digit1}. Thus 4411, would be the largest possible number for my set of cases, while 0 the smallest. I would then access them via pulling out some particular contract "con", so that I could apply logic on the cases using
for size, it's digit 3, and thus
con.digit3 / 1e3 % 10 = case of digit 3
which I could use in my contract via the generalized function, for various x and j:
if ((con.digitx / 1ex) % 10 == j)
I would replace values the following way. For example, if the existing value of digit3 is not 4, and I wanted it to be 4, I would apply the function
con.digit4 = con.digit4 + 4e3 - ((con.digit4 / 1e3) % 10) * 1e4;
In the context of Solidity's gas considerations, is there a more efficient way? I figure there is using a shift operation.
Best Answer
In Solidity a
bool
is stored in 1 byte (8 bits). However, only a single bit is actually used. Under the hood, The hex value oftrue
is0x01
,false
is0x00
. Converted to binary these are00000001
and00000000
- 7 of the 8 bits are not used.All reads and writes to storage are handled in 32 byte increments. To reduce gas costs, Solidity tightly packs variables where possible so that they are stored within the same 32 bytes. In the case of your struct you have an
address
(20 bytes) followed by 2uint8
s (1 byte each) and 2bool
s (1 byte each). This is a total of 24 bytes, so Solidity is able to pack the entire struct into a single 32 byte slot. There is no need to optimize further on your end.The concept you are considering (packing more than one
bool
within a single byte) is known as a bit field. Bit fields are more efficient in cases where you wish to store a sequence of greater than 32 booleans. Mudit Gupta has written an excellent blog post that explains how to accomplish this via bitshifting: