github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/p2pstore/handler.go (about) 1 package p2pstore 2 3 import ( 4 "encoding/hex" 5 "sync/atomic" 6 "time" 7 8 "github.com/turingchain2020/turingchain/queue" 9 "github.com/turingchain2020/turingchain/system/p2p/dht/protocol" 10 types2 "github.com/turingchain2020/turingchain/system/p2p/dht/types" 11 "github.com/turingchain2020/turingchain/types" 12 "github.com/libp2p/go-libp2p-core/network" 13 kb "github.com/libp2p/go-libp2p-kbucket" 14 ) 15 16 func (p *Protocol) handleStreamIsFullNode(resp *types.P2PResponse) error { 17 resp.Response = &types.P2PResponse_NodeInfo{ 18 NodeInfo: &types.NodeInfo{ 19 Answer: p.SubConfig.IsFullNode, 20 Height: p.PeerInfoManager.PeerHeight(p.Host.ID()), 21 }, 22 } 23 return nil 24 } 25 26 func (p *Protocol) handleStreamFetchShardPeers(req *types.P2PRequest, res *types.P2PResponse) error { 27 reqPeers := req.GetRequest().(*types.P2PRequest_ReqPeers).ReqPeers 28 count := reqPeers.Count 29 if count <= 0 { 30 count = int32(backup) 31 } 32 closerPeers := p.ShardHealthyRoutingTable.NearestPeers(genDHTID(reqPeers.ReferKey), int(count)) 33 for _, pid := range closerPeers { 34 var addrs [][]byte 35 for _, addr := range p.Host.Peerstore().Addrs(pid) { 36 addrs = append(addrs, addr.Bytes()) 37 } 38 res.CloserPeers = append(res.CloserPeers, &types.PeerInfo{ 39 ID: []byte(pid), 40 MultiAddr: addrs, 41 }) 42 } 43 return nil 44 } 45 46 func (p *Protocol) handleStreamFetchChunk(stream network.Stream) { 47 var req types.P2PRequest 48 if err := protocol.ReadStreamAndAuthenticate(&req, stream); err != nil { 49 return 50 } 51 param := req.Request.(*types.P2PRequest_ChunkInfoMsg).ChunkInfoMsg 52 var res types.P2PResponse 53 var bodys *types.BlockBodys 54 var err error 55 defer func() { 56 t := time.Now() 57 writeBodys(bodys, stream) 58 _ = protocol.WriteStream(&res, stream) 59 log.Info("handleStreamFetchChunk", "chunk hash", hex.EncodeToString(param.ChunkHash), "start", param.Start, "remote peer", stream.Conn().RemotePeer(), "addrs", stream.Conn().RemoteMultiaddr(), "time cost", time.Since(t)) 60 }() 61 62 // 全节点模式,只有网络中出现数据丢失时才提供数据 63 if p.SubConfig.IsFullNode { 64 hexHash := hex.EncodeToString(param.ChunkHash) 65 if _, ok := p.chunkWhiteList.Load(hexHash); !ok { //该chunk不在白名单里 66 if pid, ok := p.checkChunkInNetwork(param); ok { 67 //网络中可以查到数据,不应该到全节点来要数据 68 var addrs [][]byte 69 for _, addr := range p.Host.Peerstore().Addrs(pid) { 70 addrs = append(addrs, addr.Bytes()) 71 } 72 res.CloserPeers = []*types.PeerInfo{{ID: []byte(pid), MultiAddr: addrs}} 73 return 74 } 75 76 //该chunk添加到白名单,10分钟内无条件提供数据 77 p.chunkWhiteList.Store(hexHash, time.Now()) 78 //分片网络中出现数据丢失,备份该chunk到分片网络中 79 go func() { 80 chunkInfo, ok := p.getChunkInfoByHash(param.ChunkHash) 81 if !ok { 82 log.Error("HandleStreamFetchChunk chunkInfo not found", "chunk hash", hexHash) 83 return 84 } 85 p.notifyStoreChunk(chunkInfo.ChunkInfoMsg) 86 }() 87 88 } 89 bodys, err = p.getChunkBlock(param) 90 if err != nil { 91 res.Error = err.Error() 92 return 93 } 94 return 95 } 96 97 closerPeers := p.ShardHealthyRoutingTable.NearestPeers(genDHTID(param.ChunkHash), AlphaValue) 98 if len(closerPeers) != 0 && kb.Closer(p.Host.ID(), closerPeers[0], genChunkNameSpaceKey(param.ChunkHash)) { 99 closerPeers = p.ShardHealthyRoutingTable.NearestPeers(genDHTID(param.ChunkHash), backup-1) 100 } 101 for _, pid := range closerPeers { 102 if pid == p.Host.ID() { 103 continue 104 } 105 var addrs [][]byte 106 for _, addr := range p.Host.Peerstore().Addrs(pid) { 107 addrs = append(addrs, addr.Bytes()) 108 } 109 res.CloserPeers = append(res.CloserPeers, &types.PeerInfo{ 110 ID: []byte(pid), 111 MultiAddr: addrs, 112 }) 113 114 } 115 if atomic.LoadInt64(&p.concurrency) > maxConcurrency { 116 return 117 } 118 atomic.AddInt64(&p.concurrency, 1) 119 defer atomic.AddInt64(&p.concurrency, -1) 120 //分片节点模式,检查本地是否存在 121 bodys, err = p.getChunkBlock(param) 122 if err != nil { 123 res.Error = err.Error() 124 return 125 } 126 } 127 128 // 对端节点通知本节点保存数据 129 /* 130 检查点p2pStore是否保存了数据, 131 1)若已保存则只更新时间即可 132 2)若未保存则从网络中请求chunk数据 133 */ 134 func (p *Protocol) handleStreamStoreChunks(req *types.P2PRequest) { 135 param := req.Request.(*types.P2PRequest_ChunkInfoList).ChunkInfoList.Items 136 for _, info := range param { 137 chunkHash := hex.EncodeToString(info.ChunkHash) 138 //已有其他节点通知该节点保存该chunk,避免接收到多个节点的通知后重复查询数据 139 if _, ok := p.notifying.LoadOrStore(chunkHash, nil); ok { 140 continue 141 } 142 //检查本地 p2pStore,如果已存在数据则直接更新 143 if err := p.updateChunk(info); err == nil { 144 p.notifying.Delete(chunkHash) 145 continue 146 } 147 //send message to notifying queue to process 148 select { 149 case p.notifyingQueue <- info: 150 //drop the notify message if queue is full 151 default: 152 p.notifying.Delete(chunkHash) 153 } 154 } 155 } 156 157 func (p *Protocol) handleStreamGetHeader(req *types.P2PRequest, res *types.P2PResponse) error { 158 param := req.Request.(*types.P2PRequest_ReqBlocks) 159 msg := p.QueueClient.NewMessage("blockchain", types.EventGetHeaders, param.ReqBlocks) 160 err := p.QueueClient.Send(msg, true) 161 if err != nil { 162 return err 163 } 164 resp, err := p.QueueClient.Wait(msg) 165 if err != nil { 166 return err 167 } 168 169 if headers, ok := resp.GetData().(*types.Headers); ok { 170 res.Response = &types.P2PResponse_BlockHeaders{BlockHeaders: headers} 171 return nil 172 } 173 return types.ErrNotFound 174 } 175 176 func (p *Protocol) handleStreamGetHeaderOld(stream network.Stream) { 177 var req types.MessageHeaderReq 178 err := protocol.ReadStream(&req, stream) 179 if err != nil { 180 return 181 } 182 param := &types.ReqBlocks{ 183 Start: req.Message.StartHeight, 184 End: req.Message.EndHeight, 185 } 186 msg := p.QueueClient.NewMessage("blockchain", types.EventGetHeaders, param) 187 err = p.QueueClient.Send(msg, true) 188 if err != nil { 189 return 190 } 191 resp, err := p.QueueClient.Wait(msg) 192 if err != nil { 193 return 194 } 195 196 if headers, ok := resp.GetData().(*types.Headers); ok { 197 err = protocol.WriteStream(&types.MessageHeaderResp{ 198 Message: &types.P2PHeaders{ 199 Headers: headers.Items, 200 }, 201 }, stream) 202 if err != nil { 203 return 204 } 205 } 206 207 } 208 209 func (p *Protocol) handleStreamGetChunkRecord(req *types.P2PRequest, res *types.P2PResponse) error { 210 param := req.Request.(*types.P2PRequest_ReqChunkRecords).ReqChunkRecords 211 records, err := p.getChunkRecordFromBlockchain(param) 212 if err != nil { 213 return err 214 } 215 res.Response = &types.P2PResponse_ChunkRecords{ChunkRecords: records} 216 return nil 217 } 218 219 //handleEventNotifyStoreChunk handles notification of blockchain, 220 // store chunk if this node is the nearest *count* node in the local routing table. 221 func (p *Protocol) handleEventNotifyStoreChunk(m *queue.Message) { 222 req := m.GetData().(*types.ChunkInfoMsg) 223 var err error 224 defer func() { 225 m.Reply(p.QueueClient.NewMessage("blockchain", 0, &types.Reply{ 226 IsOk: err == nil, 227 })) 228 }() 229 if p.SubConfig.IsFullNode { 230 //全节点保存所有chunk, blockchain模块通知保存chunk时直接保存到本地 231 if err = p.storeChunk(req); err != nil { 232 log.Error("HandleEventNotifyStoreChunk", "storeChunk error", err) 233 } 234 return 235 } 236 237 //如果本节点是本地路由表中距离该chunk最近的节点,则保存数据;否则不需要保存数据 238 tmpRoutingTable := p.genTempRoutingTable(req.ChunkHash, backup) 239 pid := tmpRoutingTable.NearestPeer(genDHTID(req.ChunkHash)) 240 if pid != "" && kb.Closer(pid, p.Host.ID(), genChunkNameSpaceKey(req.ChunkHash)) { 241 return 242 } 243 log.Info("handleEventNotifyStoreChunk", "local nearest peer", p.Host.ID(), "chunk hash", hex.EncodeToString(req.ChunkHash)) 244 err = p.checkNetworkAndStoreChunk(req) 245 if err != nil { 246 log.Error("storeChunk", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "end", req.End, "error", err) 247 return 248 } 249 } 250 251 func (p *Protocol) handleEventGetChunkBlock(m *queue.Message) { 252 req := m.GetData().(*types.ChunkInfoMsg) 253 bodys, _, err := p.getChunk(req) 254 if err != nil { 255 log.Error("GetChunkBlock", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "end", req.End, "error", err) 256 return 257 } 258 headers, _ := p.getHeaders(&types.ReqBlocks{Start: req.Start, End: req.End}) 259 if headers == nil { 260 log.Error("GetBlockHeader", "error", types2.ErrNotFound) 261 return 262 } 263 if len(headers.Items) != len(bodys.Items) { 264 log.Error("GetBlockHeader", "error", types2.ErrLength, "header length", len(headers.Items), "body length", len(bodys.Items), "start", req.Start, "end", req.End) 265 return 266 } 267 268 var blockList []*types.Block 269 for index := range bodys.Items { 270 body := bodys.Items[index] 271 header := headers.Items[index] 272 block := &types.Block{ 273 Version: header.Version, 274 ParentHash: header.ParentHash, 275 TxHash: header.TxHash, 276 StateHash: header.StateHash, 277 Height: header.Height, 278 BlockTime: header.BlockTime, 279 Difficulty: header.Difficulty, 280 MainHash: body.MainHash, 281 MainHeight: body.MainHeight, 282 Signature: header.Signature, 283 Txs: body.Txs, 284 } 285 blockList = append(blockList, block) 286 } 287 msg := p.QueueClient.NewMessage("blockchain", types.EventAddChunkBlock, &types.Blocks{Items: blockList}) 288 err = p.QueueClient.Send(msg, false) 289 if err != nil { 290 log.Error("EventGetChunkBlock", "reply message error", err) 291 return 292 } 293 log.Info("GetChunkBlock", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "end", req.End) 294 } 295 296 func (p *Protocol) handleEventGetChunkBlockBody(m *queue.Message) { 297 req := m.GetData().(*types.ChunkInfoMsg) 298 blockBodys, _, err := p.getChunk(req) 299 if err != nil { 300 log.Error("GetChunkBlockBody", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "end", req.End, "error", err) 301 m.ReplyErr("", err) 302 return 303 } 304 m.Reply(&queue.Message{Data: blockBodys}) 305 } 306 307 func (p *Protocol) handleEventGetChunkRecord(m *queue.Message) { 308 req := m.GetData().(*types.ReqChunkRecords) 309 records := p.getChunkRecords(req) 310 if records == nil { 311 log.Error("handleEventGetChunkRecord", "getChunkRecords error", types2.ErrNotFound) 312 return 313 } 314 msg := p.QueueClient.NewMessage("blockchain", types.EventAddChunkRecord, records) 315 err := p.QueueClient.Send(msg, false) 316 if err != nil { 317 log.Error("handleEventGetChunkRecord", "reply message error", err) 318 } 319 } 320 321 func (p *Protocol) handleEventGetHeaders(m *queue.Message) { 322 req := m.GetData().(*types.ReqBlocks) 323 if len(req.GetPid()) == 0 { //根据指定的pidlist 获取对应的block header 324 log.Debug("GetHeaders:pid is nil") 325 m.Reply(p.QueueClient.NewMessage("blockchain", types.EventReply, types.Reply{Msg: []byte("no pid")})) 326 return 327 } 328 m.Reply(p.QueueClient.NewMessage("blockchain", types.EventReply, types.Reply{IsOk: true, Msg: []byte("ok")})) 329 headers, pid := p.getHeadersOld(req) 330 if headers == nil || len(headers.Items) == 0 { 331 return 332 } 333 msg := p.QueueClient.NewMessage("blockchain", types.EventAddBlockHeaders, &types.HeadersPid{Pid: pid.Pretty(), Headers: headers}) 334 err := p.QueueClient.Send(msg, true) 335 if err != nil { 336 log.Error("handleEventGetHeaders", "send message error", err) 337 return 338 } 339 _, _ = p.QueueClient.Wait(msg) 340 } 341 342 func writeBodys(bodys *types.BlockBodys, stream network.Stream) { 343 if bodys == nil { 344 return 345 } 346 var data types.P2PResponse 347 for _, body := range bodys.Items { 348 data.Response = &types.P2PResponse_BlockBody{ 349 BlockBody: body, 350 } 351 if err := protocol.WriteStream(&data, stream); err != nil { 352 return 353 } 354 } 355 }