github.com/aergoio/aergo@v1.3.1/p2p/syncmanager.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package p2p 7 8 import ( 9 "bytes" 10 "fmt" 11 "github.com/aergoio/aergo-lib/log" 12 "github.com/aergoio/aergo/chain" 13 "github.com/aergoio/aergo/internal/enc" 14 "github.com/aergoio/aergo/message" 15 "github.com/aergoio/aergo/p2p/p2pcommon" 16 "github.com/aergoio/aergo/p2p/p2putil" 17 "github.com/aergoio/aergo/types" 18 lru "github.com/hashicorp/golang-lru" 19 ) 20 21 type syncManager struct { 22 logger *log.Logger 23 actor p2pcommon.ActorService 24 pm p2pcommon.PeerManager 25 26 blkCache *lru.Cache 27 txCache *lru.Cache 28 } 29 30 type syncTask struct { 31 peer p2pcommon.RemotePeer 32 hashes []types.TxID 33 data *types.NewTransactionsNotice 34 } 35 36 func newSyncManager(actor p2pcommon.ActorService, pm p2pcommon.PeerManager, logger *log.Logger) p2pcommon.SyncManager { 37 var err error 38 sm := &syncManager{actor: actor, pm: pm, logger: logger} 39 40 sm.blkCache, err = lru.New(DefaultGlobalBlockCacheSize) 41 if err != nil { 42 panic("Failed to create p2p block cache" + err.Error()) 43 } 44 sm.txCache, err = lru.New(DefaultGlobalTxCacheSize) 45 if err != nil { 46 panic("Failed to create p2p tx cache " + err.Error()) 47 } 48 49 return sm 50 } 51 52 func (sm *syncManager) HandleBlockProducedNotice(peer p2pcommon.RemotePeer, block *types.Block) { 53 hash := types.MustParseBlockID(block.GetHash()) 54 ok, _ := sm.blkCache.ContainsOrAdd(hash, syncManagerChanSize) 55 if ok { 56 sm.logger.Warn().Str(p2putil.LogBlkHash, hash.String()).Str(p2putil.LogPeerName, peer.Name()).Msg("Duplicated blockProduced notice") 57 return 58 } 59 // check if block size is over the limit 60 if block.Size() > int(chain.MaxBlockSize()) { 61 sm.logger.Info().Str(p2putil.LogPeerName, peer.Name()).Str(p2putil.LogBlkHash, block.BlockID().String()).Int("size", block.Size()).Msg("invalid blockProduced notice. block size exceed limit") 62 return 63 } 64 65 sm.actor.SendRequest(message.ChainSvc, &message.AddBlock{PeerID: peer.ID(), Block: block, Bstate: nil}) 66 } 67 68 func (sm *syncManager) HandleNewBlockNotice(peer p2pcommon.RemotePeer, data *types.NewBlockNotice) { 69 hash := types.MustParseBlockID(data.BlockHash) 70 peerID := peer.ID() 71 //if !sm.checkWorkToken() { 72 // // just ignore it 73 // //sm.logger.Debug().Str(LogBlkHash, enc.ToString(data.BlockHash)).Str(LogPeerID, peerID.Pretty()).Msg("Ignoring newBlock notice sync syncManager is busy now.") 74 // return 75 //} 76 77 // TODO check if evicted return value is needed. 78 ok, _ := sm.blkCache.ContainsOrAdd(hash, cachePlaceHolder) 79 if ok { 80 // Kick out duplicated notice log. 81 // if sm.logger.IsDebugEnabled() { 82 // sm.logger.Debug().Str(LogBlkHash, enc.ToString(data.BlkHash)).Str(LogPeerID, peerID.Pretty()).Msg("Got NewBlock notice, but sent already from other peer") 83 // } 84 // this notice is already sent to chainservice 85 return 86 } 87 88 // request block info if selfnode does not have block already 89 foundBlock, _ := sm.actor.GetChainAccessor().GetBlock(data.BlockHash) 90 if foundBlock == nil { 91 sm.logger.Debug().Str(p2putil.LogBlkHash, enc.ToString(data.BlockHash)).Str(p2putil.LogPeerName, peer.Name()).Msg("new block notice of unknown hash. request back to notifier") 92 sm.actor.SendRequest(message.P2PSvc, &message.GetBlockInfos{ToWhom: peerID, 93 Hashes: []message.BlockHash{message.BlockHash(data.BlockHash)}}) 94 } 95 } 96 97 // HandleGetBlockResponse handle when remote peer send a block information. 98 // TODO this method will be removed after newer syncer is developed 99 func (sm *syncManager) HandleGetBlockResponse(peer p2pcommon.RemotePeer, msg p2pcommon.Message, resp *types.GetBlockResponse) { 100 blocks := resp.Blocks 101 peerID := peer.ID() 102 103 // The response should have only one block here, since this peer had requested only one block. 104 // getBlockResponse with bulky blocks is only called in newsyncer since aergosvr 0.9.9 , which is handled by other receiver and not come to this code. 105 // if bulky hashes on this condition block, it is probably sync timeout or bug. 106 if len(blocks) != 1 { 107 return 108 } 109 block := blocks[0] 110 // check if block size is over the limit 111 if block.Size() > int(chain.MaxBlockSize()) { 112 sm.logger.Info().Str(p2putil.LogPeerName, peer.Name()).Str(p2putil.LogBlkHash, block.BlockID().String()).Int("size", block.Size()).Msg("cancel to add block. block size exceed limit") 113 return 114 } 115 116 sm.actor.SendRequest(message.ChainSvc, &message.AddBlock{PeerID: peerID, Block: block, Bstate: nil}) 117 } 118 119 func (sm *syncManager) HandleNewTxNotice(peer p2pcommon.RemotePeer, hashes []types.TxID, data *types.NewTransactionsNotice) { 120 peerID := peer.ID() 121 122 // TODO it will cause problem if getTransaction failed. (i.e. remote peer was sent notice, but not response getTransaction) 123 toGet := make([]message.TXHash, 0, len(data.TxHashes)) 124 for _, hashArr := range hashes { 125 ok, _ := sm.txCache.ContainsOrAdd(hashArr, cachePlaceHolder) 126 if ok { 127 // Kickout duplicated notice log. 128 // if sm.logger.IsDebugEnabled() { 129 // sm.logger.Debug().Str(LogTxHash, enc.ToString(hashArr[:])).Str(LogPeerID, peerID.Pretty()).Msg("Got NewTx notice, but sent already from other peer") 130 // } 131 // this notice is already sent to chainservice 132 continue 133 } 134 hash := types.HashID(hashArr).Bytes() 135 toGet = append(toGet, hash) 136 } 137 if len(toGet) == 0 { 138 // sm.logger.Debug().Str(LogPeerID, peerID.Pretty()).Msg("No new tx found in tx notice") 139 return 140 } 141 sm.logger.Debug().Str("hashes", txHashArrToString(toGet)).Msg("syncManager request back unknown tx hashes") 142 // create message data 143 sm.actor.SendRequest(message.P2PSvc, &message.GetTransactions{ToWhom: peerID, Hashes: toGet}) 144 } 145 146 // bytesArrToString converts array of byte array to json array of b58 encoded string. 147 func txHashArrToString(bbarray []message.TXHash) string { 148 return txHashArrToStringWithLimit(bbarray, 10) 149 } 150 151 func txHashArrToStringWithLimit(bbarray []message.TXHash, limit int) string { 152 var buf bytes.Buffer 153 buf.WriteByte('[') 154 var arrSize = len(bbarray) 155 if limit > arrSize { 156 limit = arrSize 157 } 158 for i := 0; i < limit; i++ { 159 hash := bbarray[i] 160 buf.WriteByte('"') 161 buf.WriteString(enc.ToString([]byte(hash))) 162 buf.WriteByte('"') 163 buf.WriteByte(',') 164 } 165 if arrSize > limit { 166 buf.WriteString(fmt.Sprintf(" (and %d more), ", arrSize-limit)) 167 } 168 buf.WriteByte(']') 169 return buf.String() 170 }