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  }