Solidity参数
动态数据类型存储
Arrays数据存储
定长数组
- 定长数组作为固定大小的参数
- 数据存储按照静态类型依次
slot
存储 - 定长数组不和其他参数共享
slot
// SPDX-License-Identifier: MIT
pragma solidity =0.8.26;
contract MyFixedUint256Array {
uint256 num; // storage slot 0
uint64[3] myArr = [
4, // storage slot 1
9, // storage slot 1
2 // storage slot 1
];
uint64 next = 5; //storage slot 2
uint128[3] bigArr = [
4, // storage slot 3
9, // storage slot 3
2 // storage slot 4
];
uint64 bnext = 5; //storage slot 5
function getValue(uint256 index) public view returns (uint256 value) {
// CALL HELPER FUNCTION TO GET SLOT
assembly {
// Loads the value stored in the slot
value := sload(index)
}
}
}
不定长数组–arrays[]
- 不定长数据在合约编译时无法确认数据
size
,所以在baseSlot
存储当前参数的size
- 不定长数组具体数据的起始位置和
baseSlot
相关:keccak256(baseSlot)
- 不定长数组的数据依次从起始位置开始入栈存储
- 不定长数组的数据按照数值类型补位存储,
slot
进行高位补足存储数组参数 - 数值长度超出
256bit
后,顺延至下一个slot
存储(index += 1)
// SPDX-License-Identifier: MIT
pragma solidity =0.8.26;
contract MyDynArray {
uint256 private someNumber; // storage slot 0
address private someAddress; // storage slot 1
uint32[] private myDynamicArr = [3, 4, 5, 9, 7]; // storage slot 2
function getSlot(uint256 _index) public pure returns (uint256 slot) {
uint256 baseSlot;
assembly {
// `.slot` returns the state variable (balance) location within the storage slots.
// In our case, balance.slot = 6
baseSlot := myDynamicArr.slot
}
slot = uint256(keccak256(abi.encode(baseSlot))) + _index;
}
function getSlotValue(uint256 slot) public view returns (bytes32 value) {
assembly {
value := sload(slot)
}
}
}
- 数据类型变成
uint64[] private myDynamicArr = [3, 4, 5, 9, 7]; // storage slot 2
:- 一个
slot
最多存储4
个数组参数 - 因此,起始位置
index=0
的slot
能够存储3,4,5,9
四个参数 - 剩余参数顺眼至下一个
slot
- 因此,起始位置
index=1
的slot
存储7
- 一个
多维不定长数组
- array[][]…
uint64[][] private nestedDynamicArray = [[2, 9, 6, 3, 2], [7, 4, 8, 10, 2]];
baseSlot
存储当前数组大小,示例大小为2
- 进一步确认内部嵌套的数组大小,存储内部数组大小的
slot_array_size
和 数组index
相关:slot_array_size = keccak256(baseSlot)+ index
- 嵌套数组内部的数据
slot_array_data_loc
和slot_array_size
以及内部internal_index
相关:slot_array_data_loc = keccak256(slot_array_size)+ internal_index
- 嵌套数组内部的数据存储按照单维存储规则
// SPDX-License-Identifier: MIT
pragma solidity =0.8.26;
contract MyNestedArray {
uint256 private someNumber; // storage slot 0
// Initialize nested array
uint64[][] private nestedDynamicArray = [[2, 9, 6, 3, 2], [7, 4, 8, 10, 2]]; // storage slot 1
function getArrSizeLoc_BaseSlot_Index(uint256 index)
public
pure
returns (uint256 slot)
{
uint256 baseSlot;
for (uint256 i; i <= index; i++) {
if (i == 0) {
assembly {
// `.slot` returns the state variable (balance) location within the storage slots.
// In our case, balance.slot = 6
baseSlot := nestedDynamicArray.slot
}
}
slot = uint256(keccak256(abi.encode(baseSlot))) + index;
}
}
function getArrDataLoc_SlotLoc_InternalIndex(uint256 locslot, uint256 index)
public
pure
returns (uint256 slot)
{
slot = uint256(keccak256(abi.encode(locslot))) + index;
}
function getSlot(
uint256 baseSlot,
uint256 _index1,
uint256 _index2
) public pure returns (bytes32 _finalSlot) {
// keccak256(baseSlot) + _index1
uint256 _initialSlot = uint256(keccak256(abi.encode(baseSlot))) +
_index1;
// keccak256(_initialSlot) + _index2
_finalSlot = bytes32(
uint256(keccak256(abi.encode(_initialSlot))) + _index2
);
}
function getSlotValue(uint256 _slot) public view returns (uint256 value) {
assembly {
value := sload(_slot)
}
}
function addArray() external {
nestedDynamicArray.push([22, 6, 99, 14]);
}
}
数据:[[2, 9, 6, 3, 2], [7, 4, 8, 10, 2]],Array[array1,array2]
动态数据类型存储
说明 | slot | Value |
---|---|---|
baseSlot | 1 | 2 |
array1 存储size的slot,s1 | keccack(1)+0= 80084422859880547211683076133703299733277748156566366325829078699459944778998 | 5 |
array2 存储size的slot,s2 | keccack(1)+1= 80084422859880547211683076133703299733277748156566366325829078699459944778999 | 5 |
array1 存储index0的数据slot,d1 | keccack(s1)+0= 82253526175936117417672031222849803842933200219522072251142807856800200228130 | 0x0000000000000003000000000000000600000000000000090000000000000002 |
array1 存储index1的数据slot,d2 | keccack(s1)+1= 82253526175936117417672031222849803842933200219522072251142807856800200228131 | 0x0000000000000000000000000000000000000000000000000000000000000002 |
array2 存储index0的数据slot,d3 | keccack(s2)+0= 106053296617608346790393806727882046642653284128270527600775845709961105489201 | 0x000000000000000a000000000000000800000000000000040000000000000007 |
array2 存储index1的数据slot,d4 | keccack(s2)+1= 106053296617608346790393806727882046642653284128270527600775845709961105489202 | 0x0000000000000000000000000000000000000000000000000000000000000002 |