github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/download/download.go (about)

     1  package download
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/turingchain2020/turingchain/common/log/log15"
     9  	"github.com/turingchain2020/turingchain/system/p2p/dht/protocol"
    10  	"github.com/turingchain2020/turingchain/types"
    11  	"github.com/libp2p/go-libp2p-core/peer"
    12  )
    13  
    14  var (
    15  	log = log15.New("module", "p2p.download")
    16  )
    17  
    18  func init() {
    19  	protocol.RegisterProtocolInitializer(InitProtocol)
    20  }
    21  
    22  const (
    23  	// Deprecated: old version, use downloadBlock instead
    24  	downloadBlockOld = "/turingchain/downloadBlockReq/1.0.0"
    25  	downloadBlock    = "/turingchain/download-block/1.0.0"
    26  )
    27  
    28  // Protocol ...
    29  type Protocol struct {
    30  	*protocol.P2PEnv
    31  }
    32  
    33  // InitProtocol initials protocol
    34  func InitProtocol(env *protocol.P2PEnv) {
    35  	p := &Protocol{
    36  		P2PEnv: env,
    37  	}
    38  	//注册p2p通信协议,用于处理节点之间请求
    39  	protocol.RegisterStreamHandler(p.Host, downloadBlockOld, p.handleStreamDownloadBlockOld)
    40  	protocol.RegisterStreamHandler(p.Host, downloadBlock, p.handleStreamDownloadBlock)
    41  	//注册事件处理函数
    42  	protocol.RegisterEventHandler(types.EventFetchBlocks, p.handleEventDownloadBlock)
    43  
    44  }
    45  
    46  func (p *Protocol) downloadBlock(height int64, tasks tasks) error {
    47  
    48  	var retryCount uint
    49  	tasks.Sort() //对任务节点时延进行排序,优先选择时延低的节点进行下载
    50  ReDownload:
    51  	select {
    52  	case <-p.Ctx.Done():
    53  		log.Warn("downloadBlock", "process", "done")
    54  		return p.Ctx.Err()
    55  	default:
    56  		break
    57  	}
    58  
    59  	if tasks.Size() == 0 {
    60  		return errors.New("no peer for download")
    61  	}
    62  
    63  	retryCount++
    64  	if retryCount > 50 {
    65  		return errors.New("beyound max try count 50")
    66  	}
    67  
    68  	task := p.availbTask(tasks, height)
    69  	if task == nil {
    70  		time.Sleep(time.Millisecond * 400)
    71  		goto ReDownload
    72  	}
    73  
    74  	var downloadStart = time.Now().UnixNano()
    75  	block, err := p.downloadBlockFromPeerOld(height, task.Pid)
    76  	if err != nil {
    77  		log.Error("handleEventDownloadBlock", "SendRecvPeer", err, "pid", task.Pid)
    78  		p.releaseJob(task)
    79  		tasks = tasks.Remove(task)
    80  		goto ReDownload
    81  	}
    82  	remotePid := task.Pid.Pretty()
    83  	costTime := (time.Now().UnixNano() - downloadStart) / 1e6
    84  
    85  	log.Debug("download+++++", "from", remotePid, "height", block.GetHeight(),
    86  		"blockSize (bytes)", block.Size(), "costTime ms", costTime)
    87  
    88  	msg := p.QueueClient.NewMessage("blockchain", types.EventSyncBlock, &types.BlockPid{Pid: remotePid, Block: block}) //加入到输出通道)
    89  	_ = p.QueueClient.Send(msg, false)
    90  	p.releaseJob(task)
    91  
    92  	return nil
    93  }
    94  
    95  func (p *Protocol) downloadBlockFromPeer(height int64, pid peer.ID) (*types.Block, error) {
    96  	ctx, cancel := context.WithTimeout(p.Ctx, time.Second*10)
    97  	defer cancel()
    98  	stream, err := p.Host.NewStream(ctx, pid, downloadBlock)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	defer protocol.CloseStream(stream)
   103  	blockReq := &types.ReqBlocks{Start: height, End: height}
   104  	err = protocol.WriteStream(blockReq, stream)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	var block types.Block
   109  	err = protocol.ReadStream(&block, stream)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	return &block, nil
   114  }
   115  
   116  func (p *Protocol) downloadBlockFromPeerOld(height int64, pid peer.ID) (*types.Block, error) {
   117  	ctx, cancel := context.WithTimeout(p.Ctx, time.Second*10)
   118  	defer cancel()
   119  	stream, err := p.Host.NewStream(ctx, pid, downloadBlockOld)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	defer protocol.CloseStream(stream)
   124  	blockReq := types.MessageGetBlocksReq{
   125  		Message: &types.P2PGetBlocks{
   126  			StartHeight: height,
   127  			EndHeight:   height,
   128  		},
   129  	}
   130  	err = protocol.WriteStream(&blockReq, stream)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	var resp types.MessageGetBlocksResp
   135  	err = protocol.ReadStream(&resp, stream)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	block := resp.Message.Items[0].Value.(*types.InvData_Block).Block
   140  	return block, nil
   141  }