Struct

解除安裝。使用結構 - 載入字節

  • March 30, 2022

我正在嘗試從程序集中的結構中載入各種字節。我在這裡找到了 uint的一個很好的解釋。雖然這適用於 uint 和整個記憶體插槽,但我無法弄清楚如何從結構中獲取 bytes1 或 bytes12 變數。

contract Storage {

mapping(uint256 => turmite) public turmites;

struct turmite {
   bytes1 state;
   bytes12 baserule;
}

bytes1 state = hex"02";
constructor(){
   turmites[1] = turmite(
   state,
   0xff0801ff0201ff0000000001
   );
}

function retrieve(uint id) public{
   turmite storage data = turmites[id];
   bytes12 b;
   bytes1 a;
   bytes32 completeslot;
   assembly {
       let w := sload(data.slot)
       completeslot := w
       a := and(w, 0xff)
}   
}
}

字節和字元串左對齊,而數字(uintX)右對齊。

  • 字節32(字節1(0xFF))-> 0xFF0…00
  • uint256(uint8(0xFF)) -> 0x00…0FF

導致這種行為:

function test() public view returns (bytes1) {
   uint256 value = 0xFF00000000000000000000000000000000000000000000000000000000000000;
   bytes1 rvalue;

   assembly {
       rvalue := value
   }

   return rvalue; // 0xFF
}

SLOAD 返回一個 uint256,當嘗試將此值放入 bytes1 時,您實際上得到的是 uint 的第 32 個字節(在整個答案中,字節 32 位於最左側,字節 0 位於最右側),而不是第一個。使用 bytes12,您將獲得 32 到 20 的範圍,而不是 12 到 0 的範圍。

這正是發生的情況:

// clears bytes 32 to 1 and puts byte 32 into a
// because a is byte1 : left aligned
a := and(w, 0xff)

您可以直接在 int 上工作,並且只能在返回裝配塊之前進行轉換,如下所示:

function retrieve(uint id) public view returns (bytes1, bytes12) {
       turmite storage data = turmites[id];
       uint96 b;
       uint8 a;

       assembly {
               let w := sload(data.slot)
               a := w
               b := shr(8, w)
       }

       return (bytes1(a), bytes12(b));   
}

或者堅持使用 bytesX 並將您的值向左移動,因為這是它們將被拾取的地方:

 function retrieve(uint id) public view returns (bytes1, bytes12) {
       turmite storage data = turmites[id];
       bytes12 b;
       bytes1 a;

       assembly {
               let w := sload(data.slot)

               // Shift 152 bits (19 bytes) left to bring data.baserule at byte 32
               b := shl(152, w)

               // shift 248 bits (31 bytes) left to bring data.state at byte 32
               a := shl(248, w)
       }

       return (a, b);  
   }

引用自:https://ethereum.stackexchange.com/questions/124892