[技术学习]以太坊智能合约的存储是怎么实现的

in #blockchain4 years ago

存储空间

可以看作为一个包含2^256个入口(slot)的array,每个入口是32-byte大小

但是实际存储中,使用的是key-value的形式存储的,这个可以看作为一个稀疏数组:

32-byte keys to 32-byte values

没有数据存储的key,对应的值就是0

因此,当智能合约中,某个key对应的存储从某个值变为0时,就会回收存储空间,这在以太坊智能合约中就对应于一个refund

固定大小数据存储

对于固定数据的存储,就是按照顺序分配slot

contract StorageTest {
    uint256 a;
    uint256[2] b;

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;
}

image

动态大小数据存储 - 数组/slice

动态大小的数据结构,存储size和数据,其中size按照顺序存储,实际数据则存储在hash(slotNumber)开始的空间

contract StorageTest {
    uint256 a;     // slot 0
    uint256[2] b;  // slots 1-2

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;       // slots 3-4
    Entry[] d;
}

接着上一个solidity合约的例子,d 为变长结构,d的数组大小存储在slot 5内,而d的实际内容存储在hash(5)开始的连续空间

image

计算函数:

function arrLocation(uint256 slot, uint256 index, uint256 elementSize)
    public
    pure
    returns (uint256)
{
    return uint256(keccak256(slot)) + (index * elementSize);
}

动态大小数据存储 - map

map需要根据key对数据内容进行快速查找,存储时先对map的size指定一个slot,但是这个slot内并没有实际内容,只是利用slot的编号,去寻址后续map的内容
hash(value,slotnumber)

contract StorageTest {
    uint256 a;     // slot 0
    uint256[2] b;  // slots 1-2

    struct Entry {
        uint256 id;
        uint256 value;
    }
    Entry c;       // slots 3-4
    Entry[] d;     // slot 5 for length, keccak256(5)+ for data

    mapping(uint256 => uint256) e;
    mapping(uint256 => uint256) f;
}

image

计算函数:

function mapLocation(uint256 slot, uint256 key) public pure returns (uint256) {
    return uint256(keccak256(key, slot));
}

动态大小数据存储 - 复杂结构

对于比较复杂的结构,主要是分析先取map还是array,然后按照上述的两种计算函数组合即可,arrLocation和mapLocation

学习内容来源

https://programtheblockchain.com/

Coin Marketplace

STEEM 0.18
TRX 0.16
JST 0.030
BTC 62816.09
ETH 2466.13
USDT 1.00
SBD 2.64