github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/netsync/consensusmgr/block_fetcher.go (about) 1 package consensusmgr 2 3 import ( 4 log "github.com/sirupsen/logrus" 5 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 6 7 "github.com/bytom/bytom/p2p/security" 8 "github.com/bytom/bytom/protocol/bc" 9 ) 10 11 const ( 12 maxBlockDistance = 64 13 newBlockChSize = 64 14 msgLimit = 128 // peer message number limit 15 ) 16 17 // blockFetcher is responsible for accumulating block announcements from various peers 18 // and scheduling them for retrieval. 19 type blockFetcher struct { 20 chain Chain 21 peers Peers 22 23 newBlockCh chan *blockMsg 24 queue *prque.Prque // block import priority queue 25 msgSet map[bc.Hash]*blockMsg // already queued blocks 26 msgCounter map[string]int // per peer msg counter to prevent DOS 27 } 28 29 //NewBlockFetcher creates a block fetcher to retrieve blocks of the new propose. 30 func newBlockFetcher(chain Chain, peers Peers) *blockFetcher { 31 return &blockFetcher{ 32 chain: chain, 33 peers: peers, 34 newBlockCh: make(chan *blockMsg, newBlockChSize), 35 queue: prque.New(), 36 msgSet: make(map[bc.Hash]*blockMsg), 37 msgCounter: make(map[string]int), 38 } 39 } 40 41 func (f *blockFetcher) blockProcessorLoop() { 42 for { 43 for !f.queue.Empty() { 44 msg := f.queue.PopItem().(*blockMsg) 45 if msg.block.Height > f.chain.BestBlockHeight()+1 { 46 f.queue.Push(msg, -float32(msg.block.Height)) 47 break 48 } 49 50 f.insert(msg) 51 delete(f.msgSet, msg.block.Hash()) 52 f.msgCounter[msg.peerID]-- 53 if f.msgCounter[msg.peerID] <= 0 { 54 delete(f.msgCounter, msg.peerID) 55 } 56 } 57 f.add(<-f.newBlockCh, msgLimit) 58 } 59 } 60 61 func (f *blockFetcher) add(msg *blockMsg, limit int) { 62 // prevent DOS 63 count := f.msgCounter[msg.peerID] + 1 64 if count > limit { 65 log.WithFields(log.Fields{"module": logModule, "peer": msg.peerID, "limit": limit}).Warn("The number of peer messages exceeds the limit") 66 return 67 } 68 69 bestHeight := f.chain.BestBlockHeight() 70 if bestHeight > msg.block.Height || msg.block.Height-bestHeight > maxBlockDistance { 71 return 72 } 73 74 blockHash := msg.block.Hash() 75 if _, ok := f.msgSet[blockHash]; !ok { 76 f.msgSet[blockHash] = msg 77 f.queue.Push(msg, -float32(msg.block.Height)) 78 f.msgCounter[msg.peerID] = count 79 log.WithFields(log.Fields{ 80 "module": logModule, 81 "block height": msg.block.Height, 82 "block hash": blockHash.String(), 83 }).Debug("blockFetcher receive propose block") 84 } 85 } 86 87 func (f *blockFetcher) insert(msg *blockMsg) { 88 isOrphan, err := f.chain.ProcessBlock(msg.block) 89 if err != nil { 90 peer := f.peers.GetPeer(msg.peerID) 91 if peer == nil { 92 return 93 } 94 f.peers.ProcessIllegal(msg.peerID, security.LevelMsgIllegal, err.Error()) 95 return 96 } 97 98 if isOrphan { 99 return 100 } 101 102 proposeMsg, err := NewBlockProposeMsg(msg.block) 103 if err != nil { 104 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("failed on create BlockProposeMsg") 105 return 106 } 107 108 if err := f.peers.BroadcastMsg(NewBroadcastMsg(proposeMsg, consensusChannel)); err != nil { 109 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("failed on broadcast proposed block") 110 return 111 } 112 } 113 114 func (f *blockFetcher) processNewBlock(msg *blockMsg) { 115 f.newBlockCh <- msg 116 }