github.com/btcsuite/btcd@v0.24.0/addrmgr/knownaddress.go (about)

     1  // Copyright (c) 2013-2014 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package addrmgr
     6  
     7  import (
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/btcsuite/btcd/wire"
    12  )
    13  
    14  // KnownAddress tracks information about a known network address that is used
    15  // to determine how viable an address is.
    16  type KnownAddress struct {
    17  	mtx         sync.RWMutex // na and lastattempt
    18  	na          *wire.NetAddressV2
    19  	srcAddr     *wire.NetAddressV2
    20  	attempts    int
    21  	lastattempt time.Time
    22  	lastsuccess time.Time
    23  	tried       bool
    24  	refs        int // reference count of new buckets
    25  }
    26  
    27  // NetAddress returns the underlying wire.NetAddressV2 associated with the
    28  // known address.
    29  func (ka *KnownAddress) NetAddress() *wire.NetAddressV2 {
    30  	ka.mtx.RLock()
    31  	defer ka.mtx.RUnlock()
    32  	return ka.na
    33  }
    34  
    35  // LastAttempt returns the last time the known address was attempted.
    36  func (ka *KnownAddress) LastAttempt() time.Time {
    37  	ka.mtx.RLock()
    38  	defer ka.mtx.RUnlock()
    39  	return ka.lastattempt
    40  }
    41  
    42  // Services returns the services supported by the peer with the known address.
    43  func (ka *KnownAddress) Services() wire.ServiceFlag {
    44  	ka.mtx.RLock()
    45  	defer ka.mtx.RUnlock()
    46  	return ka.na.Services
    47  }
    48  
    49  // The unexported methods, chance and isBad, are used from within AddrManager
    50  // where KnownAddress field access is synchronized via it's own Mutex.
    51  
    52  // chance returns the selection probability for a known address.  The priority
    53  // depends upon how recently the address has been seen, how recently it was last
    54  // attempted and how often attempts to connect to it have failed.
    55  func (ka *KnownAddress) chance() float64 {
    56  	now := time.Now()
    57  	lastAttempt := now.Sub(ka.lastattempt)
    58  
    59  	if lastAttempt < 0 {
    60  		lastAttempt = 0
    61  	}
    62  
    63  	c := 1.0
    64  
    65  	// Very recent attempts are less likely to be retried.
    66  	if lastAttempt < 10*time.Minute {
    67  		c *= 0.01
    68  	}
    69  
    70  	// Failed attempts deprioritise.
    71  	for i := ka.attempts; i > 0; i-- {
    72  		c /= 1.5
    73  	}
    74  
    75  	return c
    76  }
    77  
    78  // isBad returns true if the address in question has not been tried in the last
    79  // minute and meets one of the following criteria:
    80  // 1) It claims to be from the future
    81  // 2) It hasn't been seen in over a month
    82  // 3) It has failed at least three times and never succeeded
    83  // 4) It has failed ten times in the last week
    84  // All addresses that meet these criteria are assumed to be worthless and not
    85  // worth keeping hold of.
    86  func (ka *KnownAddress) isBad() bool {
    87  	if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) {
    88  		return false
    89  	}
    90  
    91  	// From the future?
    92  	if ka.na.Timestamp.After(time.Now().Add(10 * time.Minute)) {
    93  		return true
    94  	}
    95  
    96  	// Over a month old?
    97  	if ka.na.Timestamp.Before(time.Now().Add(-1 * numMissingDays * time.Hour * 24)) {
    98  		return true
    99  	}
   100  
   101  	// Never succeeded?
   102  	if ka.lastsuccess.IsZero() && ka.attempts >= numRetries {
   103  		return true
   104  	}
   105  
   106  	// Hasn't succeeded in too long?
   107  	if !ka.lastsuccess.After(time.Now().Add(-1*minBadDays*time.Hour*24)) &&
   108  		ka.attempts >= maxFailures {
   109  		return true
   110  	}
   111  
   112  	return false
   113  }