以太坊stateObject中Storage存储内容的探究

昨天跟申总学了下怎么看EVM指令,然后就一撸到底,很爽,哈哈。。。

stateOject中有两个Storage类型的变量,是用来缓存智能合约中所有变量的值的。这个Storage类型的定义如下:

type Storage map[common.Hash]common.Hash

就是一个map,key跟value都是common.Hash类型,其实就是[]byte。这个map只有在EVM执行SSTORE指令时候会赋值,用于记录变量的值。那么这里面的key跟value具体是什么内容呢?经研究,结果如下:

  • 对于基本数据类型,key = 合约中的变量声明位置(从0开始)
  • 对于map类型,key = SHA3(map中的关键字,变量声明位置),也就是把map中的关键字和变量声明位置拼在一起成为一个64字节的[]byte,然后计算hash值
  • value不管在哪种情况下都存储变量的实际值


可以使用browser-solidity查看编译出来的EVM指令:

https://ethereum.github.io/browser-solidity

在编辑器中写测试代码:

pragma solidity ^0.4.0;
contract Demo {

    int a;
    int x;
    mapping(address => int) b;

    function myfunc() public {
        a = 8;
        x = 9;
        b[123] = 1;
    }
}

点击右边的“Start to compile”,然后点击“Details”就可以查看编译出来的EVM指令。以map为例,逐条分析指令就可以看出SSTORE具体存储的key和value是如何生成的:

// 压栈返回值
      PUSH 1 1
stack [1]
// 压栈变量position
      PUSH 2 b
stack [2 1]
// 压栈内存存储起点
      PUSH 0 b[123]
stack [0 2 1]
// 压栈map索引值(即123)
      PUSH 7B 123
stack [7B 0 2 1]
// 压栈mask
      PUSH FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF b[123]
stack [FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 7B 0 2 1]
// 索引值 & mask,弹出2个值,压栈与的结果
      AND b[123]
stack [7B 0 2 1]
// 复制第二个值并压栈
      DUP2 b[123]
stack [0 7B 0 2 1]
// 在内存0位置存储7B(即map索引值),弹出2个值
      MSTORE b[123]
stack [0 2 1]
store {7B}
// 压栈内存偏移,0x20 = 32字节
      PUSH 20 b[123]
stack [20 0 2 1]
store {7B}

// 计算内存偏移,弹出2个值,压栈相加的结果
      ADD b[123]
stack [20 2 1]
store {7B}

// 交换栈顶2个值
      SWAP1 b[123]
stack [2 20 1]
store {7B}

// 复制第二个值并压栈
      DUP2 b[123]
stack [20 2 20 1]
store {7B}  
 
// 在内存0x20位置存储2(即变量position)
      MSTORE b[123]
stack [20 1]
store {7B 2}

// 压栈内存偏移,0x20 = 32字节
      PUSH 20 b[123]
stack [20 20 1]
store {7B 2}

// 计算内存偏移,弹出2个值,压栈相加的结果
      ADD b[123]
stack [40 1]
store {7B 2}

// 压栈数据读取offset
      PUSH 0 b[123]
stack [0 40 1]
store {7B 2}

// offset=0, size=0x40,也就是从store中读取2个32字节的值,
// 然后计算SHA3,结果压栈

      KECCAK256 b[123]
stack [sha3(0x0000007B00000002) 1]
store {7B 2}

// 复制第二个值(即要赋的值)并压栈
      DUP2 b[123] = 1
stack [1 sha3 1]
store {7B 2}

// 交换栈顶2个值
      SWAP1 b[123] = 1
stack [sha3 1 1]
store {7B 2}

// 以sha3为key,1为value,存入StateDB,同时弹栈
      SSTORE b[123] = 1
stack [1]
store {7B 2}

// 弹出返回值
      POP b[123] = 1
stack []

store {7B 2}

思考题:如果是struct或者array类型,是怎么存储的呢? :-)

更多文章欢迎关注“鑫鑫点灯”专栏:https://blog.csdn.net/turkeycock/article/category/7669858

猜你喜欢

转载自blog.csdn.net/turkeycock/article/details/80560907