github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/p2pstore/query.go (about) 1 package p2pstore 2 3 import ( 4 "context" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "math/rand" 9 "time" 10 11 "github.com/turingchain2020/turingchain/common" 12 "github.com/turingchain2020/turingchain/system/p2p/dht/protocol" 13 types2 "github.com/turingchain2020/turingchain/system/p2p/dht/types" 14 "github.com/turingchain2020/turingchain/types" 15 "github.com/libp2p/go-libp2p-core/peer" 16 "github.com/libp2p/go-libp2p-core/peerstore" 17 "github.com/multiformats/go-multiaddr" 18 ) 19 20 func (p *Protocol) fetchCloserPeers(key []byte, count int, pid peer.ID) ([]peer.ID, error) { 21 ctx, cancel := context.WithTimeout(p.Ctx, time.Second*3) 22 defer cancel() 23 p.Host.ConnManager().Protect(pid, fetchShardPeer) 24 defer p.Host.ConnManager().Unprotect(pid, fetchShardPeer) 25 stream, err := p.Host.NewStream(ctx, pid, fetchShardPeer) 26 if err != nil { 27 return nil, err 28 } 29 defer protocol.CloseStream(stream) 30 req := types.P2PRequest{ 31 Request: &types.P2PRequest_ReqPeers{ 32 ReqPeers: &types.ReqPeers{ 33 ReferKey: key, 34 Count: int32(count), 35 }, 36 }, 37 } 38 if err = protocol.WriteStream(&req, stream); err != nil { 39 return nil, err 40 } 41 var resp types.P2PResponse 42 if err = protocol.ReadStream(&resp, stream); err != nil { 43 return nil, err 44 } 45 closerPeers := saveCloserPeers(resp.CloserPeers, p.Host.Peerstore()) 46 return closerPeers, nil 47 } 48 49 //getChunk gets chunk data from p2pStore or other peers. 50 func (p *Protocol) getChunk(req *types.ChunkInfoMsg) (*types.BlockBodys, peer.ID, error) { 51 if req == nil { 52 return nil, "", types2.ErrInvalidParam 53 } 54 //优先获取本地p2pStore数据 55 bodys, _ := p.getChunkBlock(req) 56 if bodys != nil { 57 return bodys, p.Host.ID(), nil 58 } 59 //本地数据不存在或已过期,则向临近节点查询 60 return p.mustFetchChunk(p.Ctx, req, true) 61 } 62 63 func (p *Protocol) getHeadersOld(param *types.ReqBlocks) (*types.Headers, peer.ID) { 64 req := types.P2PGetHeaders{ 65 StartHeight: param.Start, 66 EndHeight: param.End, 67 } 68 for _, peerID := range param.Pid { 69 pid, err := peer.Decode(peerID) 70 if err != nil { 71 log.Error("getHeaders", "decode pid error", err) 72 continue 73 } 74 headers, err := p.getHeadersFromPeerOld(&req, pid) 75 if err != nil { 76 continue 77 } 78 return headers, pid 79 } 80 return nil, "" 81 } 82 83 func (p *Protocol) getHeadersFromPeerOld(req *types.P2PGetHeaders, pid peer.ID) (*types.Headers, error) { 84 p.Host.ConnManager().Protect(pid, getHeaderOld) 85 defer p.Host.ConnManager().Unprotect(pid, getHeaderOld) 86 stream, err := p.Host.NewStream(p.Ctx, pid, getHeaderOld) 87 if err != nil { 88 return nil, err 89 } 90 defer protocol.CloseStream(stream) 91 err = protocol.WriteStream(&types.MessageHeaderReq{ 92 Message: req, 93 }, stream) 94 if err != nil { 95 return nil, err 96 } 97 var resp types.MessageHeaderResp 98 err = protocol.ReadStream(&resp, stream) 99 if err != nil { 100 return nil, err 101 } 102 return &types.Headers{ 103 Items: resp.Message.Headers, 104 }, nil 105 } 106 107 func (p *Protocol) getHeaders(param *types.ReqBlocks) (*types.Headers, peer.ID) { 108 for _, peerID := range param.Pid { 109 pid, err := peer.Decode(peerID) 110 if err != nil { 111 log.Error("getHeaders", "decode pid error", err) 112 continue 113 } 114 headers, err := p.getHeadersFromPeer(param, pid) 115 if err != nil { 116 log.Error("getHeaders", "peer", pid, "error", err) 117 continue 118 } 119 return headers, pid 120 } 121 122 if len(param.Pid) != 0 { 123 return nil, "" 124 } 125 126 for _, pid := range p.RoutingTable.ListPeers() { 127 headers, err := p.getHeadersFromPeer(param, pid) 128 if err != nil { 129 log.Error("getHeaders", "peer", pid, "error", err) 130 continue 131 } 132 return headers, pid 133 } 134 log.Error("getHeaders", "error", types2.ErrNotFound) 135 return nil, "" 136 } 137 138 func (p *Protocol) getHeadersFromPeer(param *types.ReqBlocks, pid peer.ID) (*types.Headers, error) { 139 childCtx, cancel := context.WithTimeout(p.Ctx, 30*time.Second) 140 defer cancel() 141 p.Host.ConnManager().Protect(pid, getHeader) 142 defer p.Host.ConnManager().Unprotect(pid, getHeader) 143 stream, err := p.Host.NewStream(childCtx, pid, getHeader) 144 if err != nil { 145 return nil, err 146 } 147 defer protocol.CloseStream(stream) 148 msg := types.P2PRequest{ 149 Request: &types.P2PRequest_ReqBlocks{ 150 ReqBlocks: param, 151 }, 152 } 153 err = protocol.SignAndWriteStream(&msg, stream) 154 if err != nil { 155 log.Error("getHeadersFromPeer", "SignAndWriteStream error", err) 156 return nil, err 157 } 158 var res types.P2PResponse 159 err = protocol.ReadStreamAndAuthenticate(&res, stream) 160 if err != nil { 161 return nil, err 162 } 163 if res.Error != "" { 164 return nil, errors.New(res.Error) 165 } 166 return res.Response.(*types.P2PResponse_BlockHeaders).BlockHeaders, nil 167 } 168 169 func (p *Protocol) getChunkRecords(param *types.ReqChunkRecords) *types.ChunkRecords { 170 // 从多个节点请求ChunkRecords, 并从中选择多数节点返回的数据 171 recordsCache := make(map[string]*types.ChunkRecords) 172 recordsCount := make(map[string]int) 173 for i, pid := range p.ShardHealthyRoutingTable.ListPeers() { 174 records, err := p.getChunkRecordsFromPeer(param, pid) 175 if err != nil { 176 log.Error("getChunkRecords", "peer", pid, "error", err, "start", param.Start, "end", param.End) 177 continue 178 } 179 sum := common.Sha256(types.Encode(records)) 180 recordsCache[string(sum)] = records 181 recordsCount[string(sum)]++ 182 log.Info("getChunkRecords", "peer", pid, "start", param.Start, "end", param.End) 183 if i > 10 && len(recordsCount) != 0 { 184 break 185 } 186 } 187 var records *types.ChunkRecords 188 var maxCount int 189 for sum, count := range recordsCount { 190 if count > maxCount { 191 records = recordsCache[sum] 192 } 193 } 194 195 return records 196 } 197 198 func (p *Protocol) getChunkRecordsFromPeer(param *types.ReqChunkRecords, pid peer.ID) (*types.ChunkRecords, error) { 199 childCtx, cancel := context.WithTimeout(p.Ctx, 30*time.Second) 200 defer cancel() 201 p.Host.ConnManager().Protect(pid, getChunkRecord) 202 defer p.Host.ConnManager().Unprotect(pid, getChunkRecord) 203 stream, err := p.Host.NewStream(childCtx, pid, getChunkRecord) 204 if err != nil { 205 return nil, err 206 } 207 defer protocol.CloseStream(stream) 208 msg := types.P2PRequest{ 209 Request: &types.P2PRequest_ReqChunkRecords{ 210 ReqChunkRecords: param, 211 }, 212 } 213 err = protocol.SignAndWriteStream(&msg, stream) 214 if err != nil { 215 log.Error("getChunkRecordsFromPeer", "SignAndWriteStream error", err) 216 return nil, err 217 } 218 219 var res types.P2PResponse 220 err = protocol.ReadStreamAndAuthenticate(&res, stream) 221 if err != nil { 222 return nil, err 223 } 224 if res.Error != "" { 225 return nil, errors.New(res.Error) 226 } 227 return res.Response.(*types.P2PResponse_ChunkRecords).ChunkRecords, nil 228 } 229 230 //若网络中有节点保存了该chunk,该方法可以保证查询到 231 func (p *Protocol) mustFetchChunk(pctx context.Context, req *types.ChunkInfoMsg, queryFull bool) (*types.BlockBodys, peer.ID, error) { 232 //递归查询时间上限一小时 233 ctx, cancel := context.WithTimeout(pctx, time.Minute*5) 234 defer cancel() 235 236 //保存查询过的节点,防止重复查询 237 searchedPeers := make(map[peer.ID]struct{}) 238 searchedPeers[p.Host.ID()] = struct{}{} 239 peers := p.ShardHealthyRoutingTable.NearestPeers(genDHTID(req.ChunkHash), AlphaValue) 240 log.Info("into mustFetchChunk", "shard healthy peers len", p.ShardHealthyRoutingTable.Size(), "start", req.Start, "end", req.End) 241 for len(peers) != 0 { 242 var nearerPeers []peer.ID 243 var bodys *types.BlockBodys 244 var err error 245 for _, pid := range peers { 246 if _, ok := searchedPeers[pid]; ok { 247 continue 248 } 249 searchedPeers[pid] = struct{}{} 250 start := time.Now() 251 bodys, nearerPeers, err = p.fetchChunkFromPeer(ctx, req, pid) 252 if err != nil { 253 continue 254 } 255 if bodys != nil { 256 log.Info("mustFetchChunk found", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "pid", pid, "maddrs", p.Host.Peerstore().Addrs(pid), "time cost", time.Since(start)) 257 return bodys, pid, nil 258 } 259 break 260 } 261 peers = nearerPeers 262 } 263 264 log.Error("mustFetchChunk not found", "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start, "error", types2.ErrNotFound) 265 if !queryFull { 266 return nil, "", types2.ErrNotFound 267 } 268 //如果是分片节点没有在分片网络中找到数据,最后到全节点去请求数据 269 ctx2, cancel2 := context.WithTimeout(ctx, time.Second*10) 270 defer cancel2() 271 peerInfos, err := p.FindPeers(ctx2, fullNode) 272 if err != nil { 273 log.Error("mustFetchChunk", "Find full peers error", err) 274 return nil, "", types2.ErrNotFound 275 } 276 277 for addrInfo := range peerInfos { 278 if addrInfo.ID == p.Host.ID() { 279 continue 280 } 281 log.Info("mustFetchChunk", "pid", addrInfo.ID, "addrs", addrInfo.Addrs) 282 bodys, pid := p.fetchChunkFromFullPeer(ctx, req, addrInfo.ID) 283 if bodys == nil { 284 log.Error("mustFetchChunk from full node failed", "pid", addrInfo.ID, "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start) 285 continue 286 } 287 log.Info("mustFetchChunk from full node succeed", "pid", addrInfo.ID, "chunk hash", hex.EncodeToString(req.ChunkHash), "start", req.Start) 288 return bodys, pid, nil 289 } 290 291 return nil, "", types2.ErrNotFound 292 } 293 294 func (p *Protocol) fetchChunkFromPeer(ctx context.Context, params *types.ChunkInfoMsg, pid peer.ID) (*types.BlockBodys, []peer.ID, error) { 295 childCtx, cancel := context.WithTimeout(ctx, 3*time.Minute) 296 defer cancel() 297 p.Host.ConnManager().Protect(pid, fetchChunk) 298 defer p.Host.ConnManager().Unprotect(pid, fetchChunk) 299 stream, err := p.Host.NewStream(childCtx, pid, fetchChunk) 300 if err != nil { 301 log.Error("fetchChunkFromPeer", "error", err) 302 return nil, nil, err 303 } 304 defer protocol.CloseStream(stream) 305 msg := types.P2PRequest{ 306 Request: &types.P2PRequest_ChunkInfoMsg{ 307 ChunkInfoMsg: params, 308 }, 309 } 310 err = protocol.SignAndWriteStream(&msg, stream) 311 if err != nil { 312 log.Error("fetchChunkFromPeer", "SignAndWriteStream error", err) 313 return nil, nil, err 314 } 315 var bodys []*types.BlockBody 316 var res types.P2PResponse 317 for { 318 if err := protocol.ReadStream(&res, stream); err != nil { 319 log.Error("fetchChunkFromPeer", "ReadStream error", err) 320 return nil, nil, err 321 } 322 body, ok := res.Response.(*types.P2PResponse_BlockBody) 323 if !ok { 324 break 325 } 326 bodys = append(bodys, body.BlockBody) 327 } 328 closerPeers := saveCloserPeers(res.CloserPeers, p.Host.Peerstore()) 329 if int64(len(bodys)) == params.End-params.Start+1 { 330 return &types.BlockBodys{ 331 Items: bodys, 332 }, closerPeers, nil 333 } 334 335 if len(closerPeers) == 0 { 336 return nil, nil, fmt.Errorf(res.Error) 337 } 338 return nil, closerPeers, nil 339 } 340 341 func (p *Protocol) fetchChunkFromFullPeer(ctx context.Context, params *types.ChunkInfoMsg, pid peer.ID) (*types.BlockBodys, peer.ID) { 342 bodys, peers, err := p.fetchChunkFromPeer(ctx, params, pid) 343 if err != nil { 344 log.Error("fetchChunkFromFullPeer", "error", err) 345 return nil, "" 346 } 347 if bodys != nil { 348 return bodys, pid 349 } 350 for _, pid := range peers { 351 bodys, _, err = p.fetchChunkFromPeer(ctx, params, pid) 352 if err != nil { 353 log.Error("fetchChunkFromFullPeer 2", "error", err, "pid", pid) 354 continue 355 } 356 if bodys != nil { 357 return bodys, pid 358 } 359 } 360 return nil, "" 361 } 362 363 func (p *Protocol) checkChunkInNetwork(req *types.ChunkInfoMsg) (peer.ID, bool) { 364 ctx, cancel := context.WithTimeout(p.Ctx, time.Second*10) 365 defer cancel() 366 rand.Seed(time.Now().UnixNano()) 367 random := rand.Int63n(req.End-req.Start+1) + req.Start 368 req2 := &types.ChunkInfoMsg{ 369 ChunkHash: req.ChunkHash, 370 Start: random, 371 End: random, 372 } 373 //query a random block of the chunk, to make sure that the chunk exists in the extension. 374 _, pid, err := p.mustFetchChunk(ctx, req2, false) 375 return pid, err == nil 376 } 377 378 func (p *Protocol) storeChunk(req *types.ChunkInfoMsg) error { 379 380 //如果p2pStore已保存数据,只更新时间即可 381 if err := p.updateChunk(req); err == nil { 382 return nil 383 } 384 //blockchain通知p2pStore保存数据,则blockchain应该有数据 385 bodys, err := p.getChunkFromBlockchain(req) 386 if err != nil { 387 return err 388 } 389 err = p.addChunkBlock(req, bodys) 390 if err != nil { 391 return err 392 } 393 return nil 394 } 395 396 func (p *Protocol) checkNetworkAndStoreChunk(req *types.ChunkInfoMsg) error { 397 //先检查之前的chunk是否以在网络中查到 398 infos := p.getHistoryChunkInfos(req, 3) 399 for i := len(infos) - 1; i >= 0; i-- { 400 info := infos[i] 401 if _, ok := p.checkChunkInNetwork(info); ok { 402 infos = infos[i+1:] 403 break 404 } 405 } 406 infos = append(infos, req) 407 var err error 408 for _, info := range infos { 409 log.Info("checkNetworkAndStoreChunk storing", "chunk hash", hex.EncodeToString(info.ChunkHash), "start", info.Start) 410 if err = p.storeChunk(info); err != nil { 411 log.Error("checkNetworkAndStoreChunk", "store chunk error", err, "chunkhash", hex.EncodeToString(info.ChunkHash), "start", info.Start) 412 continue 413 } 414 //本地存储之后立即到其他节点做一次备份 415 p.notifyStoreChunk(req) 416 } 417 return err 418 } 419 420 func (p *Protocol) getChunkFromBlockchain(param *types.ChunkInfoMsg) (*types.BlockBodys, error) { 421 if param == nil { 422 return nil, types2.ErrInvalidParam 423 } 424 msg := p.QueueClient.NewMessage("blockchain", types.EventGetChunkBlockBody, param) 425 err := p.QueueClient.Send(msg, true) 426 if err != nil { 427 return nil, err 428 } 429 resp, err := p.QueueClient.Wait(msg) 430 if err != nil { 431 return nil, err 432 } 433 if bodys, ok := resp.GetData().(*types.BlockBodys); ok { 434 return bodys, nil 435 } 436 return nil, types2.ErrNotFound 437 } 438 439 func (p *Protocol) getChunkRecordFromBlockchain(req *types.ReqChunkRecords) (*types.ChunkRecords, error) { 440 if req == nil { 441 return nil, types2.ErrInvalidParam 442 } 443 msg := p.QueueClient.NewMessage("blockchain", types.EventGetChunkRecord, req) 444 err := p.QueueClient.Send(msg, true) 445 if err != nil { 446 return nil, err 447 } 448 resp, err := p.QueueClient.Wait(msg) 449 if err != nil { 450 return nil, err 451 } 452 if records, ok := resp.GetData().(*types.ChunkRecords); ok { 453 return records, nil 454 } 455 456 return nil, types2.ErrNotFound 457 } 458 459 func (p *Protocol) getHistoryChunkInfos(in *types.ChunkInfoMsg, count int64) []*types.ChunkInfoMsg { 460 chunkLen := in.End - in.Start + 1 461 req := &types.ReqChunkRecords{ 462 Start: in.Start/chunkLen - count, 463 End: in.Start/chunkLen - 1, 464 } 465 if req.End < 0 { 466 return nil 467 } 468 if req.Start < 0 { 469 req.Start = 0 470 } 471 records, err := p.getChunkRecordFromBlockchain(req) 472 if err != nil { 473 log.Error("getHistoryChunkRecords", "getChunkRecordFromBlockchain error", err, "start", req.Start, "end", req.End, "records", records) 474 return nil 475 } 476 var chunkInfos []*types.ChunkInfoMsg 477 for _, info := range records.Infos { 478 chunkInfos = append(chunkInfos, &types.ChunkInfoMsg{ 479 ChunkHash: info.ChunkHash, 480 Start: info.Start, 481 End: info.End, 482 }) 483 } 484 485 return chunkInfos 486 } 487 488 func saveCloserPeers(peerInfos []*types.PeerInfo, store peerstore.Peerstore) []peer.ID { 489 var peers []peer.ID 490 for _, peerInfo := range peerInfos { 491 if peerInfo == nil { 492 continue 493 } 494 var maddrs []multiaddr.Multiaddr 495 for _, addr := range peerInfo.MultiAddr { 496 maddr, err := multiaddr.NewMultiaddrBytes(addr) 497 if err != nil { 498 continue 499 } 500 maddrs = append(maddrs, maddr) 501 } 502 pid := peer.ID(peerInfo.ID) 503 store.AddAddrs(pid, maddrs, time.Minute*30) 504 peers = append(peers, pid) 505 } 506 return peers 507 }