github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:38</date>
    10  //</624342634143420416>
    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 //上次头提取开始时的时间实例
    61  blockStarted   time.Time //上次块(体)提取开始时的时间实例
    62  receiptStarted time.Time //上次接收提取开始时的时间实例
    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向远程对等发送收据检索请求。
   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  //setblocksidle将对等机设置为空闲,允许它执行新的块检索
   229  //请求。它的估计块检索吞吐量用测量的更新。
   230  //刚才。
   231  func (p *peerConnection) SetBlocksIdle(delivered int) {
   232  	p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle)
   233  }
   234  
   235  //setbodiesidle将对等机设置为空闲,允许它执行块体检索。
   236  //请求。它的估计身体检索吞吐量是用测量值更新的。
   237  //刚才。
   238  func (p *peerConnection) SetBodiesIdle(delivered int) {
   239  	p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle)
   240  }
   241  
   242  //setReceiptSidle将对等机设置为空闲,允许它执行新的接收
   243  //检索请求。更新其估计的收据检索吞吐量
   244  //刚刚测量的。
   245  func (p *peerConnection) SetReceiptsIdle(delivered int) {
   246  	p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle)
   247  }
   248  
   249  //setnodedataidle将对等机设置为空闲,允许它执行新的状态trie
   250  //数据检索请求。它的估计状态检索吞吐量被更新
   251  //刚刚测量的。
   252  func (p *peerConnection) SetNodeDataIdle(delivered int) {
   253  	p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle)
   254  }
   255  
   256  //setidle将对等机设置为idle,允许它执行新的检索请求。
   257  //它的估计检索吞吐量用刚才测量的更新。
   258  func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) {
   259  //与扩展无关,确保对等端最终空闲
   260  	defer atomic.StoreInt32(idle, 0)
   261  
   262  	p.lock.Lock()
   263  	defer p.lock.Unlock()
   264  
   265  //如果没有发送任何内容(硬超时/不可用数据),则将吞吐量降至最低
   266  	if delivered == 0 {
   267  		*throughput = 0
   268  		return
   269  	}
   270  //否则,以新的测量来更新吞吐量。
   271  elapsed := time.Since(started) + 1 //+1(ns)以确保非零除数
   272  	measured := float64(delivered) / (float64(elapsed) / float64(time.Second))
   273  
   274  	*throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured
   275  	p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed))
   276  
   277  	p.log.Trace("Peer throughput measurements updated",
   278  		"hps", p.headerThroughput, "bps", p.blockThroughput,
   279  		"rps", p.receiptThroughput, "sps", p.stateThroughput,
   280  		"miss", len(p.lacking), "rtt", p.rtt)
   281  }
   282  
   283  //HeaderCapacity根据其
   284  //以前发现的吞吐量。
   285  func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int {
   286  	p.lock.RLock()
   287  	defer p.lock.RUnlock()
   288  
   289  	return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch)))
   290  }
   291  
   292  //BlockCapacity根据其
   293  //以前发现的吞吐量。
   294  func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int {
   295  	p.lock.RLock()
   296  	defer p.lock.RUnlock()
   297  
   298  	return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch)))
   299  }
   300  
   301  //ReceiptCapacity根据其
   302  //以前发现的吞吐量。
   303  func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int {
   304  	p.lock.RLock()
   305  	defer p.lock.RUnlock()
   306  
   307  	return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch)))
   308  }
   309  
   310  //nodeDataCapacity根据其
   311  //以前发现的吞吐量。
   312  func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int {
   313  	p.lock.RLock()
   314  	defer p.lock.RUnlock()
   315  
   316  	return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch)))
   317  }
   318  
   319  //MaxDebug将新实体添加到一组项目(块、收据、状态)中。
   320  //已知某个对等机没有(即之前已被请求)。如果
   321  //集合达到其最大允许容量,项目被随机丢弃。
   322  func (p *peerConnection) MarkLacking(hash common.Hash) {
   323  	p.lock.Lock()
   324  	defer p.lock.Unlock()
   325  
   326  	for len(p.lacking) >= maxLackingHashes {
   327  		for drop := range p.lacking {
   328  			delete(p.lacking, drop)
   329  			break
   330  		}
   331  	}
   332  	p.lacking[hash] = struct{}{}
   333  }
   334  
   335  //缺少检索区块链项目的哈希是否在缺少的对等项上
   336  //列出(即,我们是否知道同伴没有它)。
   337  func (p *peerConnection) Lacks(hash common.Hash) bool {
   338  	p.lock.RLock()
   339  	defer p.lock.RUnlock()
   340  
   341  	_, ok := p.lacking[hash]
   342  	return ok
   343  }
   344  
   345  //对等集表示参与链的活动对等集
   346  //下载过程。
   347  type peerSet struct {
   348  	peers        map[string]*peerConnection
   349  	newPeerFeed  event.Feed
   350  	peerDropFeed event.Feed
   351  	lock         sync.RWMutex
   352  }
   353  
   354  //new peer set创建一个新的peer set top跟踪活动的下载源。
   355  func newPeerSet() *peerSet {
   356  	return &peerSet{
   357  		peers: make(map[string]*peerConnection),
   358  	}
   359  }
   360  
   361  //订阅方订阅对等到达事件。
   362  func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription {
   363  	return ps.newPeerFeed.Subscribe(ch)
   364  }
   365  
   366  //订阅对等删除订阅对等离开事件。
   367  func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription {
   368  	return ps.peerDropFeed.Subscribe(ch)
   369  }
   370  
   371  //重置迭代当前对等集,并重置每个已知对等
   372  //为下一批块检索做准备。
   373  func (ps *peerSet) Reset() {
   374  	ps.lock.RLock()
   375  	defer ps.lock.RUnlock()
   376  
   377  	for _, peer := range ps.peers {
   378  		peer.Reset()
   379  	}
   380  }
   381  
   382  //寄存器向工作集中注入一个新的对等点,或者返回一个错误,如果
   383  //对等机已经知道。
   384  //
   385  //该方法还将新对等机的起始吞吐量值设置为
   386  //对所有现有同龄人的平均数,以使其有实际的使用机会
   387  //用于数据检索。
   388  func (ps *peerSet) Register(p *peerConnection) error {
   389  //检索当前中间值RTT作为健全的默认值
   390  	p.rtt = ps.medianRTT()
   391  
   392  //用一些有意义的默认值注册新的对等机
   393  	ps.lock.Lock()
   394  	if _, ok := ps.peers[p.id]; ok {
   395  		ps.lock.Unlock()
   396  		return errAlreadyRegistered
   397  	}
   398  	if len(ps.peers) > 0 {
   399  		p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0
   400  
   401  		for _, peer := range ps.peers {
   402  			peer.lock.RLock()
   403  			p.headerThroughput += peer.headerThroughput
   404  			p.blockThroughput += peer.blockThroughput
   405  			p.receiptThroughput += peer.receiptThroughput
   406  			p.stateThroughput += peer.stateThroughput
   407  			peer.lock.RUnlock()
   408  		}
   409  		p.headerThroughput /= float64(len(ps.peers))
   410  		p.blockThroughput /= float64(len(ps.peers))
   411  		p.receiptThroughput /= float64(len(ps.peers))
   412  		p.stateThroughput /= float64(len(ps.peers))
   413  	}
   414  	ps.peers[p.id] = p
   415  	ps.lock.Unlock()
   416  
   417  	ps.newPeerFeed.Send(p)
   418  	return nil
   419  }
   420  
   421  //注销从活动集删除远程对等,进一步禁用
   422  //对该特定实体采取的行动。
   423  func (ps *peerSet) Unregister(id string) error {
   424  	ps.lock.Lock()
   425  	p, ok := ps.peers[id]
   426  	if !ok {
   427  		defer ps.lock.Unlock()
   428  		return errNotRegistered
   429  	}
   430  	delete(ps.peers, id)
   431  	ps.lock.Unlock()
   432  
   433  	ps.peerDropFeed.Send(p)
   434  	return nil
   435  }
   436  
   437  //对等端检索具有给定ID的注册对等端。
   438  func (ps *peerSet) Peer(id string) *peerConnection {
   439  	ps.lock.RLock()
   440  	defer ps.lock.RUnlock()
   441  
   442  	return ps.peers[id]
   443  }
   444  
   445  //len返回集合中当前的对等数。
   446  func (ps *peerSet) Len() int {
   447  	ps.lock.RLock()
   448  	defer ps.lock.RUnlock()
   449  
   450  	return len(ps.peers)
   451  }
   452  
   453  //Allpeers检索集合中所有对等方的简单列表。
   454  func (ps *peerSet) AllPeers() []*peerConnection {
   455  	ps.lock.RLock()
   456  	defer ps.lock.RUnlock()
   457  
   458  	list := make([]*peerConnection, 0, len(ps.peers))
   459  	for _, p := range ps.peers {
   460  		list = append(list, p)
   461  	}
   462  	return list
   463  }
   464  
   465  //HeaderIdlePeers检索当前所有头空闲对等的简单列表
   466  //在活动对等集内,按其声誉排序。
   467  func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) {
   468  	idle := func(p *peerConnection) bool {
   469  		return atomic.LoadInt32(&p.headerIdle) == 0
   470  	}
   471  	throughput := func(p *peerConnection) float64 {
   472  		p.lock.RLock()
   473  		defer p.lock.RUnlock()
   474  		return p.headerThroughput
   475  	}
   476  	return ps.idlePeers(62, 64, idle, throughput)
   477  }
   478  
   479  //BodyIdlePeers检索当前位于
   480  //按其声誉排序的活动对等集。
   481  func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) {
   482  	idle := func(p *peerConnection) bool {
   483  		return atomic.LoadInt32(&p.blockIdle) == 0
   484  	}
   485  	throughput := func(p *peerConnection) float64 {
   486  		p.lock.RLock()
   487  		defer p.lock.RUnlock()
   488  		return p.blockThroughput
   489  	}
   490  	return ps.idlePeers(62, 64, idle, throughput)
   491  }
   492  
   493  //ReceiptIdlePeers检索当前所有接收空闲对等的简单列表
   494  //在活动对等集内,按其声誉排序。
   495  func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) {
   496  	idle := func(p *peerConnection) bool {
   497  		return atomic.LoadInt32(&p.receiptIdle) == 0
   498  	}
   499  	throughput := func(p *peerConnection) float64 {
   500  		p.lock.RLock()
   501  		defer p.lock.RUnlock()
   502  		return p.receiptThroughput
   503  	}
   504  	return ps.idlePeers(63, 64, idle, throughput)
   505  }
   506  
   507  //nodedataidlepeers检索当前所有空闲节点数据的简单列表
   508  //活动对等集内的对等点,按其声誉排序。
   509  func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) {
   510  	idle := func(p *peerConnection) bool {
   511  		return atomic.LoadInt32(&p.stateIdle) == 0
   512  	}
   513  	throughput := func(p *peerConnection) float64 {
   514  		p.lock.RLock()
   515  		defer p.lock.RUnlock()
   516  		return p.stateThroughput
   517  	}
   518  	return ps.idlePeers(63, 64, idle, throughput)
   519  }
   520  
   521  //idle peers检索当前满足
   522  //协议版本约束,使用提供的函数检查空闲。
   523  //由此产生的一组对等机按其度量吞吐量进行排序。
   524  func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) {
   525  	ps.lock.RLock()
   526  	defer ps.lock.RUnlock()
   527  
   528  	idle, total := make([]*peerConnection, 0, len(ps.peers)), 0
   529  	for _, p := range ps.peers {
   530  		if p.version >= minProtocol && p.version <= maxProtocol {
   531  			if idleCheck(p) {
   532  				idle = append(idle, p)
   533  			}
   534  			total++
   535  		}
   536  	}
   537  	for i := 0; i < len(idle); i++ {
   538  		for j := i + 1; j < len(idle); j++ {
   539  			if throughput(idle[i]) < throughput(idle[j]) {
   540  				idle[i], idle[j] = idle[j], idle[i]
   541  			}
   542  		}
   543  	}
   544  	return idle, total
   545  }
   546  
   547  //MediaNRTT返回对等集的中间RTT,只考虑调优
   548  //如果有更多可用的对等机,则为对等机。
   549  func (ps *peerSet) medianRTT() time.Duration {
   550  //收集所有当前测量的往返时间
   551  	ps.lock.RLock()
   552  	defer ps.lock.RUnlock()
   553  
   554  	rtts := make([]float64, 0, len(ps.peers))
   555  	for _, p := range ps.peers {
   556  		p.lock.RLock()
   557  		rtts = append(rtts, float64(p.rtt))
   558  		p.lock.RUnlock()
   559  	}
   560  	sort.Float64s(rtts)
   561  
   562  	median := rttMaxEstimate
   563  	if qosTuningPeers <= len(rtts) {
   564  median = time.Duration(rtts[qosTuningPeers/2]) //调优同行的中位数
   565  	} else if len(rtts) > 0 {
   566  median = time.Duration(rtts[len(rtts)/2]) //我们连接的对等点的中位数(甚至保持一些基线QoS)
   567  	}
   568  //将RTT限制为一些QoS默认值,与真正的RTT无关
   569  	if median < rttMinEstimate {
   570  		median = rttMinEstimate
   571  	}
   572  	if median > rttMaxEstimate {
   573  		median = rttMaxEstimate
   574  	}
   575  	return median
   576  }
   577