GO-HPB源码解读--数据结构

区块链本身就是通过特定的机制来生成和维护数据,使数据具有极高的稳定性和可靠性。所以了解区块链,首先要必须熟悉其数据结构,然后才能更好的理解数据运算机制也就是区块链的运行原理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// BlockChain represents the canonical chain given a database with a genesis
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
//
// Importing blocks in to the block chain happens according to the set of rules
// defined by the two stage Validator. Processing of blocks is done using the
// Processor which processes the included transaction. The validation of the state
// is done in the second part of the Validator. Failing results in aborting of
// the import.
//
// The BlockChain also helps in returning blocks from **any** chain included
// in the database as well as blocks that represents the canonical chain. It's
// important to note that GetBlock can return any block and does not need to be
// included in the canonical one where as GetBlockByNumber always represents the
// canonical chain.

<!-- more -->

type BlockChain struct {
config *config.ChainConfig // chain & network configuration
hc *HeaderChain
chainDb hpbdb.Database
rmLogsFeed sub.Feed
chainFeed sub.Feed
chainSideFeed sub.Feed
chainHeadFeed sub.Feed
logsFeed sub.Feed
scope sub.SubscriptionScope
genesisBlock *types.Block
mu sync.RWMutex // global mutex for locking chain operations
chainmu sync.RWMutex // blockchain insertion lock
procmu sync.RWMutex // block processor lock
checkpoint int // checkpoint counts towards the new checkpoint
currentBlock *types.Block // Current head of the block chain
currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
// procInterrupt must be atomically called
procInterrupt int32 // interrupt signaler for block processing
wg sync.WaitGroup // chain processing wait group for shutting down
engine consensus.Engine
processor Processor // block processor interface
validator Validator // block and state validator interface
badBlocks *lru.Cache // Bad block cache
}
字段 类型 含义 备注
config *config.ChainConfig 定义了chainID和监控参数
hc *HeaderChain 区块头组成的链
chainDb hpbdb.Database 数据库
rmLogsFeed sub.Feed
chainFeed sub.Feed
chainSideFeed sub.Feed
chainHeadFeed sub.Feed
logsFeed sub.Feed
scope sub.SubscriptionScope
genesisBlock *types.Block
mu sync.RWMutex 区块链的全局锁
chainmu sync.RWMutex 区块链插入锁
procmu sync.RWMutex 区块处理的锁
checkpoint int
currentBlock *types.Block 主链的头区块
currentFastBlock *types.Block 快速同步模式下链的头区块,这种情况下可能比主链长
stateCache state.Database
bodyCache *lru.Cache 最近区块体的缓存信息
bodyRLPCache *lru.Cache 最近区块体的RLP格式的缓存信息
blockCache *lru.Cache 最近区块的缓存
futureBlocks *lru.Cache 将来等待上链的区块
quit chan struct{}
running int32
procInterrupt int32
wg sync.WaitGroup
engine consensus.Engine 验证区块的引擎
processor Processor 执行区块交易的接口
validator Validator 验证区块和state有效性的接口
badBlocks *lru.Cache 验证失败的区块缓存,来自DAO事件

关键的元素:

  1. db:连接到底层数据储存,即leveldb;
  2. hc:headerchain区块头链,由blockchain额外维护的另一条链,由于Header和Block的储存空间是有很大差别的,但同时Block的Hash值就是Header(RLP)的Hash值,所以维护一个headerchain可以用于快速延长链,验证通过后再下载blockchain,或者可以与blockchain进行相互验证;
  3. genesisBlock:创始区块;
  4. currentBlock:当前区块,blockchain中并不是储存链所有的block,而是通过currentBlock向前回溯直到genesisBlock,这样就构成了区块链。
  5. bodyCache、bodyRLPCache、blockCache、futureBlocks:区块链中的缓存结构,用于加快区块链的读取和构建;
  6. engine:是consensus模块中的接口,用来验证block的接口;
  7. processor:执行区块链交易的接口,收到一个新的区块时,要对区块中的所有交易执行一遍,一方面是验证,一方面是更新worldState;
  8. validator:验证数据有效性的接口
  9. futureBlocks:收到的区块时间大于当前头区块时间15s而小于30s的区块,可作为当前节点待处理的区块。

下边是区块的数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Block represents an entire block in the Hpb blockchain.
type Block struct {
header *Header
uncles []*Header
transactions Transactions

// 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{}
}
字段 类型 含义 备注
header *Header 当前区块头
uncles []*Header 叔区块,因出块速度快,导致分叉概率高,为了增加矿工挖矿积极性,对于分叉后的无用区块也进行打包,奖励矿工,那么这些无用区块就是叔区块。同时为了为了抵消整个Ethereum网络中那些计算能力特别强大的节点会对区块的产生有过大的影响力,防止这些节点破坏“去中心化”这个根本宗旨
transactions Transactions 交易集合
hash atomic.Value 区块的哈希,是从Header中缓存下来的,等于Header中的哈希值,是header中除nonce和mixDigest数据外的rlp的hash,这样相同的交易内容的相同该区块hash是一样,哪怕是由不同的节点创建出来的。区块的header和body是分开存储的,key都是前缀加上当前hash
size atomic.Value
td *big.Int td是totalDifficulty的缩写,表示从创世区块到当前区块的所有Difficulty之和,而每个区块的Difficulty是保存在header中的
ReceivedAt time.Time 区块生成时间
ReceivedFrom interface{} 区块生成来源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Header represents a block header in the Hpb blockchain.
type Header struct {
ParentHash common.Hash `json:"parentHash" `
UncleHash common.Hash `json:"sha3Uncles" `
Coinbase common.Address `json:"miner" `
CandAddress common.Address `json:"candAddress" `
ComdAddress common.Address `json:"comdAddress" `
VoteIndex *big.Int `json:"voteIndex" `
Root common.Hash `json:"stateRoot" `
TxHash common.Hash `json:"transactionsRoot" `
ReceiptHash common.Hash `json:"receiptsRoot" `
Bloom Bloom `json:"logsBloom" `
Difficulty *big.Int `json:"difficulty" `
Number *big.Int `json:"number" `
GasLimit *big.Int `json:"gasLimit" `
GasUsed *big.Int `json:"gasUsed" `
Time *big.Int `json:"timestamp" `
Extra []byte `json:"extraData" `
MixDigest common.Hash `json:"mixHash" `
Nonce BlockNonce `json:"nonce" `
HardwareRandom []byte `json:"hardwareRandom" `
}
字段 类型 含义 备注
ParentHash common.Hash 父区块的hash
UncleHash common.Hash 叔区块的hash
Coinbase common.Address 挖矿生成该区块的地址,挖矿是由节点来完成的,每个full节点都个默认的Coinbase地址,用来接收挖矿(矿工费和打包区块的奖金)奖励
CandAddress common.Address
ComdAddress common.Address
VoteIndex *big.Int 投票索引
Root common.Hash 存储账户(合约帐户和用户帐户)状态的Merkle树的根节点的哈希,StateDB中的“state Trie”的根节点的RLP哈希值。Block中,每个账户以stateObject对象表示,账户以Address为唯一标示,其信息在相关交易(Transaction)的执行中被修改。所有账户对象可以逐个插入一个Merkle-PatricaTrie(MPT)结构里,形成“state Trie”。
TxHash common.Hash Block中交易树 “tx Trie”的根节点的RLP哈希值。Block的成员变量transactions中所有的tx对象,被逐个插入一个MPT结构,形成“tx Trie”。
ReceiptHash common.Hash “Receipt Trie”的根节点的RLP哈希值。Block的所有Transaction执行完后会生成一个Receipt数组,这个数组中的所有Receipt被逐个插入一个MPT结构中,最后形成”Receipt Trie”
Bloom Bloom Bloom过滤器(Filter),用来快速判断一个参数Log对象是否存在于一组已知的Log集合中。
Difficulty *big.Int 区块的难度。Block的Difficulty由共识算法基于parentBlock的Time和Difficulty计算得出,它会应用在区块的‘挖掘’阶段。
Number *big.Int 区块的序号。Block的Number等于其父区块Number +1。
GasLimit *big.Int 区块内所有Gas消耗的上限。该数值在区块创建时赋值,与父区块的数据相关。具体来说,根据父区块的GasUsed同创世块的GasLimit * 2/3的大小关系来计算得出。
GasUsed *big.Int 区块内所有Transaction执行时所实际消耗的Gas总和。
Time *big.Int 区块“应该”被创建的时间。由共识算法确定,一般来说,要么等于parentBlock.Time + 10s,要么等于当前系统时间。区块开始打包时间戳(调用Engine.Prepare函数的时候设置)
Extra []byte 扩展信息
MixDigest common.Hash 区块头除去Nonce, mixDigest数据的hash+nonce的RLP的hash值
Nonce BlockNonce 一个64bit的哈希数,它被用于POW等挖块算法,暴力碰撞得出,该哈希值与MixDigest哈希值一起证明该区块上已经进行了足够的计算,用于证明挖矿成功
HardwareRandom []byte BOE硬件随机数
1
2
3
4
type Body struct {
Transactions []*Transaction
Uncles []*Header
}
字段 类型 含义 备注
Transactions []*Transaction 交易集合
Uncles []*Header 叔区块头集合
1
2
3
4
5
6
7
8
type Transaction struct {
data txdata
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
fromP2P bool
}
字段 类型 含义 备注
data txdata 交易数据
hash atomic.Value
size atomic.Value
from atomic.Value tx的转帐转出方地址,就是对该tx对象作ECDSA签名计算时所用的公钥publicKey
fromP2P bool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type txdata struct {
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit *big.Int `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value" gencodec:"required"`
Payload []byte `json:"input" gencodec:"required"`
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
// This is only used when marshaling to JSON.
Hash *common.Hash `json:"hash" rlp:"-"`
}
字段 类型 含义 备注
AccountNonce uint64 发送者发起的交易总数
Price *big.Int 交易的Gas价格
GasLimit *big.Int 交易允许消耗的最大Gas
Recipient *common.Address 交易接收者地址,
Amount *big.Int 交易额
Payload []byte 它既可以作为所创建合约的指令数组,其中每一个byte作为一个单独的虚拟机指令;也可以作为数据数组,由合约指令进行操作。合约由以太坊虚拟机(Ethereum Virtual Machine, EVM)创建并执行。
V *big.Int tx的数字签名(ECDSA),是一个长度为65bytes的字节数组,它被截成三段放进tx中,前32bytes赋值给成员变量R, 再32bytes赋值给S,末1byte赋给V
R *big.Int 同上
S *big.Int 同上
Hash *common.Hash 交易HAsh,只在JSON转换时使用
以上便是区块链中最主要的“区块链”数据结构,有些字段描述不是很清楚,后续再逐步完善。