Docs: storage layout for array of arrays

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