Solidity

如何獲取字元串> 31長度的數據位置

  • August 17, 2020

文件說:

字節和字元串編碼相同。對於儲存 32 個或更多字節長的數據的字節數組,主槽儲存長度 * 2 + 1,並且數據照常儲存在 keccak256(slot) 中。

我正在使用一個字元串(> 31 個字節),一個儲存中的狀態變數,並試圖獲取數據的位置。我將插槽號(轉換為字節變數)傳遞給 keccak256。它返回一個字節32。我如何使用它來找出數據的儲存位置?

如果重要的話,我會從此程式碼中獲取 bytes32 值。

bytes32 data_slot = keccak256 (uint_to_bytes (slot_number));

函式是這樣定義的。

function uint_to_bytes (uint value) internal pure returns (bytes memory)
{
   uint byte_count = value <= 255 ? 1 : 2;
   bytes memory slot_contents = new bytes (byte_count);

   uint content_index = 0;
   bool value_started = false;
   for (int16 b = 31; b >= 0; b--)
   {
       uint a = uint (b);
       uint shift = a * 8;
       uint anded_value = (0xff << shift) & value;
       uint8 this_byte = uint8 (anded_value >> shift);

       if (this_byte > 0)
           value_started = true;

       if (value_started)
           slot_contents [content_index++] = byte (this_byte);
   }

   return slot_contents;
}

就我而言,基本插槽號是 5,其中包含我的字元串的長度。該插槽中的長度是正確的。

但是當 keccak256 返回一個 bytes32 時,我如何獲取數據的位置。當我將 bytes32 轉換為 uint256 時,我得到 99383055861825221844433915613614375939768875017829574557572350922731547121557。當然這不可能是數據所在的插槽號。

Solidity 中的儲存是 bytes32 到 bytes32 的映射,底層的插槽由 bytes32 表示。我沒有完全理解您提供的程式碼,但這是我的兩分錢。

當您聲明byte[]契約入庫時,它已被打包。這意味著針對該數組中的一個索引的數據將佔用一個字節,而不是像簡單數組那樣佔用 32 個字節的完整插槽。對於不涉及打包的普通數組,索引 0 和 1 處的數據可以位於keccak256(slot number)andkeccak256(slot number) + 1但對於字節數組(或任何打包數組,例如uint8[]),情況並非如此,因為keccak256(slot number)它將返回數組的前 32 個索引處的數據包裝。

一個例子:

pragma solidity 0.5.0;

contract TestStorage {
   byte[] b;

   constructor () public {
       uint8 i;
       for (i = 1 ; i <= 32; i++) {
           b.push(byte(i));
       }
   
       for (i = 1 ; i <= 32; i++) {
           b.push(byte(i));
       }
   }

   function readFromStorage() public view returns(bytes32 slot1, bytes32 slot2, bytes32 slot3) {
       bytes memory slot = new bytes(32);
       assembly {
           mstore(
               add(slot, 32),
               b_slot
           )
       
           let slotHash := keccak256(add(slot, 32), 32)
           slot1 := sload(
               add(
                   slotHash,
                   0
               )
           )
       
           slot2 := sload(
               add(
                   slotHash,
                   1
               )
           )
       
           slot3 := sload(
               add(
                   slotHash,
                   2
               )
           )
       
       }

   }
}

在建構子中,我們使用相同的內容填充前 32 個字節和第二個 32 個字節,並使用彙編讀取函式。只有前兩個插槽被填充,第三個插槽為空。

在此處輸入圖像描述

希望能幫助到你!

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