github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatptc/downloader/peer.go (about)

     1  package downloader
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"math/big"
     8  	"sort"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/neatlab/neatio/chain/log"
    14  	"github.com/neatlab/neatio/utilities/common"
    15  	"github.com/neatlab/neatio/utilities/event"
    16  )
    17  
    18  const (
    19  	maxLackingHashes  = 4096
    20  	measurementImpact = 0.1
    21  )
    22  
    23  var (
    24  	errAlreadyFetching   = errors.New("already fetching blocks from peer")
    25  	errAlreadyRegistered = errors.New("peer is already registered")
    26  	errNotRegistered     = errors.New("peer is not registered")
    27  )
    28  
    29  type peerConnection struct {
    30  	id string
    31  
    32  	headerIdle  int32
    33  	blockIdle   int32
    34  	receiptIdle int32
    35  	stateIdle   int32
    36  
    37  	headerThroughput  float64
    38  	blockThroughput   float64
    39  	receiptThroughput float64
    40  	stateThroughput   float64
    41  
    42  	rtt time.Duration
    43  
    44  	headerStarted  time.Time
    45  	blockStarted   time.Time
    46  	receiptStarted time.Time
    47  	stateStarted   time.Time
    48  
    49  	lacking map[common.Hash]struct{}
    50  
    51  	peer Peer
    52  
    53  	version int
    54  	log     log.Logger
    55  	lock    sync.RWMutex
    56  }
    57  
    58  type LightPeer interface {
    59  	Head() (common.Hash, *big.Int)
    60  	RequestHeadersByHash(common.Hash, int, int, bool) error
    61  	RequestHeadersByNumber(uint64, int, int, bool) error
    62  }
    63  
    64  type Peer interface {
    65  	LightPeer
    66  	RequestBodies([]common.Hash) error
    67  	RequestReceipts([]common.Hash) error
    68  	RequestNodeData([]common.Hash) error
    69  }
    70  
    71  type lightPeerWrapper struct {
    72  	peer LightPeer
    73  }
    74  
    75  func (w *lightPeerWrapper) Head() (common.Hash, *big.Int) { return w.peer.Head() }
    76  func (w *lightPeerWrapper) RequestHeadersByHash(h common.Hash, amount int, skip int, reverse bool) error {
    77  	return w.peer.RequestHeadersByHash(h, amount, skip, reverse)
    78  }
    79  func (w *lightPeerWrapper) RequestHeadersByNumber(i uint64, amount int, skip int, reverse bool) error {
    80  	return w.peer.RequestHeadersByNumber(i, amount, skip, reverse)
    81  }
    82  func (w *lightPeerWrapper) RequestBodies([]common.Hash) error {
    83  	panic("RequestBodies not supported in light client mode sync")
    84  }
    85  func (w *lightPeerWrapper) RequestReceipts([]common.Hash) error {
    86  	panic("RequestReceipts not supported in light client mode sync")
    87  }
    88  func (w *lightPeerWrapper) RequestNodeData([]common.Hash) error {
    89  	panic("RequestNodeData not supported in light client mode sync")
    90  }
    91  
    92  func newPeerConnection(id string, version int, peer Peer, logger log.Logger) *peerConnection {
    93  	return &peerConnection{
    94  		id:      id,
    95  		lacking: make(map[common.Hash]struct{}),
    96  
    97  		peer: peer,
    98  
    99  		version: version,
   100  		log:     logger,
   101  	}
   102  }
   103  
   104  func (p *peerConnection) Reset() {
   105  	p.lock.Lock()
   106  	defer p.lock.Unlock()
   107  
   108  	atomic.StoreInt32(&p.headerIdle, 0)
   109  	atomic.StoreInt32(&p.blockIdle, 0)
   110  	atomic.StoreInt32(&p.receiptIdle, 0)
   111  	atomic.StoreInt32(&p.stateIdle, 0)
   112  
   113  	p.headerThroughput = 0
   114  	p.blockThroughput = 0
   115  	p.receiptThroughput = 0
   116  	p.stateThroughput = 0
   117  
   118  	p.lacking = make(map[common.Hash]struct{})
   119  }
   120  
   121  func (p *peerConnection) FetchHeaders(from uint64, count int) error {
   122  
   123  	if p.version < 62 {
   124  		panic(fmt.Sprintf("header fetch [eth/62+] requested on eth/%d", p.version))
   125  	}
   126  
   127  	if !atomic.CompareAndSwapInt32(&p.headerIdle, 0, 1) {
   128  		return errAlreadyFetching
   129  	}
   130  	p.headerStarted = time.Now()
   131  
   132  	go p.peer.RequestHeadersByNumber(from, count, 0, false)
   133  
   134  	return nil
   135  }
   136  
   137  func (p *peerConnection) FetchBodies(request *fetchRequest) error {
   138  
   139  	if p.version < 62 {
   140  		panic(fmt.Sprintf("body fetch [eth/62+] requested on eth/%d", p.version))
   141  	}
   142  
   143  	if !atomic.CompareAndSwapInt32(&p.blockIdle, 0, 1) {
   144  		return errAlreadyFetching
   145  	}
   146  	p.blockStarted = time.Now()
   147  
   148  	hashes := make([]common.Hash, 0, len(request.Headers))
   149  	for _, header := range request.Headers {
   150  		hashes = append(hashes, header.Hash())
   151  	}
   152  	go p.peer.RequestBodies(hashes)
   153  
   154  	return nil
   155  }
   156  
   157  func (p *peerConnection) FetchReceipts(request *fetchRequest) error {
   158  
   159  	if p.version < 63 {
   160  		panic(fmt.Sprintf("body fetch [eth/63+] requested on eth/%d", p.version))
   161  	}
   162  
   163  	if !atomic.CompareAndSwapInt32(&p.receiptIdle, 0, 1) {
   164  		return errAlreadyFetching
   165  	}
   166  	p.receiptStarted = time.Now()
   167  
   168  	hashes := make([]common.Hash, 0, len(request.Headers))
   169  	for _, header := range request.Headers {
   170  		hashes = append(hashes, header.Hash())
   171  	}
   172  	go p.peer.RequestReceipts(hashes)
   173  
   174  	return nil
   175  }
   176  
   177  func (p *peerConnection) FetchNodeData(hashes []common.Hash) error {
   178  
   179  	if p.version < 63 {
   180  		panic(fmt.Sprintf("node data fetch [eth/63+] requested on eth/%d", p.version))
   181  	}
   182  
   183  	if !atomic.CompareAndSwapInt32(&p.stateIdle, 0, 1) {
   184  		return errAlreadyFetching
   185  	}
   186  	p.stateStarted = time.Now()
   187  
   188  	go p.peer.RequestNodeData(hashes)
   189  
   190  	return nil
   191  }
   192  
   193  func (p *peerConnection) SetHeadersIdle(delivered int) {
   194  	p.setIdle(p.headerStarted, delivered, &p.headerThroughput, &p.headerIdle)
   195  }
   196  
   197  func (p *peerConnection) SetBlocksIdle(delivered int) {
   198  	p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle)
   199  }
   200  
   201  func (p *peerConnection) SetBodiesIdle(delivered int) {
   202  	p.setIdle(p.blockStarted, delivered, &p.blockThroughput, &p.blockIdle)
   203  }
   204  
   205  func (p *peerConnection) SetReceiptsIdle(delivered int) {
   206  	p.setIdle(p.receiptStarted, delivered, &p.receiptThroughput, &p.receiptIdle)
   207  }
   208  
   209  func (p *peerConnection) SetNodeDataIdle(delivered int) {
   210  	p.setIdle(p.stateStarted, delivered, &p.stateThroughput, &p.stateIdle)
   211  }
   212  
   213  func (p *peerConnection) setIdle(started time.Time, delivered int, throughput *float64, idle *int32) {
   214  
   215  	defer atomic.StoreInt32(idle, 0)
   216  
   217  	p.lock.Lock()
   218  	defer p.lock.Unlock()
   219  
   220  	if delivered == 0 {
   221  		*throughput = 0
   222  		return
   223  	}
   224  
   225  	elapsed := time.Since(started) + 1
   226  	measured := float64(delivered) / (float64(elapsed) / float64(time.Second))
   227  
   228  	*throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured
   229  	p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed))
   230  
   231  	p.log.Trace("Peer throughput measurements updated",
   232  		"hps", p.headerThroughput, "bps", p.blockThroughput,
   233  		"rps", p.receiptThroughput, "sps", p.stateThroughput,
   234  		"miss", len(p.lacking), "rtt", p.rtt)
   235  }
   236  
   237  func (p *peerConnection) HeaderCapacity(targetRTT time.Duration) int {
   238  	p.lock.RLock()
   239  	defer p.lock.RUnlock()
   240  
   241  	return int(math.Min(1+math.Max(1, p.headerThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxHeaderFetch)))
   242  }
   243  
   244  func (p *peerConnection) BlockCapacity(targetRTT time.Duration) int {
   245  	p.lock.RLock()
   246  	defer p.lock.RUnlock()
   247  
   248  	return int(math.Min(1+math.Max(1, p.blockThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxBlockFetch)))
   249  }
   250  
   251  func (p *peerConnection) ReceiptCapacity(targetRTT time.Duration) int {
   252  	p.lock.RLock()
   253  	defer p.lock.RUnlock()
   254  
   255  	return int(math.Min(1+math.Max(1, p.receiptThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxReceiptFetch)))
   256  }
   257  
   258  func (p *peerConnection) NodeDataCapacity(targetRTT time.Duration) int {
   259  	p.lock.RLock()
   260  	defer p.lock.RUnlock()
   261  
   262  	return int(math.Min(1+math.Max(1, p.stateThroughput*float64(targetRTT)/float64(time.Second)), float64(MaxStateFetch)))
   263  }
   264  
   265  func (p *peerConnection) MarkLacking(hash common.Hash) {
   266  	p.lock.Lock()
   267  	defer p.lock.Unlock()
   268  
   269  	for len(p.lacking) >= maxLackingHashes {
   270  		for drop := range p.lacking {
   271  			delete(p.lacking, drop)
   272  			break
   273  		}
   274  	}
   275  	p.lacking[hash] = struct{}{}
   276  }
   277  
   278  func (p *peerConnection) Lacks(hash common.Hash) bool {
   279  	p.lock.RLock()
   280  	defer p.lock.RUnlock()
   281  
   282  	_, ok := p.lacking[hash]
   283  	return ok
   284  }
   285  
   286  type peerSet struct {
   287  	peers        map[string]*peerConnection
   288  	newPeerFeed  event.Feed
   289  	peerDropFeed event.Feed
   290  	lock         sync.RWMutex
   291  }
   292  
   293  func newPeerSet() *peerSet {
   294  	return &peerSet{
   295  		peers: make(map[string]*peerConnection),
   296  	}
   297  }
   298  
   299  func (ps *peerSet) SubscribeNewPeers(ch chan<- *peerConnection) event.Subscription {
   300  	return ps.newPeerFeed.Subscribe(ch)
   301  }
   302  
   303  func (ps *peerSet) SubscribePeerDrops(ch chan<- *peerConnection) event.Subscription {
   304  	return ps.peerDropFeed.Subscribe(ch)
   305  }
   306  
   307  func (ps *peerSet) Reset() {
   308  	ps.lock.RLock()
   309  	defer ps.lock.RUnlock()
   310  
   311  	for _, peer := range ps.peers {
   312  		peer.Reset()
   313  	}
   314  }
   315  
   316  func (ps *peerSet) Register(p *peerConnection) error {
   317  
   318  	p.rtt = ps.medianRTT()
   319  
   320  	ps.lock.Lock()
   321  	if _, ok := ps.peers[p.id]; ok {
   322  		ps.lock.Unlock()
   323  		return errAlreadyRegistered
   324  	}
   325  	if len(ps.peers) > 0 {
   326  		p.headerThroughput, p.blockThroughput, p.receiptThroughput, p.stateThroughput = 0, 0, 0, 0
   327  
   328  		for _, peer := range ps.peers {
   329  			peer.lock.RLock()
   330  			p.headerThroughput += peer.headerThroughput
   331  			p.blockThroughput += peer.blockThroughput
   332  			p.receiptThroughput += peer.receiptThroughput
   333  			p.stateThroughput += peer.stateThroughput
   334  			peer.lock.RUnlock()
   335  		}
   336  		p.headerThroughput /= float64(len(ps.peers))
   337  		p.blockThroughput /= float64(len(ps.peers))
   338  		p.receiptThroughput /= float64(len(ps.peers))
   339  		p.stateThroughput /= float64(len(ps.peers))
   340  	}
   341  	ps.peers[p.id] = p
   342  	ps.lock.Unlock()
   343  
   344  	ps.newPeerFeed.Send(p)
   345  	return nil
   346  }
   347  
   348  func (ps *peerSet) Unregister(id string) error {
   349  	ps.lock.Lock()
   350  	p, ok := ps.peers[id]
   351  	if !ok {
   352  		defer ps.lock.Unlock()
   353  		return errNotRegistered
   354  	}
   355  	delete(ps.peers, id)
   356  	ps.lock.Unlock()
   357  
   358  	ps.peerDropFeed.Send(p)
   359  	return nil
   360  }
   361  
   362  func (ps *peerSet) Peer(id string) *peerConnection {
   363  	ps.lock.RLock()
   364  	defer ps.lock.RUnlock()
   365  
   366  	return ps.peers[id]
   367  }
   368  
   369  func (ps *peerSet) Len() int {
   370  	ps.lock.RLock()
   371  	defer ps.lock.RUnlock()
   372  
   373  	return len(ps.peers)
   374  }
   375  
   376  func (ps *peerSet) AllPeers() []*peerConnection {
   377  	ps.lock.RLock()
   378  	defer ps.lock.RUnlock()
   379  
   380  	list := make([]*peerConnection, 0, len(ps.peers))
   381  	for _, p := range ps.peers {
   382  		list = append(list, p)
   383  	}
   384  	return list
   385  }
   386  
   387  func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) {
   388  	idle := func(p *peerConnection) bool {
   389  		return atomic.LoadInt32(&p.headerIdle) == 0
   390  	}
   391  	throughput := func(p *peerConnection) float64 {
   392  		p.lock.RLock()
   393  		defer p.lock.RUnlock()
   394  		return p.headerThroughput
   395  	}
   396  	return ps.idlePeers(62, 64, idle, throughput)
   397  }
   398  
   399  func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) {
   400  	idle := func(p *peerConnection) bool {
   401  		return atomic.LoadInt32(&p.blockIdle) == 0
   402  	}
   403  	throughput := func(p *peerConnection) float64 {
   404  		p.lock.RLock()
   405  		defer p.lock.RUnlock()
   406  		return p.blockThroughput
   407  	}
   408  	return ps.idlePeers(62, 64, idle, throughput)
   409  }
   410  
   411  func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) {
   412  	idle := func(p *peerConnection) bool {
   413  		return atomic.LoadInt32(&p.receiptIdle) == 0
   414  	}
   415  	throughput := func(p *peerConnection) float64 {
   416  		p.lock.RLock()
   417  		defer p.lock.RUnlock()
   418  		return p.receiptThroughput
   419  	}
   420  	return ps.idlePeers(63, 64, idle, throughput)
   421  }
   422  
   423  func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) {
   424  	idle := func(p *peerConnection) bool {
   425  		return atomic.LoadInt32(&p.stateIdle) == 0
   426  	}
   427  	throughput := func(p *peerConnection) float64 {
   428  		p.lock.RLock()
   429  		defer p.lock.RUnlock()
   430  		return p.stateThroughput
   431  	}
   432  	return ps.idlePeers(63, 64, idle, throughput)
   433  }
   434  
   435  func (ps *peerSet) idlePeers(minProtocol, maxProtocol int, idleCheck func(*peerConnection) bool, throughput func(*peerConnection) float64) ([]*peerConnection, int) {
   436  	ps.lock.RLock()
   437  	defer ps.lock.RUnlock()
   438  
   439  	idle, total := make([]*peerConnection, 0, len(ps.peers)), 0
   440  	for _, p := range ps.peers {
   441  		if p.version >= minProtocol && p.version <= maxProtocol {
   442  			if idleCheck(p) {
   443  				idle = append(idle, p)
   444  			}
   445  			total++
   446  		}
   447  	}
   448  	for i := 0; i < len(idle); i++ {
   449  		for j := i + 1; j < len(idle); j++ {
   450  			if throughput(idle[i]) < throughput(idle[j]) {
   451  				idle[i], idle[j] = idle[j], idle[i]
   452  			}
   453  		}
   454  	}
   455  	return idle, total
   456  }
   457  
   458  func (ps *peerSet) medianRTT() time.Duration {
   459  
   460  	ps.lock.RLock()
   461  	defer ps.lock.RUnlock()
   462  
   463  	rtts := make([]float64, 0, len(ps.peers))
   464  	for _, p := range ps.peers {
   465  		p.lock.RLock()
   466  		rtts = append(rtts, float64(p.rtt))
   467  		p.lock.RUnlock()
   468  	}
   469  	sort.Float64s(rtts)
   470  
   471  	median := rttMaxEstimate
   472  	if qosTuningPeers <= len(rtts) {
   473  		median = time.Duration(rtts[qosTuningPeers/2])
   474  	} else if len(rtts) > 0 {
   475  		median = time.Duration(rtts[len(rtts)/2])
   476  	}
   477  
   478  	if median < rttMinEstimate {
   479  		median = rttMinEstimate
   480  	}
   481  	if median > rttMaxEstimate {
   482  		median = rttMaxEstimate
   483  	}
   484  	return median
   485  }