github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/netsync/chainmgr/block_keeper.go (about) 1 package chainmgr 2 3 import ( 4 "time" 5 6 log "github.com/sirupsen/logrus" 7 8 "github.com/bytom/bytom/consensus" 9 dbm "github.com/bytom/bytom/database/leveldb" 10 "github.com/bytom/bytom/netsync/peers" 11 "github.com/bytom/bytom/p2p/security" 12 "github.com/bytom/bytom/protocol/bc" 13 "github.com/bytom/bytom/protocol/bc/types" 14 ) 15 16 const ( 17 syncCycle = 5 * time.Second 18 19 noNeedSync = iota 20 fastSyncType 21 regularSyncType 22 ) 23 24 var ( 25 maxNumOfBlocksPerMsg = uint64(64) 26 maxNumOfHeadersPerMsg = uint64(1000) 27 maxNumOfBlocksRegularSync = uint64(128) 28 ) 29 30 // Fetcher is the interface for fetch struct 31 type Fetcher interface { 32 processBlock(peerID string, block *types.Block) 33 processBlocks(peerID string, blocks []*types.Block) 34 processHeaders(peerID string, headers []*types.BlockHeader) 35 requireBlock(peerID string, height uint64) (*types.Block, error) 36 } 37 38 type blockMsg struct { 39 block *types.Block 40 peerID string 41 } 42 43 type blocksMsg struct { 44 blocks []*types.Block 45 peerID string 46 } 47 48 type headersMsg struct { 49 headers []*types.BlockHeader 50 peerID string 51 } 52 53 type blockKeeper struct { 54 chain Chain 55 fastSync *fastSync 56 msgFetcher Fetcher 57 peers *peers.PeerSet 58 syncPeer *peers.Peer 59 60 quit chan struct{} 61 } 62 63 func newBlockKeeper(chain Chain, peers *peers.PeerSet, fastSyncDB dbm.DB) *blockKeeper { 64 storage := newStorage(fastSyncDB) 65 msgFetcher := newMsgFetcher(storage, peers) 66 return &blockKeeper{ 67 chain: chain, 68 fastSync: newFastSync(chain, msgFetcher, storage, peers), 69 msgFetcher: msgFetcher, 70 peers: peers, 71 quit: make(chan struct{}), 72 } 73 } 74 75 func (bk *blockKeeper) locateBlocks(locator []*bc.Hash, stopHash *bc.Hash, isTimeout func() bool) ([]*types.Block, error) { 76 headers, err := bk.locateHeaders(locator, stopHash, 0, maxNumOfBlocksPerMsg) 77 if err != nil { 78 return nil, err 79 } 80 81 blocks := []*types.Block{} 82 for _, header := range headers { 83 headerHash := header.Hash() 84 block, err := bk.chain.GetBlockByHash(&headerHash) 85 if err != nil { 86 return nil, err 87 } 88 89 blocks = append(blocks, block) 90 if isTimeout() { 91 break 92 } 93 } 94 return blocks, nil 95 } 96 97 func (bk *blockKeeper) locateHeaders(locator []*bc.Hash, stopHash *bc.Hash, skip uint64, maxNum uint64) ([]*types.BlockHeader, error) { 98 startHeader, err := bk.chain.GetHeaderByHeight(0) 99 if err != nil { 100 return nil, err 101 } 102 103 for _, hash := range locator { 104 header, err := bk.chain.GetHeaderByHash(hash) 105 if err == nil && bk.chain.InMainChain(header.Hash()) { 106 startHeader = header 107 break 108 } 109 } 110 111 headers := make([]*types.BlockHeader, 0) 112 stopHeader, err := bk.chain.GetHeaderByHash(stopHash) 113 if err != nil { 114 return headers, err 115 } 116 117 if !bk.chain.InMainChain(*stopHash) || stopHeader.Height < startHeader.Height { 118 return headers, nil 119 } 120 121 headers = append(headers, startHeader) 122 if stopHeader.Height == startHeader.Height { 123 return headers, nil 124 } 125 126 for num, index := uint64(0), startHeader.Height; num < maxNum-1; num++ { 127 index += skip + 1 128 if index >= stopHeader.Height { 129 headers = append(headers, stopHeader) 130 break 131 } 132 133 header, err := bk.chain.GetHeaderByHeight(index) 134 if err != nil { 135 return nil, err 136 } 137 138 headers = append(headers, header) 139 } 140 141 return headers, nil 142 } 143 144 func (bk *blockKeeper) processBlock(peerID string, block *types.Block) { 145 bk.msgFetcher.processBlock(peerID, block) 146 } 147 148 func (bk *blockKeeper) processBlocks(peerID string, blocks []*types.Block) { 149 bk.msgFetcher.processBlocks(peerID, blocks) 150 } 151 152 func (bk *blockKeeper) processHeaders(peerID string, headers []*types.BlockHeader) { 153 bk.msgFetcher.processHeaders(peerID, headers) 154 } 155 156 func (bk *blockKeeper) regularBlockSync() error { 157 peerHeight := bk.syncPeer.Height() 158 bestHeight := bk.chain.BestBlockHeight() 159 targetHeight := bestHeight + maxNumOfBlocksRegularSync 160 if targetHeight > peerHeight { 161 targetHeight = peerHeight 162 } 163 164 for i := bestHeight + 1; i <= targetHeight; { 165 block, err := bk.msgFetcher.requireBlock(bk.syncPeer.ID(), i) 166 if err != nil { 167 bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelConnException, err.Error()) 168 return err 169 } 170 171 isOrphan, err := bk.chain.ProcessBlock(block) 172 if err != nil { 173 bk.peers.ProcessIllegal(bk.syncPeer.ID(), security.LevelMsgIllegal, err.Error()) 174 return err 175 } 176 177 if isOrphan { 178 i-- 179 continue 180 } 181 182 //This code is used to preventing the sync peer return a dust block which will not change the node's chain status 183 if bestHeight = bk.chain.BestBlockHeight(); i == bestHeight+1 { 184 log.WithFields(log.Fields{"module": logModule, "height": i}).Warn("stop regular sync due to loop sync same height") 185 return nil 186 } 187 188 i = bestHeight + 1 189 } 190 log.WithFields(log.Fields{"module": logModule, "height": bk.chain.BestBlockHeight()}).Info("regular sync success") 191 return nil 192 } 193 194 func (bk *blockKeeper) start() { 195 go bk.syncWorker() 196 } 197 198 func (bk *blockKeeper) checkSyncType() int { 199 bestHeight := bk.chain.BestBlockHeight() 200 peer := bk.peers.BestPeer(consensus.SFFullNode | consensus.SFFastSync) 201 if peer != nil { 202 if peerJustifiedHeight := peer.JustifiedHeight(); peerJustifiedHeight >= bestHeight+minGapStartFastSync { 203 bk.fastSync.setSyncPeer(peer) 204 return fastSyncType 205 } 206 } 207 208 peer = bk.peers.BestPeer(consensus.SFFullNode) 209 if peer == nil { 210 log.WithFields(log.Fields{"module": logModule}).Debug("can't find sync peer") 211 return noNeedSync 212 } 213 214 if peer.Height() > bestHeight { 215 bk.syncPeer = peer 216 return regularSyncType 217 } 218 219 return noNeedSync 220 } 221 222 func (bk *blockKeeper) startSync() bool { 223 switch bk.checkSyncType() { 224 case fastSyncType: 225 if err := bk.fastSync.process(); err != nil { 226 log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("failed on fast sync") 227 return false 228 } 229 case regularSyncType: 230 if err := bk.regularBlockSync(); err != nil { 231 log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on regularBlockSync") 232 return false 233 } 234 default: 235 return false 236 } 237 238 return true 239 } 240 241 func (bk *blockKeeper) stop() { 242 close(bk.quit) 243 } 244 245 func (bk *blockKeeper) syncWorker() { 246 syncTicker := time.NewTicker(syncCycle) 247 defer syncTicker.Stop() 248 249 for { 250 select { 251 case <-syncTicker.C: 252 if update := bk.startSync(); !update { 253 continue 254 } 255 256 lastJustifiedHeader, err := bk.chain.LastJustifiedHeader() 257 if err != nil { 258 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail get last just justified header") 259 } 260 261 if err := bk.peers.BroadcastNewStatus(bk.chain.BestBlockHeader(), lastJustifiedHeader); err != nil { 262 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new status") 263 } 264 case <-bk.quit: 265 return 266 } 267 } 268 }