github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/network/stream/delivery.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //
    10  //
    11  //
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  
    25  package stream
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"time"
    31  
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/ethereum/go-ethereum/metrics"
    34  	"github.com/ethereum/go-ethereum/p2p/discover"
    35  	cp "github.com/ethereum/go-ethereum/swarm/chunk"
    36  	"github.com/ethereum/go-ethereum/swarm/log"
    37  	"github.com/ethereum/go-ethereum/swarm/network"
    38  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    39  	"github.com/ethereum/go-ethereum/swarm/storage"
    40  	opentracing "github.com/opentracing/opentracing-go"
    41  )
    42  
    43  const (
    44  	swarmChunkServerStreamName = "RETRIEVE_REQUEST"
    45  	deliveryCap                = 32
    46  )
    47  
    48  var (
    49  	processReceivedChunksCount    = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil)
    50  	handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil)
    51  
    52  	requestFromPeersCount     = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil)
    53  	requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil)
    54  )
    55  
    56  type Delivery struct {
    57  	db       *storage.DBAPI
    58  	overlay  network.Overlay
    59  	receiveC chan *ChunkDeliveryMsg
    60  	getPeer  func(discover.NodeID) *Peer
    61  }
    62  
    63  func NewDelivery(overlay network.Overlay, db *storage.DBAPI) *Delivery {
    64  	d := &Delivery{
    65  		db:       db,
    66  		overlay:  overlay,
    67  		receiveC: make(chan *ChunkDeliveryMsg, deliveryCap),
    68  	}
    69  
    70  	go d.processReceivedChunks()
    71  	return d
    72  }
    73  
    74  //
    75  type SwarmChunkServer struct {
    76  	deliveryC  chan []byte
    77  	batchC     chan []byte
    78  	db         *storage.DBAPI
    79  	currentLen uint64
    80  	quit       chan struct{}
    81  }
    82  
    83  //
    84  func NewSwarmChunkServer(db *storage.DBAPI) *SwarmChunkServer {
    85  	s := &SwarmChunkServer{
    86  		deliveryC: make(chan []byte, deliveryCap),
    87  		batchC:    make(chan []byte),
    88  		db:        db,
    89  		quit:      make(chan struct{}),
    90  	}
    91  	go s.processDeliveries()
    92  	return s
    93  }
    94  
    95  //
    96  func (s *SwarmChunkServer) processDeliveries() {
    97  	var hashes []byte
    98  	var batchC chan []byte
    99  	for {
   100  		select {
   101  		case <-s.quit:
   102  			return
   103  		case hash := <-s.deliveryC:
   104  			hashes = append(hashes, hash...)
   105  			batchC = s.batchC
   106  		case batchC <- hashes:
   107  			hashes = nil
   108  			batchC = nil
   109  		}
   110  	}
   111  }
   112  
   113  //
   114  func (s *SwarmChunkServer) SetNextBatch(_, _ uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) {
   115  	select {
   116  	case hashes = <-s.batchC:
   117  	case <-s.quit:
   118  		return
   119  	}
   120  
   121  	from = s.currentLen
   122  	s.currentLen += uint64(len(hashes))
   123  	to = s.currentLen
   124  	return
   125  }
   126  
   127  //
   128  func (s *SwarmChunkServer) Close() {
   129  	close(s.quit)
   130  }
   131  
   132  //
   133  func (s *SwarmChunkServer) GetData(ctx context.Context, key []byte) ([]byte, error) {
   134  	chunk, err := s.db.Get(ctx, storage.Address(key))
   135  	if err == storage.ErrFetching {
   136  		<-chunk.ReqC
   137  	} else if err != nil {
   138  		return nil, err
   139  	}
   140  	return chunk.SData, nil
   141  }
   142  
   143  //
   144  type RetrieveRequestMsg struct {
   145  	Addr      storage.Address
   146  	SkipCheck bool
   147  }
   148  
   149  func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error {
   150  	log.Trace("received request", "peer", sp.ID(), "hash", req.Addr)
   151  	handleRetrieveRequestMsgCount.Inc(1)
   152  
   153  	var osp opentracing.Span
   154  	ctx, osp = spancontext.StartSpan(
   155  		ctx,
   156  		"retrieve.request")
   157  	defer osp.Finish()
   158  
   159  	s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", false))
   160  	if err != nil {
   161  		return err
   162  	}
   163  	streamer := s.Server.(*SwarmChunkServer)
   164  	chunk, created := d.db.GetOrCreateRequest(ctx, req.Addr)
   165  	if chunk.ReqC != nil {
   166  		if created {
   167  			if err := d.RequestFromPeers(ctx, chunk.Addr[:], true, sp.ID()); err != nil {
   168  				log.Warn("unable to forward chunk request", "peer", sp.ID(), "key", chunk.Addr, "err", err)
   169  				chunk.SetErrored(storage.ErrChunkForward)
   170  				return nil
   171  			}
   172  		}
   173  		go func() {
   174  			var osp opentracing.Span
   175  			ctx, osp = spancontext.StartSpan(
   176  				ctx,
   177  				"waiting.delivery")
   178  			defer osp.Finish()
   179  
   180  			t := time.NewTimer(10 * time.Minute)
   181  			defer t.Stop()
   182  
   183  			log.Debug("waiting delivery", "peer", sp.ID(), "hash", req.Addr, "node", common.Bytes2Hex(d.overlay.BaseAddr()), "created", created)
   184  			start := time.Now()
   185  			select {
   186  			case <-chunk.ReqC:
   187  				log.Debug("retrieve request ReqC closed", "peer", sp.ID(), "hash", req.Addr, "time", time.Since(start))
   188  			case <-t.C:
   189  				log.Debug("retrieve request timeout", "peer", sp.ID(), "hash", req.Addr)
   190  				chunk.SetErrored(storage.ErrChunkTimeout)
   191  				return
   192  			}
   193  			chunk.SetErrored(nil)
   194  
   195  			if req.SkipCheck {
   196  				err := sp.Deliver(ctx, chunk, s.priority)
   197  				if err != nil {
   198  					log.Warn("ERROR in handleRetrieveRequestMsg, DROPPING peer!", "err", err)
   199  					sp.Drop(err)
   200  				}
   201  			}
   202  			streamer.deliveryC <- chunk.Addr[:]
   203  		}()
   204  		return nil
   205  	}
   206  //
   207  	if req.SkipCheck {
   208  		log.Trace("deliver", "peer", sp.ID(), "hash", chunk.Addr)
   209  		if length := len(chunk.SData); length < 9 {
   210  			log.Error("Chunk.SData to deliver is too short", "len(chunk.SData)", length, "address", chunk.Addr)
   211  		}
   212  		return sp.Deliver(ctx, chunk, s.priority)
   213  	}
   214  	streamer.deliveryC <- chunk.Addr[:]
   215  	return nil
   216  }
   217  
   218  type ChunkDeliveryMsg struct {
   219  	Addr  storage.Address
   220  SData []byte //
   221  peer  *Peer  //
   222  }
   223  
   224  func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error {
   225  	var osp opentracing.Span
   226  	ctx, osp = spancontext.StartSpan(
   227  		ctx,
   228  		"chunk.delivery")
   229  	defer osp.Finish()
   230  
   231  	req.peer = sp
   232  	d.receiveC <- req
   233  	return nil
   234  }
   235  
   236  func (d *Delivery) processReceivedChunks() {
   237  R:
   238  	for req := range d.receiveC {
   239  		processReceivedChunksCount.Inc(1)
   240  
   241  		if len(req.SData) > cp.DefaultSize+8 {
   242  			log.Warn("received chunk is bigger than expected", "len", len(req.SData))
   243  			continue R
   244  		}
   245  
   246  //
   247  		chunk, err := d.db.Get(context.TODO(), req.Addr)
   248  		if err == nil {
   249  			continue R
   250  		}
   251  		if err != storage.ErrFetching {
   252  			log.Error("processReceivedChunks db error", "addr", req.Addr, "err", err, "chunk", chunk)
   253  			continue R
   254  		}
   255  		select {
   256  		case <-chunk.ReqC:
   257  			log.Error("someone else delivered?", "hash", chunk.Addr.Hex())
   258  			continue R
   259  		default:
   260  		}
   261  
   262  		chunk.SData = req.SData
   263  		d.db.Put(context.TODO(), chunk)
   264  
   265  		go func(req *ChunkDeliveryMsg) {
   266  			err := chunk.WaitToStore()
   267  			if err == storage.ErrChunkInvalid {
   268  				req.peer.Drop(err)
   269  			}
   270  		}(req)
   271  	}
   272  }
   273  
   274  //
   275  func (d *Delivery) RequestFromPeers(ctx context.Context, hash []byte, skipCheck bool, peersToSkip ...discover.NodeID) error {
   276  	var success bool
   277  	var err error
   278  	requestFromPeersCount.Inc(1)
   279  
   280  	d.overlay.EachConn(hash, 255, func(p network.OverlayConn, po int, nn bool) bool {
   281  		spId := p.(network.Peer).ID()
   282  		for _, p := range peersToSkip {
   283  			if p == spId {
   284  				log.Trace("Delivery.RequestFromPeers: skip peer", "peer", spId)
   285  				return true
   286  			}
   287  		}
   288  		sp := d.getPeer(spId)
   289  		if sp == nil {
   290  			log.Warn("Delivery.RequestFromPeers: peer not found", "id", spId)
   291  			return true
   292  		}
   293  		err = sp.SendPriority(ctx, &RetrieveRequestMsg{
   294  			Addr:      hash,
   295  			SkipCheck: skipCheck,
   296  		}, Top)
   297  		if err != nil {
   298  			return true
   299  		}
   300  		requestFromPeersEachCount.Inc(1)
   301  		success = true
   302  		return false
   303  	})
   304  	if success {
   305  		return nil
   306  	}
   307  	return errors.New("no peer found")
   308  }