github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/netsync/block_keeper.go (about) 1 package netsync 2 3 import ( 4 "container/list" 5 "time" 6 7 log "github.com/sirupsen/logrus" 8 9 "github.com/bytom/bytom/consensus" 10 "github.com/bytom/bytom/errors" 11 "github.com/bytom/bytom/mining/tensority" 12 "github.com/bytom/bytom/p2p/security" 13 "github.com/bytom/bytom/protocol/bc" 14 "github.com/bytom/bytom/protocol/bc/types" 15 ) 16 17 const ( 18 syncCycle = 5 * time.Second 19 blockProcessChSize = 1024 20 blocksProcessChSize = 128 21 headersProcessChSize = 1024 22 ) 23 24 var ( 25 maxBlockPerMsg = uint64(128) 26 maxBlockHeadersPerMsg = uint64(2048) 27 syncTimeout = 30 * time.Second 28 29 errAppendHeaders = errors.New("fail to append list due to order dismatch") 30 errRequestTimeout = errors.New("request timeout") 31 errPeerDropped = errors.New("Peer dropped") 32 errPeerMisbehave = errors.New("peer is misbehave") 33 ErrPeerMisbehave = errors.New("peer is misbehave") 34 ) 35 36 type blockMsg struct { 37 block *types.Block 38 peerID string 39 } 40 41 type blocksMsg struct { 42 blocks []*types.Block 43 peerID string 44 } 45 46 type headersMsg struct { 47 headers []*types.BlockHeader 48 peerID string 49 } 50 51 type blockKeeper struct { 52 chain Chain 53 peers *peerSet 54 55 syncPeer *peer 56 blockProcessCh chan *blockMsg 57 blocksProcessCh chan *blocksMsg 58 headersProcessCh chan *headersMsg 59 60 headerList *list.List 61 } 62 63 func newBlockKeeper(chain Chain, peers *peerSet) *blockKeeper { 64 bk := &blockKeeper{ 65 chain: chain, 66 peers: peers, 67 blockProcessCh: make(chan *blockMsg, blockProcessChSize), 68 blocksProcessCh: make(chan *blocksMsg, blocksProcessChSize), 69 headersProcessCh: make(chan *headersMsg, headersProcessChSize), 70 headerList: list.New(), 71 } 72 bk.resetHeaderState() 73 go bk.syncWorker() 74 return bk 75 } 76 77 func (bk *blockKeeper) appendHeaderList(headers []*types.BlockHeader) error { 78 for _, header := range headers { 79 prevHeader := bk.headerList.Back().Value.(*types.BlockHeader) 80 if prevHeader.Hash() != header.PreviousBlockHash { 81 return errAppendHeaders 82 } 83 bk.headerList.PushBack(header) 84 } 85 return nil 86 } 87 88 func (bk *blockKeeper) blockLocator() []*bc.Hash { 89 header := bk.chain.BestBlockHeader() 90 locator := []*bc.Hash{} 91 92 step := uint64(1) 93 for header != nil { 94 headerHash := header.Hash() 95 locator = append(locator, &headerHash) 96 if header.Height == 0 { 97 break 98 } 99 100 var err error 101 if header.Height < step { 102 header, err = bk.chain.GetHeaderByHeight(0) 103 } else { 104 header, err = bk.chain.GetHeaderByHeight(header.Height - step) 105 } 106 if err != nil { 107 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("blockKeeper fail on get blockLocator") 108 break 109 } 110 111 if len(locator) >= 9 { 112 step *= 2 113 } 114 } 115 return locator 116 } 117 118 func (bk *blockKeeper) fastBlockSync(checkPoint *consensus.Checkpoint) error { 119 bk.resetHeaderState() 120 lastHeader := bk.headerList.Back().Value.(*types.BlockHeader) 121 for ; lastHeader.Hash() != checkPoint.Hash; lastHeader = bk.headerList.Back().Value.(*types.BlockHeader) { 122 if lastHeader.Height >= checkPoint.Height { 123 return errors.Wrap(errPeerMisbehave, "peer is not in the checkpoint branch") 124 } 125 126 lastHash := lastHeader.Hash() 127 headers, err := bk.requireHeaders([]*bc.Hash{&lastHash}, &checkPoint.Hash) 128 if err != nil { 129 return err 130 } 131 132 if len(headers) == 0 { 133 return errors.Wrap(errPeerMisbehave, "requireHeaders return empty list") 134 } 135 136 if err := bk.appendHeaderList(headers); err != nil { 137 return err 138 } 139 } 140 141 fastHeader := bk.headerList.Front() 142 for bk.chain.BestBlockHeight() < checkPoint.Height { 143 locator := bk.blockLocator() 144 blocks, err := bk.requireBlocks(locator, &checkPoint.Hash) 145 if err != nil { 146 return err 147 } 148 149 if len(blocks) == 0 { 150 return errors.Wrap(errPeerMisbehave, "requireBlocks return empty list") 151 } 152 153 for _, block := range blocks { 154 if fastHeader = fastHeader.Next(); fastHeader == nil { 155 return errors.New("get block than is higher than checkpoint") 156 } 157 158 blockHash := block.Hash() 159 if blockHash != fastHeader.Value.(*types.BlockHeader).Hash() { 160 return errPeerMisbehave 161 } 162 163 seed, err := bk.chain.CalcNextSeed(&block.PreviousBlockHash) 164 if err != nil { 165 return errors.Wrap(err, "fail on fastBlockSync calculate seed") 166 } 167 168 tensority.AIHash.AddCache(&blockHash, seed, &bc.Hash{}) 169 _, err = bk.chain.ProcessBlock(block) 170 tensority.AIHash.RemoveCache(&blockHash, seed) 171 if err != nil { 172 return errors.Wrap(err, "fail on fastBlockSync process block") 173 } 174 } 175 } 176 return nil 177 } 178 179 func (bk *blockKeeper) locateBlocks(locator []*bc.Hash, stopHash *bc.Hash) ([]*types.Block, error) { 180 headers, err := bk.locateHeaders(locator, stopHash) 181 if err != nil { 182 return nil, err 183 } 184 185 blocks := []*types.Block{} 186 for i, header := range headers { 187 if uint64(i) >= maxBlockPerMsg { 188 break 189 } 190 191 headerHash := header.Hash() 192 block, err := bk.chain.GetBlockByHash(&headerHash) 193 if err != nil { 194 return nil, err 195 } 196 197 blocks = append(blocks, block) 198 } 199 return blocks, nil 200 } 201 202 func (bk *blockKeeper) locateHeaders(locator []*bc.Hash, stopHash *bc.Hash) ([]*types.BlockHeader, error) { 203 stopHeader, err := bk.chain.GetHeaderByHash(stopHash) 204 if err != nil { 205 return nil, err 206 } 207 208 startHeader, err := bk.chain.GetHeaderByHeight(0) 209 if err != nil { 210 return nil, err 211 } 212 213 for _, hash := range locator { 214 header, err := bk.chain.GetHeaderByHash(hash) 215 if err == nil && bk.chain.InMainChain(header.Hash()) { 216 startHeader = header 217 break 218 } 219 } 220 221 totalHeaders := stopHeader.Height - startHeader.Height 222 if totalHeaders > maxBlockHeadersPerMsg { 223 totalHeaders = maxBlockHeadersPerMsg 224 } 225 226 headers := []*types.BlockHeader{} 227 for i := uint64(1); i <= totalHeaders; i++ { 228 header, err := bk.chain.GetHeaderByHeight(startHeader.Height + i) 229 if err != nil { 230 return nil, err 231 } 232 233 headers = append(headers, header) 234 } 235 return headers, nil 236 } 237 238 func (bk *blockKeeper) nextCheckpoint() *consensus.Checkpoint { 239 height := bk.chain.BestBlockHeader().Height 240 checkpoints := consensus.ActiveNetParams.Checkpoints 241 if len(checkpoints) == 0 || height >= checkpoints[len(checkpoints)-1].Height { 242 return nil 243 } 244 245 nextCheckpoint := &checkpoints[len(checkpoints)-1] 246 for i := len(checkpoints) - 2; i >= 0; i-- { 247 if height >= checkpoints[i].Height { 248 break 249 } 250 nextCheckpoint = &checkpoints[i] 251 } 252 return nextCheckpoint 253 } 254 255 func (bk *blockKeeper) processBlock(peerID string, block *types.Block) { 256 bk.blockProcessCh <- &blockMsg{block: block, peerID: peerID} 257 } 258 259 func (bk *blockKeeper) processBlocks(peerID string, blocks []*types.Block) { 260 bk.blocksProcessCh <- &blocksMsg{blocks: blocks, peerID: peerID} 261 } 262 263 func (bk *blockKeeper) processHeaders(peerID string, headers []*types.BlockHeader) { 264 bk.headersProcessCh <- &headersMsg{headers: headers, peerID: peerID} 265 } 266 267 func (bk *blockKeeper) regularBlockSync(wantHeight uint64) error { 268 i := bk.chain.BestBlockHeight() + 1 269 for i <= wantHeight { 270 block, err := bk.requireBlock(i) 271 if err != nil { 272 return err 273 } 274 275 isOrphan, err := bk.chain.ProcessBlock(block) 276 if err != nil { 277 return err 278 } 279 280 if isOrphan { 281 i-- 282 continue 283 } 284 i = bk.chain.BestBlockHeight() + 1 285 } 286 return nil 287 } 288 289 func (bk *blockKeeper) requireBlock(height uint64) (*types.Block, error) { 290 if ok := bk.syncPeer.getBlockByHeight(height); !ok { 291 return nil, errPeerDropped 292 } 293 294 timeout := time.NewTimer(syncTimeout) 295 defer timeout.Stop() 296 297 for { 298 select { 299 case msg := <-bk.blockProcessCh: 300 if msg.peerID != bk.syncPeer.ID() { 301 continue 302 } 303 if msg.block.Height != height { 304 continue 305 } 306 return msg.block, nil 307 case <-timeout.C: 308 return nil, errors.Wrap(errRequestTimeout, "requireBlock") 309 } 310 } 311 } 312 313 func (bk *blockKeeper) requireBlocks(locator []*bc.Hash, stopHash *bc.Hash) ([]*types.Block, error) { 314 if ok := bk.syncPeer.getBlocks(locator, stopHash); !ok { 315 return nil, errPeerDropped 316 } 317 318 timeout := time.NewTimer(syncTimeout) 319 defer timeout.Stop() 320 321 for { 322 select { 323 case msg := <-bk.blocksProcessCh: 324 if msg.peerID != bk.syncPeer.ID() { 325 continue 326 } 327 return msg.blocks, nil 328 case <-timeout.C: 329 return nil, errors.Wrap(errRequestTimeout, "requireBlocks") 330 } 331 } 332 } 333 334 func (bk *blockKeeper) requireHeaders(locator []*bc.Hash, stopHash *bc.Hash) ([]*types.BlockHeader, error) { 335 if ok := bk.syncPeer.getHeaders(locator, stopHash); !ok { 336 return nil, errPeerDropped 337 } 338 339 timeout := time.NewTimer(syncTimeout) 340 defer timeout.Stop() 341 342 for { 343 select { 344 case msg := <-bk.headersProcessCh: 345 if msg.peerID != bk.syncPeer.ID() { 346 continue 347 } 348 return msg.headers, nil 349 case <-timeout.C: 350 return nil, errors.Wrap(errRequestTimeout, "requireHeaders") 351 } 352 } 353 } 354 355 // resetHeaderState sets the headers-first mode state to values appropriate for 356 // syncing from a new peer. 357 func (bk *blockKeeper) resetHeaderState() { 358 header := bk.chain.BestBlockHeader() 359 bk.headerList.Init() 360 if bk.nextCheckpoint() != nil { 361 bk.headerList.PushBack(header) 362 } 363 } 364 365 func (bk *blockKeeper) startSync() bool { 366 checkPoint := bk.nextCheckpoint() 367 peer := bk.peers.bestPeer(consensus.SFFastSync | consensus.SFFullNode) 368 if peer != nil && checkPoint != nil && peer.Height() >= checkPoint.Height { 369 bk.syncPeer = peer 370 if err := bk.fastBlockSync(checkPoint); err != nil { 371 log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on fastBlockSync") 372 bk.peers.ProcessIllegal(peer.ID(), security.LevelMsgIllegal, err.Error()) 373 return false 374 } 375 return true 376 } 377 378 blockHeight := bk.chain.BestBlockHeight() 379 peer = bk.peers.bestPeer(consensus.SFFullNode) 380 if peer != nil && peer.Height() > blockHeight { 381 bk.syncPeer = peer 382 targetHeight := blockHeight + maxBlockPerMsg 383 if targetHeight > peer.Height() { 384 targetHeight = peer.Height() 385 } 386 387 if err := bk.regularBlockSync(targetHeight); err != nil { 388 log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on regularBlockSync") 389 bk.peers.ProcessIllegal(peer.ID(), security.LevelMsgIllegal, err.Error()) 390 return false 391 } 392 return true 393 } 394 return false 395 } 396 397 func (bk *blockKeeper) syncWorker() { 398 genesisBlock, err := bk.chain.GetBlockByHeight(0) 399 if err != nil { 400 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on handleStatusRequestMsg get genesis") 401 return 402 } 403 syncTicker := time.NewTicker(syncCycle) 404 defer syncTicker.Stop() 405 406 for { 407 <-syncTicker.C 408 if update := bk.startSync(); !update { 409 continue 410 } 411 412 block, err := bk.chain.GetBlockByHeight(bk.chain.BestBlockHeight()) 413 if err != nil { 414 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker get best block") 415 } 416 417 if err := bk.peers.broadcastMinedBlock(block); err != nil { 418 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new block") 419 } 420 421 if err = bk.peers.broadcastNewStatus(block, genesisBlock); err != nil { 422 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new status") 423 } 424 } 425 }