以太坊源码解读(4)Block类和储存

一、Block类

type Block struct {
        /******header*******/
	header       *Header
        /******header*******/

        /******body*********/
	uncles       []*Header
	transactions Transactions
        /******body*********/

	// caches
	hash atomic.Value
	size atomic.Value

	// Td is used by package core to store the total difficulty
	// of the chain up to and including the block.
	td *big.Int

	// These fields are used by package eth to track
	// inter-peer block relay.
	ReceivedAt   time.Time
	ReceivedFrom interface{}
}

block类实际上就只有两个部分,header和body。其他的如hash、size、td等都是在接受和验证区块后产生的内容,实际上向全网公布的时候block就只有header和body(uncles和transactions)。

Header里有哪些内容呢?

type Header struct {
	ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
	UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
	Coinbase    common.Address `json:"miner"            gencodec:"required"`
	Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
	TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
	ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
	Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
	Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
	Number      *big.Int       `json:"number"           gencodec:"required"`
	GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
	GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
	Time        *big.Int       `json:"timestamp"        gencodec:"required"`
	Extra       []byte         `json:"extraData"        gencodec:"required"`
	MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"`
	Nonce       BlockNonce     `json:"nonce"            gencodec:"required"`
}

1)ParentHash:前一个区块的hash
2)UncleHash:叔区块hash,如果有多个叔区块就加到一起
3)Coinbase:矿工账户
4)Root:StateDB中的“state Trie”的根节点的RLP哈希值。
5)TxHash:“tx Trie”的根节点的RLP哈希值。
6)ReceiptHash: "Receipt Trie”的根节点的RLP哈希值。
7)Bloom:Bloom过滤器(Filter),用来快速判断一个参数Log对象是否存在于一组已知的Log集合中。
8)Difficulty:难度值
9)Number:区块号
10)GasLimit:区块内所有Gas消耗的理论上限。该数值在区块创建时设置,与父区块的GasUsed有关。
11)GasUsed:区块内所有Transaction执行时所实际消耗的Gas总和。
12)Time:时间戳
13)Extra:额外信息
14)Nonce:pow产生的数值,也可以用于验证矿工的工作

二、Root、TxHash、ReceiptHash

在比特币中,区块body中的交易通过merkle tree的形式组织,然后将merkle root存在block header中。

而在以太坊中不是merkle-tree,而是Merkle-PatricaTrie(MPT)结构,而且存在三棵树:state Trie、tx Trie、Receipt Trie。

首先,在StateDB中,每个账户以stateObject对象表示,所有账户对象可以逐个插入一个Merkle-PatricaTrie(MPT)结构里,形成“state Trie”。其次,Block的transactions中所有的tx对象,被逐个插入一个MPT结构,形成“tx Trie”。最后,所有Transaction执行完后会生成一个Receipt数组,这个数组中的所有Receipt被逐个插入一个MPT结构中,形成"Receipt Trie"

上图中表示的意思是,首先一个区块的几个重要部分分开储存在leveldb中,header、body、receipts以RLP编码的形式储存在数据库中,key都是用num+key构成的。另外,我们可以通过‘h’+num+hash+'t'查询区块链的总难度td;‘H’+hash可以查询到blocknumber;在知道num的情况下可以查询‘h’+num+‘n’对应的区块链上的hash(即不在规范链上的区块可能也有该num,但是无法通过这个key查询到);在仅仅知道hash的情况下,通过‘l’+hash来查询区块hash+区块号+交易编码的编码值,这样的值仅仅储存规范链上的区块,所以我们可以快速的查看某hash对应的区块是否在规范链上。

keyvalue
'h' + num +hashheader的RLP编码值
'b' + num +hashbody的RLP编码值
'r' + num +hashreceipt的RLP编码值
'h' + num + hash + 't'截止该区块的总难度值
'h' + num + 'n'区块号对应的规范链上的区块的hash(规范链 )
'H' + hashHeader对应的block number(规范链)
'l' + hash【区块hash、区块号num、交易编号】的编码值,是交易查询入口(规范链)

这些信息都在强烈的暗示,num(Number)和hash是Block最为重要的两个属性:num用来确定Block在整个区块链中所处的位置,hash用来辨识惟一的Block/Header对象。

通过以上的设计,Block结构体的所有重要成员,都被存储进了底层数据库。当所有Block对象的信息都已经写进数据库后,我们就可以使用BlockChain结构体来处理整个块链。

一、blockchain的数据结构 type BlockChain struct { chainConfig *params.ChainConfig // 初始化配置 ...