以太坊源码解读(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对应的区块是否在规范链上。
key | value |
'h' + num +hash | header的RLP编码值 |
'b' + num +hash | body的RLP编码值 |
'r' + num +hash | receipt的RLP编码值 |
'h' + num + hash + 't' | 截止该区块的总难度值 |
'h' + num + 'n' | 区块号对应的规范链上的区块的hash(规范链 ) |
'H' + hash | Header对应的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 // 初始化配置 ...