github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/eth/downloader/peer.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:37</date>
    10  //</624450088256671744>
    11  
    12  
    13  //包含下载程序的活动对等集,维护两个故障
    14  //以及信誉指标,以确定块检索的优先级。
    15  
    16  package downloader
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"math"
    22  	"math/big"
    23  	"sort"
    24  	"sync"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/event"
    30  	"github.com/ethereum/go-ethereum/log"
    31  )
    32  
    33  const (
    34  maxLackingHashes  = 4096 //列表中允许或缺少项的最大项数
    35  measurementImpact = 0.1  //单个度量对对等端最终吞吐量值的影响。
    36  )
    37  
    38  var (
    39  	errAlreadyFetching   = errors.New("already fetching blocks from peer")
    40  	errAlreadyRegistered = errors.New("peer is already registered")
    41  	errNotRegistered     = errors.New("peer is not registered")
    42  )
    43  
    44  //对等连接表示从中检索哈希和块的活动对等。
    45  type peerConnection struct {
    46  id string //对等方的唯一标识符
    47  
    48  headerIdle  int32 //对等机的当前头活动状态(空闲=0,活动=1)
    49  blockIdle   int32 //对等机的当前块活动状态(空闲=0,活动=1)
    50  receiptIdle int32 //对等机的当前接收活动状态(空闲=0,活动=1)
    51  stateIdle   int32 //对等机的当前节点数据活动状态(空闲=0,活动=1)
    52  
    53  headerThroughput  float64 //每秒可检索的头数
    54  blockThroughput   float64 //每秒可检索的块(体)数
    55  receiptThroughput float64 //每秒可检索的接收数
    56  stateThroughput   float64 //每秒可检索的节点数据块数
    57  
    58  rtt time.Duration //请求往返时间以跟踪响应(QoS)
    59  
    60  headerStarted  time.Time //Time instance when the last header fetch was started
    61  blockStarted   time.Time //上次块(体)提取开始时的时间实例
    62  receiptStarted time.Time //Time instance when the last receipt fetch was started
    63  stateStarted   time.Time //上次节点数据提取开始时的时间实例
    64  
    65  lacking map[common.Hash]struct{} //不请求的哈希集(以前没有)
    66  
    67  	peer Peer
    68  
    69  version int        //ETH协议版本号转换策略
    70  log     log.Logger //上下文记录器,用于向对等日志添加额外信息
    71  	lock    sync.RWMutex
    72  }
    73  
    74  //light peer封装了与远程light peer同步所需的方法。
    75  type LightPeer interface {
    76  	Head() (common.Hash, *big.Int)
    77  	RequestHeadersByHash(common.Hash, int, int, bool) error
    78  	RequestHeadersByNumber(uint64, int, int, bool) error
    79  }
    80  
    81  //对等体封装了与远程完整对等体同步所需的方法。
    82  type Peer interface {
    83  	LightPeer
    84  	RequestBodies([]common.Hash) error
    85  	RequestReceipts([]common.Hash) error
    86  	RequestNodeData([]common.Hash) error
    87  }
    88  
    89  //LightPeerWrapper包装了一个LightPeer结构,删除了仅限对等的方法。
    90  type lightPeerWrapper struct {
    91  	peer LightPeer
    92  }
    93  
    94  func (w *lightPeerWrapper) Head() (common.Hash, *big.Int) { return w.peer.Head() }
    95  func (w *lightPeerWrapper) RequestHeadersByHash(h common.Hash, amount int, skip int, reverse bool) error {
    96  	return w.peer.RequestHeadersByHash(h, amount, skip, reverse)
    97  }
    98  func (w *lightPeerWrapper) RequestHeadersByNumber(i uint64, amount int, skip int, reverse bool) error {
    99  	return w.peer.RequestHeadersByNumber(i, amount, skip, reverse)
   100  }
   101  func (w *lightPeerWrapper) RequestBodies([]common.Hash) error {
   102  	panic("RequestBodies not supported in light client mode sync")
   103  }
   104  func (w *lightPeerWrapper) RequestReceipts([]common.Hash) error {
   105  	panic("RequestReceipts not supported in light client mode sync")
   106  }
   107  func (w *lightPeerWrapper) RequestNodeData([]common.Hash) error {
   108  	panic("RequestNodeData not supported in light client mode sync")
   109  }
   110  
   111  //NexPeRead创建了一个新的下载器对等体。
   112  func newPeerConnection(id string, version int, peer Peer, logger log.Logger) *peerConnection {
   113  	return &peerConnection{
   114  		id:      id,
   115  		lacking: make(map[common.Hash]struct{}),
   116  
   117  		peer: peer,
   118  
   119  		version: version,
   120  		log:     logger,
   121  	}
   122  }
   123  
   124  //重置清除对等实体的内部状态。
   125  func (p *peerConnection) Reset() {
   126  	p.lock.Lock()
   127  	defer p.lock.Unlock()
   128  
   129  	atomic.StoreInt32(&p.headerIdle, 0)
   130  	atomic.StoreInt32(&p.blockIdle, 0)
   131  	atomic.StoreInt32(&p.receiptIdle, 0)
   132  	atomic.StoreInt32(&p.stateIdle, 0)
   133  
   134  	p.headerThroughput = 0
   135  	p.blockThroughput = 0
   136  	p.receiptThroughput = 0
   137  	p.stateThroughput = 0
   138  
   139  	p.lacking = make(map[common.Hash]struct{})
   140  }
   141  
   142  //fetchheaders向远程对等端发送头检索请求。
   143  func (p *peerConnection) FetchHeaders(from uint64, count int) error {
   144  //健全性检查协议版本
   145  	if p.version < 62 {
   146  		panic(fmt.Sprintf("header fetch [eth/62+] requested on eth/%d", p.version))
   147  	}
   148  //如果对等机已获取,则短路
   149  	if !atomic.CompareAndSwapInt32(&p.headerIdle, 0, 1) {
   150  		return errAlreadyFetching
   151  	}
   152  	p.headerStarted = time.Now()
   153  
   154  //发出头检索请求(绝对向上,无间隙)
   155  	go p.peer.RequestHeadersByNumber(from, count, 0, false)
   156  
   157  	return nil
   158  }
   159  
   160  //fetchbodies向远程对等端发送一个块体检索请求。
   161  func (p *peerConnection) FetchBodies(request *fetchRequest) error {
   162  //健全性检查协议版本
   163  	if p.version < 62 {
   164  		panic(fmt.Sprintf("body fetch [eth/62+] requested on eth/%d", p.version))
   165  	}
   166  //如果对等机已获取,则短路
   167  	if !atomic.CompareAndSwapInt32(&p.blockIdle, 0, 1) {
   168  		return errAlreadyFetching
   169  	}
   170  	p.blockStarted = time.Now()
   171  
   172  //将标题集转换为可检索切片
   173  	hashes := make([]common.Hash, 0, len(request.Headers))
   174  	for _, header := range request.Headers {
   175  		hashes = append(hashes, header.Hash())
   176  	}
   177  	go p.peer.RequestBodies(hashes)
   178  
   179  	return nil
   180  }
   181  
   182  //FetchReceipts sends a receipt retrieval request to the remote peer.
   183  func (p *peerConnection) FetchReceipts(request *fetchRequest) error {
   184  //健全性检查协议版本
   185  	if p.version < 63 {
   186  		panic(fmt.Sprintf("body fetch [eth/63+] requested on eth/%d", p.version))
   187  	}
   188  //如果对等机已获取,则短路
   189  	if !atomic.CompareAndSwapInt32(&p.receiptIdle, 0, 1) {
   190  		return errAlreadyFetching
   191  	}
   192  	p.receiptStarted = time.Now()
   193  
   194  //将标题集转换为可检索切片
   195  	hashes := make([]common.Hash, 0, len(request.Headers))
   196  	for _, header := range request.Headers {
   197  		hashes = append(hashes, header.Hash())
   198  	}
   199  	go p.peer.RequestReceipts(hashes)
   200  
   201  	return nil
   202  }
   203  
   204  //FETCHNODEDATA向远程对等体发送节点状态数据检索请求。
   205  func (p *peerConnection) FetchNodeData(hashes []common.Hash) error {
   206  //健全性检查协议版本
   207  	if p.version < 63 {
   208  		panic(fmt.Sprintf("node data fetch [eth/63+] requested on eth/%d", p.version))
   209  	}
   210  //如果对等机已获取,则短路
   211  	if !atomic.CompareAndSwapInt32(&p.stateIdle, 0, 1) {
   212  		return errAlreadyFetching
   213  	}
   214  	p.stateStarted = time.Now()
   215  
   216  	go p.peer.RequestNodeData(hashes)
   217  
   218  	return nil
   219  }
   220  
   221  //setheadersidle将对等机设置为空闲,允许它执行新的头检索
   222  //请求。它的估计头检索吞吐量用测量值更新。
   223  //刚才。
   224  func (p *peerConnection) SetHeadersIdle(delivered int) {
   225  	p.setIdle(p.headerStarted, delivered, &p.headerThroughput, &p.headerIdle)
   226  }
   227  
   228  //SetBodiesIdle sets the peer to idle, allowing it to execute block body retrieval
   229  //请求。它的估计身体检索吞吐量是用测量值更新的。
   230  //刚才。
   231  func (p *peerConnection) SetBodiesIdle(delivered int) {
   232  	p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle)
   233  }
   234  
   235  //setReceiptSidle将对等机设置为空闲,允许它执行新的接收
   236  //检索请求。更新其估计的收据检索吞吐量
   237  //刚刚测量的。
   238  func (p *peerConnection) SetReceiptsIdle(delivered int) {
   239  	p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle)
   240  }
   241  
   242  //setnodedataidle将对等机设置为空闲,允许它执行新的状态trie
   243  //数据检索请求。它的估计状态检索吞吐量被更新
   244  //刚刚测量的。
   245  func (p *peerConnection) SetNodeDataIdle(delivered int) {
   246  	p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle)
   247  }
   248  
   249  //setidle将对等机设置为idle,允许它执行新的检索请求。
   250  //它的估计检索吞吐量用刚才测量的更新。
   251  func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) {
   252  //与扩展无关,确保对等端最终空闲
   253  	defer atomic.StoreInt32(idle, 0)
   254  
   255  	p.lock.Lock()
   256  	defer p.lock.Unlock()
   257  
   258  //如果没有发送任何内容(硬超时/不可用数据),则将吞吐量降至最低
   259  	if delivered == 0 {
   260  		*throughput = 0
   261  		return
   262  	}
   263  //否则,以新的测量来更新吞吐量。
   264  elapsed := time.Since(started) + 1 //+1(ns)以确保非零除数
   265  	measured := float64(delivered) / (float64(elapsed) / float64(time.Second))
   266  
   267  	*throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured
   268  	p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed))
   269  
   270  	p.log.Trace("Peer throughput measurements updated",
   271  		"hps", p.headerThroughput, "bps", p.blockThroughput,
   272  		"rps", p.receiptThroughput, "sps", p.stateThroughput,
   273  		"miss", len(p.lacking), "rtt", p.rtt)
   274  }
   275  
   276  //HeaderCapacity根据其
   277  //以前发现的吞吐量。
   278  func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int {
   279  	p.lock.RLock()
   280  	defer p.lock.RUnlock()
   281  
   282  	return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch)))
   283  }
   284  
   285  //BlockCapacity根据其
   286  //以前发现的吞吐量。
   287  func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int {
   288  	p.lock.RLock()
   289  	defer p.lock.RUnlock()
   290  
   291  	return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch)))
   292  }
   293  
   294  //ReceiptCapacity根据其
   295  //以前发现的吞吐量。
   296  func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int {
   297  	p.lock.RLock()
   298  	defer p.lock.RUnlock()
   299  
   300  	return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch)))
   301  }
   302  
   303  //nodeDataCapacity根据其
   304  //以前发现的吞吐量。
   305  func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int {
   306  	p.lock.RLock()
   307  	defer p.lock.RUnlock()
   308  
   309  	return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch)))
   310  }
   311  
   312  //MaxDebug将新实体添加到一组项目(块、收据、状态)中。
   313  //已知某个对等机没有(即之前已被请求)。如果
   314  //集合达到其最大允许容量,项目被随机丢弃。
   315  func (p *peerConnection) MarkLacking(hash common.Hash) {
   316  	p.lock.Lock()
   317  	defer p.lock.Unlock()
   318  
   319  	for len(p.lacking) >= maxLackingHashes {
   320  		for drop := range p.lacking {
   321  			delete(p.lacking, drop)
   322  			break
   323  		}
   324  	}
   325  	p.lacking[hash] = struct{}{}
   326  }
   327  
   328  //缺少检索区块链项目的哈希是否在缺少的对等项上
   329  //列出(即,我们是否知道同伴没有它)。
   330  func (p *peerConnection) Lacks(hash common.Hash) bool {
   331  	p.lock.RLock()
   332  	defer p.lock.RUnlock()
   333  
   334  	_, ok := p.lacking[hash]
   335  	return ok
   336  }
   337  
   338  //peerSet represents the collection of active peer participating in the chain
   339  //下载过程。
   340  type peerSet struct {
   341  	peers        map[string]*peerConnection
   342  	newPeerFeed  event.Feed
   343  	peerDropFeed event.Feed
   344  	lock         sync.RWMutex
   345  }
   346  
   347  //new peer set创建一个新的peer set top跟踪活动的下载源。
   348  func newPeerSet() *peerSet {
   349  	return &peerSet{
   350  		peers: make(map[string]*peerConnection),
   351  	}
   352  }
   353  
   354  //订阅方订阅对等到达事件。
   355  func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription {
   356  	return ps.newPeerFeed.Subscribe(ch)
   357  }
   358  
   359  //订阅对等删除订阅对等离开事件。
   360  func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription {
   361  	return ps.peerDropFeed.Subscribe(ch)
   362  }
   363  
   364  //重置迭代当前对等集,并重置每个已知对等
   365  //为下一批块检索做准备。
   366  func (ps *peerSet) Reset() {
   367  	ps.lock.RLock()
   368  	defer ps.lock.RUnlock()
   369  
   370  	for _, peer := range ps.peers {
   371  		peer.Reset()
   372  	}
   373  }
   374  
   375  //寄存器向工作集中注入一个新的对等点,或者返回一个错误,如果
   376  //对等机已经知道。
   377  //
   378  //该方法还将新对等机的起始吞吐量值设置为
   379  //对所有现有同龄人的平均数,以使其有实际的使用机会
   380  //用于数据检索。
   381  func (ps *peerSet) Register(p *peerConnection) error {
   382  //检索当前中间值RTT作为健全的默认值
   383  	p.rtt = ps.medianRTT()
   384  
   385  //用一些有意义的默认值注册新的对等机
   386  	ps.lock.Lock()
   387  	if _, ok := ps.peers[p.id]; ok {
   388  		ps.lock.Unlock()
   389  		return errAlreadyRegistered
   390  	}
   391  	if len(ps.peers) > 0 {
   392  		p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0
   393  
   394  		for _, peer := range ps.peers {
   395  			peer.lock.RLock()
   396  			p.headerThroughput += peer.headerThroughput
   397  			p.blockThroughput += peer.blockThroughput
   398  			p.receiptThroughput += peer.receiptThroughput
   399  			p.stateThroughput += peer.stateThroughput
   400  			peer.lock.RUnlock()
   401  		}
   402  		p.headerThroughput /= float64(len(ps.peers))
   403  		p.blockThroughput /= float64(len(ps.peers))
   404  		p.receiptThroughput /= float64(len(ps.peers))
   405  		p.stateThroughput /= float64(len(ps.peers))
   406  	}
   407  	ps.peers[p.id] = p
   408  	ps.lock.Unlock()
   409  
   410  	ps.newPeerFeed.Send(p)
   411  	return nil
   412  }
   413  
   414  //注销从活动集删除远程对等,进一步禁用
   415  //对该特定实体采取的行动。
   416  func (ps *peerSet) Unregister(id string) error {
   417  	ps.lock.Lock()
   418  	p, ok := ps.peers[id]
   419  	if !ok {
   420  		defer ps.lock.Unlock()
   421  		return errNotRegistered
   422  	}
   423  	delete(ps.peers, id)
   424  	ps.lock.Unlock()
   425  
   426  	ps.peerDropFeed.Send(p)
   427  	return nil
   428  }
   429  
   430  //对等端检索具有给定ID的注册对等端。
   431  func (ps *peerSet) Peer(id string) *peerConnection {
   432  	ps.lock.RLock()
   433  	defer ps.lock.RUnlock()
   434  
   435  	return ps.peers[id]
   436  }
   437  
   438  //len返回集合中当前的对等数。
   439  func (ps *peerSet) Len() int {
   440  	ps.lock.RLock()
   441  	defer ps.lock.RUnlock()
   442  
   443  	return len(ps.peers)
   444  }
   445  
   446  //Allpeers检索集合中所有对等方的简单列表。
   447  func (ps *peerSet) AllPeers() []*peerConnection {
   448  	ps.lock.RLock()
   449  	defer ps.lock.RUnlock()
   450  
   451  	list := make([]*peerConnection, 0, len(ps.peers))
   452  	for _, p := range ps.peers {
   453  		list = append(list, p)
   454  	}
   455  	return list
   456  }
   457  
   458  //HeaderIdlePeers检索当前所有头空闲对等的简单列表
   459  //在活动对等集内,按其声誉排序。
   460  func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) {
   461  	idle := func(p *peerConnection) bool {
   462  		return atomic.LoadInt32(&p.headerIdle) == 0
   463  	}
   464  	throughput := func(p *peerConnection) float64 {
   465  		p.lock.RLock()
   466  		defer p.lock.RUnlock()
   467  		return p.headerThroughput
   468  	}
   469  	return ps.idlePeers(62, 64, idle, throughput)
   470  }
   471  
   472  //BodyIdlePeers检索当前位于
   473  //按其声誉排序的活动对等集。
   474  func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) {
   475  	idle := func(p *peerConnection) bool {
   476  		return atomic.LoadInt32(&p.blockIdle) == 0
   477  	}
   478  	throughput := func(p *peerConnection) float64 {
   479  		p.lock.RLock()
   480  		defer p.lock.RUnlock()
   481  		return p.blockThroughput
   482  	}
   483  	return ps.idlePeers(62, 64, idle, throughput)
   484  }
   485  
   486  //ReceiptIdlePeers检索当前所有接收空闲对等的简单列表
   487  //在活动对等集内,按其声誉排序。
   488  func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) {
   489  	idle := func(p *peerConnection) bool {
   490  		return atomic.LoadInt32(&p.receiptIdle) == 0
   491  	}
   492  	throughput := func(p *peerConnection) float64 {
   493  		p.lock.RLock()
   494  		defer p.lock.RUnlock()
   495  		return p.receiptThroughput
   496  	}
   497  	return ps.idlePeers(63, 64, idle, throughput)
   498  }
   499  
   500  //nodedataidlepeers检索当前所有空闲节点数据的简单列表
   501  //活动对等集内的对等点,按其声誉排序。
   502  func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) {
   503  	idle := func(p *peerConnection) bool {
   504  		return atomic.LoadInt32(&p.stateIdle) == 0
   505  	}
   506  	throughput := func(p *peerConnection) float64 {
   507  		p.lock.RLock()
   508  		defer p.lock.RUnlock()
   509  		return p.stateThroughput
   510  	}
   511  	return ps.idlePeers(63, 64, idle, throughput)
   512  }
   513  
   514  //idle peers检索当前满足
   515  //协议版本约束,使用提供的函数检查空闲。
   516  //由此产生的一组对等机按其度量吞吐量进行排序。
   517  func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) {
   518  	ps.lock.RLock()
   519  	defer ps.lock.RUnlock()
   520  
   521  	idle, total := make([]*peerConnection, 0, len(ps.peers)), 0
   522  	for _, p := range ps.peers {
   523  		if p.version >= minProtocol && p.version <= maxProtocol {
   524  			if idleCheck(p) {
   525  				idle = append(idle, p)
   526  			}
   527  			total++
   528  		}
   529  	}
   530  	for i := 0; i < len(idle); i++ {
   531  		for j := i + 1; j < len(idle); j++ {
   532  			if throughput(idle[i]) < throughput(idle[j]) {
   533  				idle[i], idle[j] = idle[j], idle[i]
   534  			}
   535  		}
   536  	}
   537  	return idle, total
   538  }
   539  
   540  //MediaNRTT返回对等集的中间RTT,只考虑调优
   541  //如果有更多可用的对等机,则为对等机。
   542  func (ps *peerSet) medianRTT() time.Duration {
   543  //Gather all the currently measured round trip times
   544  	ps.lock.RLock()
   545  	defer ps.lock.RUnlock()
   546  
   547  	rtts := make([]float64, 0, len(ps.peers))
   548  	for _, p := range ps.peers {
   549  		p.lock.RLock()
   550  		rtts = append(rtts, float64(p.rtt))
   551  		p.lock.RUnlock()
   552  	}
   553  	sort.Float64s(rtts)
   554  
   555  	median := rttMaxEstimate
   556  	if qosTuningPeers <= len(rtts) {
   557  median = time.Duration(rtts[qosTuningPeers/2]) //调优同行的中位数
   558  	} else if len(rtts) > 0 {
   559  median = time.Duration(rtts[len(rtts)/2]) //我们连接的对等点的中位数(甚至保持一些基线QoS)
   560  	}
   561  //Restrict the RTT into some QoS defaults, irrelevant of true RTT
   562  	if median < rttMinEstimate {
   563  		median = rttMinEstimate
   564  	}
   565  	if median > rttMaxEstimate {
   566  		median = rttMaxEstimate
   567  	}
   568  	return median
   569  }
   570