Solidity

使用 Assembly 訪問狀態變數

  • March 18, 2022

我用彙編做了一些實驗,不幸的是,沒有太多的文件,其中大多數都涵蓋了相同的主題(數學運算、extcodesize 等)。在這裡,我試圖讀取我的狀態變數,當我只有一個變數時它可以工作,但似乎不再是多個變數的情況了。

指針似乎指向錯誤的地方,所以我測試了不同的方法

pragma solidity ^0.8.0;

contract Assembly {
 
   bool private var1 = true;
   bool private var2 = false;
   uint8 private var3 = 8;


   function getThirdVariable() public view returns(uint8 res, uint8 res2, uint8 res3, uint8 res4) {
       assembly {
           res := var3.slot
           res2 := var3.offset
           res3 := sload(var3.slot)
           res4 := sload(var3.offset)
       }
   }
}

這是我的函式的返回:

uint8: res 0
uint8: res2 2
uint8: res3 1
uint8: res4 0

任何幫助將不勝感激

這是因為狀態變數在可能的情況下被打包在儲存槽中。

您的變數在 storage 中具有以下大小:

boolean : 1 byte
uint8   : 1 byte 

假設一個儲存槽是 32 字節,它們三個都可以放入第一個槽 (0)。

您可以使用此功能進行檢查:

function getSlots() public view returns (uint256, uint256, uint256) {
 uint256 slotVar1;
 uint256 slotVar2;
 uint256 slotVar3;

 assembly {
   slotVar1 := var1.slot
   slotVar2 := var2.slot
   slotVar3 := var3.slot
 }

 return (slotVar1, slotVar2, slotVar3); // 0, 0, 0
}

現在,因為它們被打包在同一個插槽中,所以它們不能具有相同的偏移量:

function getOffsets() public view returns (uint256, uint256, uint256) {
 uint256 offsetVar1;
 uint256 offsetVar2;
 uint256 offsetVar3;

 assembly {
   offsetVar1 := var1.offset
   offsetVar2 := var2.offset
   offsetVar3 := var3.offset
 }

 return (offsetVar1, offsetVar2, offsetVar3); // 0, 1, 2
}

值槽 0 本身反映了這一點:

0x0000000000000000000000000000000000000000000000000000000000000080001

其中字節 0:0x01 是 var 1(布爾真),字節 1:0x00 是 var 2(布爾假),字節 2:0x08 是 var 3(uint8 8)。

要獲取第三個變數,您需要從var3.slot偏移量開始的儲存槽中的 1 個字節var3.offset

function getThirdVariable() public view returns(uint8) {
 uint8 value;

 assembly {
   let tmp := sload(var3.slot)           // get the value at var3.slot
   tmp := shr(mul(var3.offset, 8), tmp)  // shift that value by var3.offset * 8 bits to the right
   value := tmp                          // store the result for return
 }

 return value; // 8
}

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