以太坊 stateObject中Storage存储内容

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}

下一章:以太坊源码分析 挖矿

以太坊挖矿流程的基本框架参见下图:其中涉及到的组件之间的关系可以参见下面的UML图:1. Miner启动打包在eth Service初始化的时候,会创建一个Miner实例:eth.miner = miner.New(e ...