如何獲取字元串> 31長度的數據位置
文件說:
字節和字元串編碼相同。對於儲存 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 個字節,並使用彙編讀取函式。只有前兩個插槽被填充,第三個插槽為空。
希望能幫助到你!