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  }