区块链本身就是通过特定的机制来生成和维护数据,使数据具有极高的稳定性和可靠性。所以了解区块链,首先要必须熟悉其数据结构,然后才能更好的理解数据运算机制也就是区块链的运行原理。
1 | // BlockChain represents the canonical chain given a database with a genesis |
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| 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事件 |
关键的元素:
- db:连接到底层数据储存,即leveldb;
- hc:headerchain区块头链,由blockchain额外维护的另一条链,由于Header和Block的储存空间是有很大差别的,但同时Block的Hash值就是Header(RLP)的Hash值,所以维护一个headerchain可以用于快速延长链,验证通过后再下载blockchain,或者可以与blockchain进行相互验证;
- genesisBlock:创始区块;
- currentBlock:当前区块,blockchain中并不是储存链所有的block,而是通过currentBlock向前回溯直到genesisBlock,这样就构成了区块链。
- bodyCache、bodyRLPCache、blockCache、futureBlocks:区块链中的缓存结构,用于加快区块链的读取和构建;
- engine:是consensus模块中的接口,用来验证block的接口;
- processor:执行区块链交易的接口,收到一个新的区块时,要对区块中的所有交易执行一遍,一方面是验证,一方面是更新worldState;
- validator:验证数据有效性的接口
- futureBlocks:收到的区块时间大于当前头区块时间15s而小于30s的区块,可作为当前节点待处理的区块。
下边是区块的数据结构
1 | // Block represents an entire block in the Hpb blockchain. |
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| 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 | // Header represents a block header in the Hpb blockchain. |
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| 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 | type Body struct { |
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| Transactions | []*Transaction | 交易集合 | |
| Uncles | []*Header | 叔区块头集合 |
1 | type Transaction struct { |
| 字段 | 类型 | 含义 | 备注 | ||
|---|---|---|---|---|---|
| data | txdata | 交易数据 | |||
| hash | atomic.Value | ||||
| size | atomic.Value | ||||
| from | atomic.Value | tx的转帐转出方地址,就是对该tx对象作ECDSA签名计算时所用的公钥publicKey | |||
| fromP2P | bool | ||||
|
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| 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转换时使用 | |
| 以上便是区块链中最主要的“区块链”数据结构,有些字段描述不是很清楚,后续再逐步完善。 |