在block pool接收到一个新区块,如果新区块在block pool中能找到父区块(连续的父区块个数,也就是gap),但是在当前世界状态中找不到父区块。如果gap超过一定的数值(32),启动同步。BlockPool中启动Sync服务的相关逻辑如下:
1.// find parent in Chain.
2.var parentBlock *Block
3.ifparentBlock = bc.GetBlock(lb.parentHash); parentBlock == nil {
4.// still not found, wait to parent block from network.
5.ifsender == NoSender {
6.returnErrMissingParentBlock
7.}
8.
9.// do sync if there are so many empty slots.
10.ifgap > ChunkSize { //如果gap超过Chunk的大小,启动同步
11.ifbc.StartActiveSync() {
12.logging.CLog().WithFields(logrus.Fields{
13."tail": bc.tailBlock,
14."block": block,
15."offline": gap,
16."limit": ChunkSize,
17.}).Warn("Offline too long, pend mining and restart sync from others.")
18.}
19.returnErrInvalidBlockCannotFindParentInLocalAndTrySync
20.}
21.if!bc.IsActiveSyncing() {
22.iferr := pool.downloadParent(sender, lb.block); err != nil {
23.returnerr
24.}
25.}
26.returnErrInvalidBlockCannotFindParentInLocalAndTryDownload
27.}
1)Chunk,ChunkHeader以及ChunkData
星云链节点间同步以Chunk为单位,一个Chunk包含32个区块。同步区块数据分成两个阶段:1)同步ChunkHeader 2)同步具体Chunk中的区块数据。
ChunkHeader描述Chunk的信息,示意如下图:
Chunk Header包括32个区块的Hash信息以及区块Hash组成的Hash Root。因为一次同步最多同步10个区块,所以,在一次同步中最多传输10个Chunk Header。为了保证10个Chunk Header的数据一致性,在传输过程中提供了区块Hash Root的Hash Root,如下图:
ChunkData描述一个Chunk的具体区块数据,如下图:
生成以及验证ChunkHeader以及ChunkData的逻辑在sync/chunk.go代码中。generateChunkHeaders和verifyChunkHeaders用来生成和验证ChunkHeader信息。generateChunkData和verifyChunkData用来生成和验证ChunkData信息。
11.2) Sync Service和Task
Service整个Sync逻辑的接口,实现了两个主要功能:1)监听网络消息2)StartActiveSync启动同步。Service使用messageCh,向NetService注册四个Subscriber,分别监听四个消息(ChunkHeader请求和回复以及ChunkData请求和回复),并针对四个消息提供了四个处理函数,如下图所示:
StartActiveSync函数是同步的入口函数,主要创建Task开始同步。Task类型的startSyncLoop函数从当前区块链的最后一个区块开始同步区块。startSyncLoop函数的逻辑示意如下图,同步分两个阶段(Chunk Headers以及Chunk Data同步):
领取专属 10元无门槛券
私享最新 技术干货