github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/retrieve.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:39</date>
    10  //</624450096053882880>
    11  
    12  
    13  //package light实现可按需检索的状态和链对象
    14  //对于以太坊Light客户端。
    15  package les
    16  
    17  import (
    18  	"context"
    19  	"crypto/rand"
    20  	"encoding/binary"
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common/mclock"
    26  	"github.com/ethereum/go-ethereum/light"
    27  )
    28  
    29  var (
    30  	retryQueue         = time.Millisecond * 100
    31  	softRequestTimeout = time.Millisecond * 500
    32  	hardRequestTimeout = time.Second * 10
    33  )
    34  
    35  //RetrieveManager是一个位于RequestDistributor之上的层,负责
    36  //按请求ID匹配答复,并处理超时,必要时重新发送。
    37  type retrieveManager struct {
    38  	dist       *requestDistributor
    39  	peers      *peerSet
    40  	serverPool peerSelector
    41  
    42  	lock     sync.RWMutex
    43  	sentReqs map[uint64]*sentReq
    44  }
    45  
    46  //validatorfunc是一个处理回复消息的函数
    47  type validatorFunc func(distPeer, *Msg) error
    48  
    49  //peerSelector receives feedback info about response times and timeouts
    50  type peerSelector interface {
    51  	adjustResponseTime(*poolEntry, time.Duration, bool)
    52  }
    53  
    54  //sentreq表示由retrievemanager发送和跟踪的请求
    55  type sentReq struct {
    56  	rm       *retrieveManager
    57  	req      *distReq
    58  	id       uint64
    59  	validate validatorFunc
    60  
    61  	eventsCh chan reqPeerEvent
    62  	stopCh   chan struct{}
    63  	stopped  bool
    64  	err      error
    65  
    66  lock   sync.RWMutex //保护对Sento地图的访问
    67  	sentTo map[distPeer]sentReqToPeer
    68  
    69  lastReqQueued bool     //上一个请求已排队,但未发送
    70  lastReqSentTo distPeer //如果不是零,则最后一个请求已发送给给定的对等方,但未超时。
    71  reqSrtoCount  int      //达到软(但非硬)超时的请求数
    72  }
    73  
    74  //SentReqTopeer通知来自对等Goroutine(TryRequest)的请求有关响应
    75  //由给定的对等方传递。每个对等端的每个请求只允许一次传递,
    76  //在此之后,delivered设置为true,响应的有效性将发送到
    77  //有效通道,不接受其他响应。
    78  type sentReqToPeer struct {
    79  	delivered bool
    80  	valid     chan bool
    81  }
    82  
    83  //ReqPeerEvent由Peer Goroutine(TryRequest)的请求发送到
    84  //通过eventsch通道请求状态机(retrieveloop)。
    85  type reqPeerEvent struct {
    86  	event int
    87  	peer  distPeer
    88  }
    89  
    90  const (
    91  rpSent = iota //if peer == nil, not sent (no suitable peers)
    92  	rpSoftTimeout
    93  	rpHardTimeout
    94  	rpDeliveredValid
    95  	rpDeliveredInvalid
    96  )
    97  
    98  //newRetrieveManager创建检索管理器
    99  func newRetrieveManager(peers *peerSet, dist *requestDistributor, serverPool peerSelector) *retrieveManager {
   100  	return &retrieveManager{
   101  		peers:      peers,
   102  		dist:       dist,
   103  		serverPool: serverPool,
   104  		sentReqs:   make(map[uint64]*sentReq),
   105  	}
   106  }
   107  
   108  //检索发送请求(必要时发送给多个对等方)并等待响应
   109  //通过传递函数传递并由
   110  //验证程序回调。当传递有效答案或上下文为
   111  //取消。
   112  func (rm *retrieveManager) retrieve(ctx context.Context, reqID uint64, req *distReq, val validatorFunc, shutdown chan struct{}) error {
   113  	sentReq := rm.sendReq(reqID, req, val)
   114  	select {
   115  	case <-sentReq.stopCh:
   116  	case <-ctx.Done():
   117  		sentReq.stop(ctx.Err())
   118  	case <-shutdown:
   119  		sentReq.stop(fmt.Errorf("Client is shutting down"))
   120  	}
   121  	return sentReq.getError()
   122  }
   123  
   124  //sendreq启动一个进程,该进程不断尝试为
   125  //在停止或成功之前,从任何合适的对等方请求。
   126  func (rm *retrieveManager) sendReq(reqID uint64, req *distReq, val validatorFunc) *sentReq {
   127  	r := &sentReq{
   128  		rm:       rm,
   129  		req:      req,
   130  		id:       reqID,
   131  		sentTo:   make(map[distPeer]sentReqToPeer),
   132  		stopCh:   make(chan struct{}),
   133  		eventsCh: make(chan reqPeerEvent, 10),
   134  		validate: val,
   135  	}
   136  
   137  	canSend := req.canSend
   138  	req.canSend = func(p distPeer) bool {
   139  //为cansend添加额外的检查:请求以前没有发送到同一个对等机
   140  		r.lock.RLock()
   141  		_, sent := r.sentTo[p]
   142  		r.lock.RUnlock()
   143  		return !sent && canSend(p)
   144  	}
   145  
   146  	request := req.request
   147  	req.request = func(p distPeer) func() {
   148  //在实际发送请求之前,在sentto映射中输入一个条目
   149  		r.lock.Lock()
   150  		r.sentTo[p] = sentReqToPeer{false, make(chan bool, 1)}
   151  		r.lock.Unlock()
   152  		return request(p)
   153  	}
   154  	rm.lock.Lock()
   155  	rm.sentReqs[reqID] = r
   156  	rm.lock.Unlock()
   157  
   158  	go r.retrieveLoop()
   159  	return r
   160  }
   161  
   162  //LES协议管理器调用Deliver将回复消息传递给等待的请求。
   163  func (rm *retrieveManager) deliver(peer distPeer, msg *Msg) error {
   164  	rm.lock.RLock()
   165  	req, ok := rm.sentReqs[msg.ReqID]
   166  	rm.lock.RUnlock()
   167  
   168  	if ok {
   169  		return req.deliver(peer, msg)
   170  	}
   171  	return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
   172  }
   173  
   174  //reqstatefn表示检索循环状态机的状态
   175  type reqStateFn func() reqStateFn
   176  
   177  //RetrieveLoop是检索状态机事件循环
   178  func (r *sentReq) retrieveLoop() {
   179  	go r.tryRequest()
   180  	r.lastReqQueued = true
   181  	state := r.stateRequesting
   182  
   183  	for state != nil {
   184  		state = state()
   185  	}
   186  
   187  	r.rm.lock.Lock()
   188  	delete(r.rm.sentReqs, r.id)
   189  	r.rm.lock.Unlock()
   190  }
   191  
   192  //状态请求:请求最近已排队或发送;当达到软超时时,
   193  //将向新对等发送新请求
   194  func (r *sentReq) stateRequesting() reqStateFn {
   195  	select {
   196  	case ev := <-r.eventsCh:
   197  		r.update(ev)
   198  		switch ev.event {
   199  		case rpSent:
   200  			if ev.peer == nil {
   201  //请求发送失败,没有合适的对等机
   202  				if r.waiting() {
   203  //我们已经在等待可能成功的已发送请求,请继续等待
   204  					return r.stateNoMorePeers
   205  				}
   206  //无需等待,无需询问其他对等方,返回时出错
   207  				r.stop(light.ErrNoPeers)
   208  //无需转到停止状态,因为waiting()已返回false
   209  				return nil
   210  			}
   211  		case rpSoftTimeout:
   212  //上次请求超时,请尝试询问新的对等方
   213  			go r.tryRequest()
   214  			r.lastReqQueued = true
   215  			return r.stateRequesting
   216  		case rpDeliveredInvalid:
   217  //如果是上次发送的请求(更新时设置为nil),则启动新的请求。
   218  			if !r.lastReqQueued && r.lastReqSentTo == nil {
   219  				go r.tryRequest()
   220  				r.lastReqQueued = true
   221  			}
   222  			return r.stateRequesting
   223  		case rpDeliveredValid:
   224  			r.stop(nil)
   225  			return r.stateStopped
   226  		}
   227  		return r.stateRequesting
   228  	case <-r.stopCh:
   229  		return r.stateStopped
   230  	}
   231  }
   232  
   233  //StateNoMorepeers:无法发送更多请求,因为没有合适的对等机可用。
   234  //对等方稍后可能会适合某个请求,或者可能会出现新的对等方,因此我们
   235  //继续努力。
   236  func (r *sentReq) stateNoMorePeers() reqStateFn {
   237  	select {
   238  	case <-time.After(retryQueue):
   239  		go r.tryRequest()
   240  		r.lastReqQueued = true
   241  		return r.stateRequesting
   242  	case ev := <-r.eventsCh:
   243  		r.update(ev)
   244  		if ev.event == rpDeliveredValid {
   245  			r.stop(nil)
   246  			return r.stateStopped
   247  		}
   248  		if r.waiting() {
   249  			return r.stateNoMorePeers
   250  		}
   251  		r.stop(light.ErrNoPeers)
   252  		return nil
   253  	case <-r.stopCh:
   254  		return r.stateStopped
   255  	}
   256  }
   257  
   258  //Statestopped:请求成功或取消,只是等待一些对等方
   259  //要么回答,要么很难超时
   260  func (r *sentReq) stateStopped() reqStateFn {
   261  	for r.waiting() {
   262  		r.update(<-r.eventsCh)
   263  	}
   264  	return nil
   265  }
   266  
   267  //更新根据事件更新排队/发送标志和超时对等计数器
   268  func (r *sentReq) update(ev reqPeerEvent) {
   269  	switch ev.event {
   270  	case rpSent:
   271  		r.lastReqQueued = false
   272  		r.lastReqSentTo = ev.peer
   273  	case rpSoftTimeout:
   274  		r.lastReqSentTo = nil
   275  		r.reqSrtoCount++
   276  	case rpHardTimeout:
   277  		r.reqSrtoCount--
   278  	case rpDeliveredValid, rpDeliveredInvalid:
   279  		if ev.peer == r.lastReqSentTo {
   280  			r.lastReqSentTo = nil
   281  		} else {
   282  			r.reqSrtoCount--
   283  		}
   284  	}
   285  }
   286  
   287  //如果检索机制正在等待来自的答案,则waiting返回true。
   288  //任何同龄人
   289  func (r *sentReq) waiting() bool {
   290  	return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0
   291  }
   292  
   293  //TryRequest尝试将请求发送到新的对等机,并等待它
   294  //succeed or time out if it has been sent. It also sends the appropriate reqPeerEvent
   295  //发送到请求的事件通道的消息。
   296  func (r *sentReq) tryRequest() {
   297  	sent := r.rm.dist.queue(r.req)
   298  	var p distPeer
   299  	select {
   300  	case p = <-sent:
   301  	case <-r.stopCh:
   302  		if r.rm.dist.cancel(r.req) {
   303  			p = nil
   304  		} else {
   305  			p = <-sent
   306  		}
   307  	}
   308  
   309  	r.eventsCh <- reqPeerEvent{rpSent, p}
   310  	if p == nil {
   311  		return
   312  	}
   313  
   314  	reqSent := mclock.Now()
   315  	srto, hrto := false, false
   316  
   317  	r.lock.RLock()
   318  	s, ok := r.sentTo[p]
   319  	r.lock.RUnlock()
   320  	if !ok {
   321  		panic(nil)
   322  	}
   323  
   324  	defer func() {
   325  //向服务器池发送反馈,并在发生硬超时时删除对等机
   326  		pp, ok := p.(*peer)
   327  		if ok && r.rm.serverPool != nil {
   328  			respTime := time.Duration(mclock.Now() - reqSent)
   329  			r.rm.serverPool.adjustResponseTime(pp.poolEntry, respTime, srto)
   330  		}
   331  		if hrto {
   332  			pp.Log().Debug("Request timed out hard")
   333  			if r.rm.peers != nil {
   334  				r.rm.peers.Unregister(pp.id)
   335  			}
   336  		}
   337  
   338  		r.lock.Lock()
   339  		delete(r.sentTo, p)
   340  		r.lock.Unlock()
   341  	}()
   342  
   343  	select {
   344  	case ok := <-s.valid:
   345  		if ok {
   346  			r.eventsCh <- reqPeerEvent{rpDeliveredValid, p}
   347  		} else {
   348  			r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p}
   349  		}
   350  		return
   351  	case <-time.After(softRequestTimeout):
   352  		srto = true
   353  		r.eventsCh <- reqPeerEvent{rpSoftTimeout, p}
   354  	}
   355  
   356  	select {
   357  	case ok := <-s.valid:
   358  		if ok {
   359  			r.eventsCh <- reqPeerEvent{rpDeliveredValid, p}
   360  		} else {
   361  			r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p}
   362  		}
   363  	case <-time.After(hardRequestTimeout):
   364  		hrto = true
   365  		r.eventsCh <- reqPeerEvent{rpHardTimeout, p}
   366  	}
   367  }
   368  
   369  //传递属于此请求的答复
   370  func (r *sentReq) deliver(peer distPeer, msg *Msg) error {
   371  	r.lock.Lock()
   372  	defer r.lock.Unlock()
   373  
   374  	s, ok := r.sentTo[peer]
   375  	if !ok || s.delivered {
   376  		return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
   377  	}
   378  	valid := r.validate(peer, msg) == nil
   379  	r.sentTo[peer] = sentReqToPeer{true, s.valid}
   380  	s.valid <- valid
   381  	if !valid {
   382  		return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID)
   383  	}
   384  	return nil
   385  }
   386  
   387  //停止停止检索进程并设置将返回的错误代码
   388  //通过获得错误
   389  func (r *sentReq) stop(err error) {
   390  	r.lock.Lock()
   391  	if !r.stopped {
   392  		r.stopped = true
   393  		r.err = err
   394  		close(r.stopCh)
   395  	}
   396  	r.lock.Unlock()
   397  }
   398  
   399  //GetError返回任何检索错误(由
   400  //停止功能)停止后
   401  func (r *sentReq) getError() error {
   402  	return r.err
   403  }
   404  
   405  //genreqid生成新的随机请求ID
   406  func genReqID() uint64 {
   407  	var rnd [8]byte
   408  	rand.Read(rnd[:])
   409  	return binary.BigEndian.Uint64(rnd[:])
   410  }
   411