github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/stream/delivery.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:43</date>
    10  //</624450115179909120>
    11  
    12  
    13  package stream
    14  
    15  import (
    16  	"context"
    17  	"errors"
    18  	"fmt"
    19  
    20  	"github.com/ethereum/go-ethereum/metrics"
    21  	"github.com/ethereum/go-ethereum/p2p/enode"
    22  	"github.com/ethereum/go-ethereum/swarm/log"
    23  	"github.com/ethereum/go-ethereum/swarm/network"
    24  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    25  	"github.com/ethereum/go-ethereum/swarm/storage"
    26  	opentracing "github.com/opentracing/opentracing-go"
    27  )
    28  
    29  const (
    30  	swarmChunkServerStreamName = "RETRIEVE_REQUEST"
    31  	deliveryCap                = 32
    32  )
    33  
    34  var (
    35  	processReceivedChunksCount    = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil)
    36  	handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil)
    37  	retrieveChunkFail             = metrics.NewRegisteredCounter("network.stream.retrieve_chunks_fail.count", nil)
    38  
    39  	requestFromPeersCount     = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil)
    40  	requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil)
    41  )
    42  
    43  type Delivery struct {
    44  	chunkStore storage.SyncChunkStore
    45  	kad        *network.Kademlia
    46  	getPeer    func(enode.ID) *Peer
    47  }
    48  
    49  func NewDelivery(kad *network.Kademlia, chunkStore storage.SyncChunkStore) *Delivery {
    50  	return &Delivery{
    51  		chunkStore: chunkStore,
    52  		kad:        kad,
    53  	}
    54  }
    55  
    56  //swarmchunkserver实现服务器
    57  type SwarmChunkServer struct {
    58  	deliveryC  chan []byte
    59  	batchC     chan []byte
    60  	chunkStore storage.ChunkStore
    61  	currentLen uint64
    62  	quit       chan struct{}
    63  }
    64  
    65  //newswarmchunkserver是swarmchunkserver构造函数
    66  func NewSwarmChunkServer(chunkStore storage.ChunkStore) *SwarmChunkServer {
    67  	s := &SwarmChunkServer{
    68  		deliveryC:  make(chan []byte, deliveryCap),
    69  		batchC:     make(chan []byte),
    70  		chunkStore: chunkStore,
    71  		quit:       make(chan struct{}),
    72  	}
    73  	go s.processDeliveries()
    74  	return s
    75  }
    76  
    77  //processDeliveries处理已传递的块散列
    78  func (s *SwarmChunkServer) processDeliveries() {
    79  	var hashes []byte
    80  	var batchC chan []byte
    81  	for {
    82  		select {
    83  		case <-s.quit:
    84  			return
    85  		case hash := <-s.deliveryC:
    86  			hashes = append(hashes, hash...)
    87  			batchC = s.batchC
    88  		case batchC <- hashes:
    89  			hashes = nil
    90  			batchC = nil
    91  		}
    92  	}
    93  }
    94  
    95  //对于swarmchunkserver,sessionindex在所有情况下都返回零。
    96  func (s *SwarmChunkServer) SessionIndex() (uint64, error) {
    97  	return 0, nil
    98  }
    99  
   100  //设置下一批
   101  func (s *SwarmChunkServer) SetNextBatch(_, _ uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) {
   102  	select {
   103  	case hashes = <-s.batchC:
   104  	case <-s.quit:
   105  		return
   106  	}
   107  
   108  	from = s.currentLen
   109  	s.currentLen += uint64(len(hashes))
   110  	to = s.currentLen
   111  	return
   112  }
   113  
   114  //需要在流服务器上调用Close
   115  func (s *SwarmChunkServer) Close() {
   116  	close(s.quit)
   117  }
   118  
   119  //GetData从数据库存储检索块数据
   120  func (s *SwarmChunkServer) GetData(ctx context.Context, key []byte) ([]byte, error) {
   121  	chunk, err := s.chunkStore.Get(ctx, storage.Address(key))
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	return chunk.Data(), nil
   126  }
   127  
   128  //retrieverequestmsg是块检索请求的协议msg
   129  type RetrieveRequestMsg struct {
   130  	Addr      storage.Address
   131  	SkipCheck bool
   132  	HopCount  uint8
   133  }
   134  
   135  func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error {
   136  	log.Trace("received request", "peer", sp.ID(), "hash", req.Addr)
   137  	handleRetrieveRequestMsgCount.Inc(1)
   138  
   139  	var osp opentracing.Span
   140  	ctx, osp = spancontext.StartSpan(
   141  		ctx,
   142  		"retrieve.request")
   143  	defer osp.Finish()
   144  
   145  	s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", true))
   146  	if err != nil {
   147  		return err
   148  	}
   149  	streamer := s.Server.(*SwarmChunkServer)
   150  
   151  	var cancel func()
   152  //TODO:用这个硬编码超时做点什么,将来可能使用TTL
   153  	ctx = context.WithValue(ctx, "peer", sp.ID().String())
   154  	ctx = context.WithValue(ctx, "hopcount", req.HopCount)
   155  	ctx, cancel = context.WithTimeout(ctx, network.RequestTimeout)
   156  
   157  	go func() {
   158  		select {
   159  		case <-ctx.Done():
   160  		case <-streamer.quit:
   161  		}
   162  		cancel()
   163  	}()
   164  
   165  	go func() {
   166  		chunk, err := d.chunkStore.Get(ctx, req.Addr)
   167  		if err != nil {
   168  			retrieveChunkFail.Inc(1)
   169  			log.Debug("ChunkStore.Get can not retrieve chunk", "peer", sp.ID().String(), "addr", req.Addr, "hopcount", req.HopCount, "err", err)
   170  			return
   171  		}
   172  		if req.SkipCheck {
   173  			syncing := false
   174  			err = sp.Deliver(ctx, chunk, s.priority, syncing)
   175  			if err != nil {
   176  				log.Warn("ERROR in handleRetrieveRequestMsg", "err", err)
   177  			}
   178  			return
   179  		}
   180  		select {
   181  		case streamer.deliveryC <- chunk.Address()[:]:
   182  		case <-streamer.quit:
   183  		}
   184  
   185  	}()
   186  
   187  	return nil
   188  }
   189  
   190  //区块传送总是使用相同的讯息类型….
   191  type ChunkDeliveryMsg struct {
   192  	Addr  storage.Address
   193  SData []byte //存储的块数据(包括大小)
   194  peer  *Peer  //设置在handlechunkdeliverymsg中
   195  }
   196  
   197  //…但如果交换记帐是用于同步或检索的传递,则需要消除歧义。
   198  //根据消息类型决定是否需要解释此消息
   199  
   200  //定义用于检索的块传递(使用记帐)
   201  type ChunkDeliveryMsgRetrieval ChunkDeliveryMsg
   202  
   203  //定义用于同步的块传递(无记帐)
   204  type ChunkDeliveryMsgSyncing ChunkDeliveryMsg
   205  
   206  //TODO:修复上下文snafu
   207  func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error {
   208  	var osp opentracing.Span
   209  	ctx, osp = spancontext.StartSpan(
   210  		ctx,
   211  		"chunk.delivery")
   212  	defer osp.Finish()
   213  
   214  	processReceivedChunksCount.Inc(1)
   215  
   216  	go func() {
   217  		req.peer = sp
   218  		err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData))
   219  		if err != nil {
   220  			if err == storage.ErrChunkInvalid {
   221  //我们删除了这个日志,因为它会破坏日志
   222  //TODO:启用此日志行
   223  //log.warn(“传递的块无效”,“对等”,sp.id(),“块”,req.addr,)
   224  				req.peer.Drop(err)
   225  			}
   226  		}
   227  	}()
   228  	return nil
   229  }
   230  
   231  //RequestFromPeers将块检索请求发送到
   232  func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (*enode.ID, chan struct{}, error) {
   233  	requestFromPeersCount.Inc(1)
   234  	var sp *Peer
   235  	spID := req.Source
   236  
   237  	if spID != nil {
   238  		sp = d.getPeer(*spID)
   239  		if sp == nil {
   240  			return nil, nil, fmt.Errorf("source peer %v not found", spID.String())
   241  		}
   242  	} else {
   243  		d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int) bool {
   244  			id := p.ID()
   245  			if p.LightNode {
   246  //跳过灯光节点
   247  				return true
   248  			}
   249  			if req.SkipPeer(id.String()) {
   250  				log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id)
   251  				return true
   252  			}
   253  			sp = d.getPeer(id)
   254  			if sp == nil {
   255  //log.warn(“delivery.requestfrompeers:找不到对等机”,“id”,id)
   256  				return true
   257  			}
   258  			spID = &id
   259  			return false
   260  		})
   261  		if sp == nil {
   262  			return nil, nil, errors.New("no peer found")
   263  		}
   264  	}
   265  
   266  	err := sp.SendPriority(ctx, &RetrieveRequestMsg{
   267  		Addr:      req.Addr,
   268  		SkipCheck: req.SkipCheck,
   269  		HopCount:  req.HopCount,
   270  	}, Top)
   271  	if err != nil {
   272  		return nil, nil, err
   273  	}
   274  	requestFromPeersEachCount.Inc(1)
   275  
   276  	return spID, sp.quit, nil
   277  }
   278