Hello, everyone.
I’m reading the storage layout docs and I’m puzzled by one of the closed formulas provided for the concrete example of an array uint24[][] x
.
The docs say that the storage slot of element x[i][j]
is keccak256(keccak256(p) + i) + floor(j / 10)
where p
is the slot where x
is stored (I’ve also substituted floor(256 / 24)
with 10
). So far so good, it all checks out.
However, they then say that, to recover the element from the slot data v
you have to compute (v >> ((j % 10) * 24)) & type(uint24).max
. Now, I agree that you have to right-shift v
and then AND it with the uint24
bitmask. But the shift quantity looks wrong to me: (24 * j%10)
is the amount of bits to the left of the element. Shouldn’t we instead shift by 256 - (24 * (j%10 + 1))
, which is the amount of bits sitting at the right of the element?
Thanks to all for the help!
Cheers
Shifting right by 24 * (j % 10)
and then taking the least significant 24 bits via the uint24-mask, means that the data in the array is represented in Little-Endian format.
Shifting right by 256 - 24 * (j % 10 + 1)
and then taking the least significant 24 bits via the uint24-mask, means that the data in the array is represented in Big-Endian format.
An example of how the value 0x12345678 is stored at address 100 in memory, might help illustrating the difference between these two forms of data-representation:
+---------+---------------+------------+
| Address | Little Endian | Big Endian |
+---------+---------------+------------+
| 100 | 0x78 | 0x12 |
| 101 | 0x56 | 0x34 |
| 102 | 0x34 | 0x56 |
| 103 | 0x12 | 0x78 |
+---------+---------------+------------+
Hi, thanks for the answer!
I think I figured this out. So, Solidity actually does store integers in little-endian, but that detail is abstracted away (much like C does): in other words, >>
shifts towards the least significant bits (not necessarily right-wards then), so it translates to a left-shift opcode. Thus, when we do v >> something
we are actually shifting left, in storage, and that’s why the closed formula is correct.
Does that make sense?
That’s indeed the definition of >>
, aka shift right.
That’s obviously just a matter of the terminology used, which is designated for describing the nature of the operation in a more verbose (human-readable) manner.
It’s not like those bit are physically sitting somewhere, then moved to somewhere on the right hand side of their original location.
What I meant to emphasize is, that the data in the array is ultimately stored in Little Endian order, meaning that the value stored in cell N represents data which is “least significant” compared with the value stored in cell N+1.
For example, when storing the data 0x12345678
in a byte-array:
- The value stored in cell 0 is
0x78
- The value stored in cell 1 is
0x56
- The value stored in cell 2 is
0x34
- The value stored in cell 3 is
0x12