github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/p2p/pex/addrbook.go (about)

     1  // Modified for Tendermint
     2  // Originally Copyright (c) 2013-2014 Conformal Systems LLC.
     3  // https://github.com/conformal/btcd/blob/master/LICENSE
     4  
     5  package pex
     6  
     7  import (
     8  	crand "crypto/rand"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"math"
    12  	"math/rand"
    13  	"net"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/minio/highwayhash"
    18  	"github.com/tendermint/tendermint/crypto"
    19  	tmmath "github.com/tendermint/tendermint/libs/math"
    20  	tmrand "github.com/tendermint/tendermint/libs/rand"
    21  	"github.com/tendermint/tendermint/libs/service"
    22  	"github.com/tendermint/tendermint/p2p"
    23  )
    24  
    25  const (
    26  	bucketTypeNew = 0x01
    27  	bucketTypeOld = 0x02
    28  )
    29  
    30  // AddrBook is an address book used for tracking peers
    31  // so we can gossip about them to others and select
    32  // peers to dial.
    33  // TODO: break this up?
    34  type AddrBook interface {
    35  	service.Service
    36  
    37  	// Add our own addresses so we don't later add ourselves
    38  	AddOurAddress(*p2p.NetAddress)
    39  	// Check if it is our address
    40  	OurAddress(*p2p.NetAddress) bool
    41  
    42  	AddPrivateIDs([]string)
    43  
    44  	// Add and remove an address
    45  	AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error
    46  	RemoveAddress(*p2p.NetAddress)
    47  
    48  	// Check if the address is in the book
    49  	HasAddress(*p2p.NetAddress) bool
    50  
    51  	// Do we need more peers?
    52  	NeedMoreAddrs() bool
    53  	// Is Address Book Empty? Answer should not depend on being in your own
    54  	// address book, or private peers
    55  	Empty() bool
    56  
    57  	// Pick an address to dial
    58  	PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress
    59  
    60  	// Mark address
    61  	MarkGood(p2p.ID)
    62  	MarkAttempt(*p2p.NetAddress)
    63  	MarkBad(*p2p.NetAddress, time.Duration) // Move peer to bad peers list
    64  	// Add bad peers back to addrBook
    65  	ReinstateBadPeers()
    66  
    67  	IsGood(*p2p.NetAddress) bool
    68  	IsBanned(*p2p.NetAddress) bool
    69  
    70  	// Send a selection of addresses to peers
    71  	GetSelection() []*p2p.NetAddress
    72  	// Send a selection of addresses with bias
    73  	GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress
    74  
    75  	Size() int
    76  
    77  	// Persist to disk
    78  	Save()
    79  }
    80  
    81  var _ AddrBook = (*addrBook)(nil)
    82  
    83  // addrBook - concurrency safe peer address manager.
    84  // Implements AddrBook.
    85  type addrBook struct {
    86  	service.BaseService
    87  
    88  	// accessed concurrently
    89  	mtx        sync.Mutex
    90  	rand       *tmrand.Rand
    91  	ourAddrs   map[string]struct{}
    92  	privateIDs map[p2p.ID]struct{}
    93  	addrLookup map[p2p.ID]*knownAddress // new & old
    94  	badPeers   map[p2p.ID]*knownAddress // blacklisted peers
    95  	bucketsOld []map[string]*knownAddress
    96  	bucketsNew []map[string]*knownAddress
    97  	nOld       int
    98  	nNew       int
    99  
   100  	// immutable after creation
   101  	filePath          string
   102  	key               string // random prefix for bucket placement
   103  	routabilityStrict bool
   104  	hashKey           []byte
   105  
   106  	wg sync.WaitGroup
   107  }
   108  
   109  func newHashKey() []byte {
   110  	result := make([]byte, highwayhash.Size)
   111  	crand.Read(result)
   112  	return result
   113  }
   114  
   115  // NewAddrBook creates a new address book.
   116  // Use Start to begin processing asynchronous address updates.
   117  func NewAddrBook(filePath string, routabilityStrict bool) AddrBook {
   118  	am := &addrBook{
   119  		rand:              tmrand.NewRand(),
   120  		ourAddrs:          make(map[string]struct{}),
   121  		privateIDs:        make(map[p2p.ID]struct{}),
   122  		addrLookup:        make(map[p2p.ID]*knownAddress),
   123  		badPeers:          make(map[p2p.ID]*knownAddress),
   124  		filePath:          filePath,
   125  		routabilityStrict: routabilityStrict,
   126  		hashKey:           newHashKey(),
   127  	}
   128  	am.init()
   129  	am.BaseService = *service.NewBaseService(nil, "AddrBook", am)
   130  	return am
   131  }
   132  
   133  // Initialize the buckets.
   134  // When modifying this, don't forget to update loadFromFile()
   135  func (a *addrBook) init() {
   136  	a.key = crypto.CRandHex(24) // 24/2 * 8 = 96 bits
   137  	// New addr buckets
   138  	a.bucketsNew = make([]map[string]*knownAddress, newBucketCount)
   139  	for i := range a.bucketsNew {
   140  		a.bucketsNew[i] = make(map[string]*knownAddress)
   141  	}
   142  	// Old addr buckets
   143  	a.bucketsOld = make([]map[string]*knownAddress, oldBucketCount)
   144  	for i := range a.bucketsOld {
   145  		a.bucketsOld[i] = make(map[string]*knownAddress)
   146  	}
   147  }
   148  
   149  // OnStart implements Service.
   150  func (a *addrBook) OnStart() error {
   151  	if err := a.BaseService.OnStart(); err != nil {
   152  		return err
   153  	}
   154  	a.loadFromFile(a.filePath)
   155  
   156  	// wg.Add to ensure that any invocation of .Wait()
   157  	// later on will wait for saveRoutine to terminate.
   158  	a.wg.Add(1)
   159  	go a.saveRoutine()
   160  
   161  	return nil
   162  }
   163  
   164  // OnStop implements Service.
   165  func (a *addrBook) OnStop() {
   166  	a.BaseService.OnStop()
   167  }
   168  
   169  func (a *addrBook) Wait() {
   170  	a.wg.Wait()
   171  }
   172  
   173  func (a *addrBook) FilePath() string {
   174  	return a.filePath
   175  }
   176  
   177  //-------------------------------------------------------
   178  
   179  // AddOurAddress one of our addresses.
   180  func (a *addrBook) AddOurAddress(addr *p2p.NetAddress) {
   181  	a.mtx.Lock()
   182  	defer a.mtx.Unlock()
   183  
   184  	a.Logger.Debug("Add our address to book", "addr", addr)
   185  	a.ourAddrs[addr.String()] = struct{}{}
   186  }
   187  
   188  // OurAddress returns true if it is our address.
   189  func (a *addrBook) OurAddress(addr *p2p.NetAddress) bool {
   190  	a.mtx.Lock()
   191  	defer a.mtx.Unlock()
   192  
   193  	_, ok := a.ourAddrs[addr.String()]
   194  	return ok
   195  }
   196  
   197  func (a *addrBook) AddPrivateIDs(ids []string) {
   198  	a.mtx.Lock()
   199  	defer a.mtx.Unlock()
   200  
   201  	for _, id := range ids {
   202  		a.privateIDs[p2p.ID(id)] = struct{}{}
   203  	}
   204  }
   205  
   206  // AddAddress implements AddrBook
   207  // Add address to a "new" bucket. If it's already in one, only add it probabilistically.
   208  // Returns error if the addr is non-routable. Does not add self.
   209  // NOTE: addr must not be nil
   210  func (a *addrBook) AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error {
   211  	a.mtx.Lock()
   212  	defer a.mtx.Unlock()
   213  
   214  	return a.addAddress(addr, src)
   215  }
   216  
   217  // RemoveAddress implements AddrBook - removes the address from the book.
   218  func (a *addrBook) RemoveAddress(addr *p2p.NetAddress) {
   219  	a.mtx.Lock()
   220  	defer a.mtx.Unlock()
   221  
   222  	a.removeAddress(addr)
   223  }
   224  
   225  // IsGood returns true if peer was ever marked as good and haven't
   226  // done anything wrong since then.
   227  func (a *addrBook) IsGood(addr *p2p.NetAddress) bool {
   228  	a.mtx.Lock()
   229  	defer a.mtx.Unlock()
   230  
   231  	return a.addrLookup[addr.ID].isOld()
   232  }
   233  
   234  // IsBanned returns true if the peer is currently banned
   235  func (a *addrBook) IsBanned(addr *p2p.NetAddress) bool {
   236  	a.mtx.Lock()
   237  	_, ok := a.badPeers[addr.ID]
   238  	a.mtx.Unlock()
   239  
   240  	return ok
   241  }
   242  
   243  // HasAddress returns true if the address is in the book.
   244  func (a *addrBook) HasAddress(addr *p2p.NetAddress) bool {
   245  	a.mtx.Lock()
   246  	defer a.mtx.Unlock()
   247  
   248  	ka := a.addrLookup[addr.ID]
   249  	return ka != nil
   250  }
   251  
   252  // NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book.
   253  func (a *addrBook) NeedMoreAddrs() bool {
   254  	return a.Size() < needAddressThreshold
   255  }
   256  
   257  // Empty implements AddrBook - returns true if there are no addresses in the address book.
   258  // Does not count the peer appearing in its own address book, or private peers.
   259  func (a *addrBook) Empty() bool {
   260  	return a.Size() == 0
   261  }
   262  
   263  // PickAddress implements AddrBook. It picks an address to connect to.
   264  // The address is picked randomly from an old or new bucket according
   265  // to the biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to that range)
   266  // and determines how biased we are to pick an address from a new bucket.
   267  // PickAddress returns nil if the AddrBook is empty or if we try to pick
   268  // from an empty bucket.
   269  func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress {
   270  	a.mtx.Lock()
   271  	defer a.mtx.Unlock()
   272  
   273  	bookSize := a.size()
   274  	if bookSize <= 0 {
   275  		if bookSize < 0 {
   276  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   277  		}
   278  		return nil
   279  	}
   280  	if biasTowardsNewAddrs > 100 {
   281  		biasTowardsNewAddrs = 100
   282  	}
   283  	if biasTowardsNewAddrs < 0 {
   284  		biasTowardsNewAddrs = 0
   285  	}
   286  
   287  	// Bias between new and old addresses.
   288  	oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(biasTowardsNewAddrs))
   289  	newCorrelation := math.Sqrt(float64(a.nNew)) * float64(biasTowardsNewAddrs)
   290  
   291  	// pick a random peer from a random bucket
   292  	var bucket map[string]*knownAddress
   293  	pickFromOldBucket := (newCorrelation+oldCorrelation)*a.rand.Float64() < oldCorrelation
   294  	if (pickFromOldBucket && a.nOld == 0) ||
   295  		(!pickFromOldBucket && a.nNew == 0) {
   296  		return nil
   297  	}
   298  	// loop until we pick a random non-empty bucket
   299  	for len(bucket) == 0 {
   300  		if pickFromOldBucket {
   301  			bucket = a.bucketsOld[a.rand.Intn(len(a.bucketsOld))]
   302  		} else {
   303  			bucket = a.bucketsNew[a.rand.Intn(len(a.bucketsNew))]
   304  		}
   305  	}
   306  	// pick a random index and loop over the map to return that index
   307  	randIndex := a.rand.Intn(len(bucket))
   308  	for _, ka := range bucket {
   309  		if randIndex == 0 {
   310  			return ka.Addr
   311  		}
   312  		randIndex--
   313  	}
   314  	return nil
   315  }
   316  
   317  // MarkGood implements AddrBook - it marks the peer as good and
   318  // moves it into an "old" bucket.
   319  func (a *addrBook) MarkGood(id p2p.ID) {
   320  	a.mtx.Lock()
   321  	defer a.mtx.Unlock()
   322  
   323  	ka := a.addrLookup[id]
   324  	if ka == nil {
   325  		return
   326  	}
   327  	ka.markGood()
   328  	if ka.isNew() {
   329  		a.moveToOld(ka)
   330  	}
   331  }
   332  
   333  // MarkAttempt implements AddrBook - it marks that an attempt was made to connect to the address.
   334  func (a *addrBook) MarkAttempt(addr *p2p.NetAddress) {
   335  	a.mtx.Lock()
   336  	defer a.mtx.Unlock()
   337  
   338  	ka := a.addrLookup[addr.ID]
   339  	if ka == nil {
   340  		return
   341  	}
   342  	ka.markAttempt()
   343  }
   344  
   345  // MarkBad implements AddrBook. Kicks address out from book, places
   346  // the address in the badPeers pool.
   347  func (a *addrBook) MarkBad(addr *p2p.NetAddress, banTime time.Duration) {
   348  	a.mtx.Lock()
   349  	defer a.mtx.Unlock()
   350  
   351  	if a.addBadPeer(addr, banTime) {
   352  		a.removeAddress(addr)
   353  	}
   354  }
   355  
   356  // ReinstateBadPeers removes bad peers from ban list and places them into a new
   357  // bucket.
   358  func (a *addrBook) ReinstateBadPeers() {
   359  	a.mtx.Lock()
   360  	defer a.mtx.Unlock()
   361  
   362  	for _, ka := range a.badPeers {
   363  		if ka.isBanned() {
   364  			continue
   365  		}
   366  
   367  		bucket, err := a.calcNewBucket(ka.Addr, ka.Src)
   368  		if err != nil {
   369  			a.Logger.Error("Failed to calculate new bucket (bad peer won't be reinstantiated)",
   370  				"addr", ka.Addr, "err", err)
   371  			continue
   372  		}
   373  
   374  		a.addToNewBucket(ka, bucket)
   375  		delete(a.badPeers, ka.ID())
   376  
   377  		a.Logger.Debug("Reinstated address", "addr", ka.Addr)
   378  	}
   379  }
   380  
   381  // GetSelection implements AddrBook.
   382  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   383  // Must never return a nil address.
   384  func (a *addrBook) GetSelection() []*p2p.NetAddress {
   385  	a.mtx.Lock()
   386  	defer a.mtx.Unlock()
   387  
   388  	bookSize := a.size()
   389  	if bookSize <= 0 {
   390  		if bookSize < 0 {
   391  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   392  		}
   393  		return nil
   394  	}
   395  
   396  	numAddresses := tmmath.MaxInt(
   397  		tmmath.MinInt(minGetSelection, bookSize),
   398  		bookSize*getSelectionPercent/100)
   399  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   400  
   401  	// XXX: instead of making a list of all addresses, shuffling, and slicing a random chunk,
   402  	// could we just select a random numAddresses of indexes?
   403  	allAddr := make([]*p2p.NetAddress, bookSize)
   404  	i := 0
   405  	for _, ka := range a.addrLookup {
   406  		allAddr[i] = ka.Addr
   407  		i++
   408  	}
   409  
   410  	// Fisher-Yates shuffle the array. We only need to do the first
   411  	// `numAddresses' since we are throwing the rest.
   412  	for i := 0; i < numAddresses; i++ {
   413  		// pick a number between current index and the end
   414  		j := tmrand.Intn(len(allAddr)-i) + i
   415  		allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
   416  	}
   417  
   418  	// slice off the limit we are willing to share.
   419  	return allAddr[:numAddresses]
   420  }
   421  
   422  func percentageOfNum(p, n int) int {
   423  	return int(math.Round((float64(p) / float64(100)) * float64(n)))
   424  }
   425  
   426  // GetSelectionWithBias implements AddrBook.
   427  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   428  // Must never return a nil address.
   429  //
   430  // Each address is picked randomly from an old or new bucket according to the
   431  // biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to
   432  // that range) and determines how biased we are to pick an address from a new
   433  // bucket.
   434  func (a *addrBook) GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress {
   435  	a.mtx.Lock()
   436  	defer a.mtx.Unlock()
   437  
   438  	bookSize := a.size()
   439  	if bookSize <= 0 {
   440  		if bookSize < 0 {
   441  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   442  		}
   443  		return nil
   444  	}
   445  
   446  	if biasTowardsNewAddrs > 100 {
   447  		biasTowardsNewAddrs = 100
   448  	}
   449  	if biasTowardsNewAddrs < 0 {
   450  		biasTowardsNewAddrs = 0
   451  	}
   452  
   453  	numAddresses := tmmath.MaxInt(
   454  		tmmath.MinInt(minGetSelection, bookSize),
   455  		bookSize*getSelectionPercent/100)
   456  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   457  
   458  	// number of new addresses that, if possible, should be in the beginning of the selection
   459  	// if there are no enough old addrs, will choose new addr instead.
   460  	numRequiredNewAdd := tmmath.MaxInt(percentageOfNum(biasTowardsNewAddrs, numAddresses), numAddresses-a.nOld)
   461  	selection := a.randomPickAddresses(bucketTypeNew, numRequiredNewAdd)
   462  	selection = append(selection, a.randomPickAddresses(bucketTypeOld, numAddresses-len(selection))...)
   463  	return selection
   464  }
   465  
   466  //------------------------------------------------
   467  
   468  // Size returns the number of addresses in the book.
   469  func (a *addrBook) Size() int {
   470  	a.mtx.Lock()
   471  	defer a.mtx.Unlock()
   472  
   473  	return a.size()
   474  }
   475  
   476  func (a *addrBook) size() int {
   477  	return a.nNew + a.nOld
   478  }
   479  
   480  //----------------------------------------------------------
   481  
   482  // Save persists the address book to disk.
   483  func (a *addrBook) Save() {
   484  	a.saveToFile(a.filePath) // thread safe
   485  }
   486  
   487  func (a *addrBook) saveRoutine() {
   488  	defer a.wg.Done()
   489  
   490  	saveFileTicker := time.NewTicker(dumpAddressInterval)
   491  out:
   492  	for {
   493  		select {
   494  		case <-saveFileTicker.C:
   495  			a.saveToFile(a.filePath)
   496  		case <-a.Quit():
   497  			break out
   498  		}
   499  	}
   500  	saveFileTicker.Stop()
   501  	a.saveToFile(a.filePath)
   502  }
   503  
   504  //----------------------------------------------------------
   505  
   506  func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress {
   507  	switch bucketType {
   508  	case bucketTypeNew:
   509  		return a.bucketsNew[bucketIdx]
   510  	case bucketTypeOld:
   511  		return a.bucketsOld[bucketIdx]
   512  	default:
   513  		panic("Invalid bucket type")
   514  	}
   515  }
   516  
   517  // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full.
   518  // NOTE: currently it always returns true.
   519  func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) {
   520  	// Sanity check
   521  	if ka.isOld() {
   522  		a.Logger.Error("Failed Sanity Check! Cant add old address to new bucket", "ka", ka, "bucket", bucketIdx)
   523  		return
   524  	}
   525  
   526  	addrStr := ka.Addr.String()
   527  	bucket := a.getBucket(bucketTypeNew, bucketIdx)
   528  
   529  	// Already exists?
   530  	if _, ok := bucket[addrStr]; ok {
   531  		return
   532  	}
   533  
   534  	// Enforce max addresses.
   535  	if len(bucket) > newBucketSize {
   536  		a.Logger.Debug("new bucket is full, expiring new")
   537  		a.expireNew(bucketIdx)
   538  	}
   539  
   540  	// Add to bucket.
   541  	bucket[addrStr] = ka
   542  	// increment nNew if the peer doesnt already exist in a bucket
   543  	if ka.addBucketRef(bucketIdx) == 1 {
   544  		a.nNew++
   545  	}
   546  
   547  	// Add it to addrLookup
   548  	a.addrLookup[ka.ID()] = ka
   549  }
   550  
   551  // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full.
   552  func (a *addrBook) addToOldBucket(ka *knownAddress, bucketIdx int) bool {
   553  	// Sanity check
   554  	if ka.isNew() {
   555  		a.Logger.Error(fmt.Sprintf("Cannot add new address to old bucket: %v", ka))
   556  		return false
   557  	}
   558  	if len(ka.Buckets) != 0 {
   559  		a.Logger.Error(fmt.Sprintf("Cannot add already old address to another old bucket: %v", ka))
   560  		return false
   561  	}
   562  
   563  	addrStr := ka.Addr.String()
   564  	bucket := a.getBucket(bucketTypeOld, bucketIdx)
   565  
   566  	// Already exists?
   567  	if _, ok := bucket[addrStr]; ok {
   568  		return true
   569  	}
   570  
   571  	// Enforce max addresses.
   572  	if len(bucket) > oldBucketSize {
   573  		return false
   574  	}
   575  
   576  	// Add to bucket.
   577  	bucket[addrStr] = ka
   578  	if ka.addBucketRef(bucketIdx) == 1 {
   579  		a.nOld++
   580  	}
   581  
   582  	// Ensure in addrLookup
   583  	a.addrLookup[ka.ID()] = ka
   584  
   585  	return true
   586  }
   587  
   588  func (a *addrBook) removeFromBucket(ka *knownAddress, bucketType byte, bucketIdx int) {
   589  	if ka.BucketType != bucketType {
   590  		a.Logger.Error(fmt.Sprintf("Bucket type mismatch: %v", ka))
   591  		return
   592  	}
   593  	bucket := a.getBucket(bucketType, bucketIdx)
   594  	delete(bucket, ka.Addr.String())
   595  	if ka.removeBucketRef(bucketIdx) == 0 {
   596  		if bucketType == bucketTypeNew {
   597  			a.nNew--
   598  		} else {
   599  			a.nOld--
   600  		}
   601  		delete(a.addrLookup, ka.ID())
   602  	}
   603  }
   604  
   605  func (a *addrBook) removeFromAllBuckets(ka *knownAddress) {
   606  	for _, bucketIdx := range ka.Buckets {
   607  		bucket := a.getBucket(ka.BucketType, bucketIdx)
   608  		delete(bucket, ka.Addr.String())
   609  	}
   610  	ka.Buckets = nil
   611  	if ka.BucketType == bucketTypeNew {
   612  		a.nNew--
   613  	} else {
   614  		a.nOld--
   615  	}
   616  	delete(a.addrLookup, ka.ID())
   617  }
   618  
   619  //----------------------------------------------------------
   620  
   621  func (a *addrBook) pickOldest(bucketType byte, bucketIdx int) *knownAddress {
   622  	bucket := a.getBucket(bucketType, bucketIdx)
   623  	var oldest *knownAddress
   624  	for _, ka := range bucket {
   625  		if oldest == nil || ka.LastAttempt.Before(oldest.LastAttempt) {
   626  			oldest = ka
   627  		}
   628  	}
   629  	return oldest
   630  }
   631  
   632  // adds the address to a "new" bucket. if its already in one,
   633  // it only adds it probabilistically
   634  func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
   635  	if addr == nil || src == nil {
   636  		return ErrAddrBookNilAddr{addr, src}
   637  	}
   638  
   639  	if err := addr.Valid(); err != nil {
   640  		return ErrAddrBookInvalidAddr{Addr: addr, AddrErr: err}
   641  	}
   642  
   643  	if _, ok := a.badPeers[addr.ID]; ok {
   644  		return ErrAddressBanned{addr}
   645  	}
   646  
   647  	if _, ok := a.privateIDs[addr.ID]; ok {
   648  		return ErrAddrBookPrivate{addr}
   649  	}
   650  
   651  	if _, ok := a.privateIDs[src.ID]; ok {
   652  		return ErrAddrBookPrivateSrc{src}
   653  	}
   654  
   655  	// TODO: we should track ourAddrs by ID and by IP:PORT and refuse both.
   656  	if _, ok := a.ourAddrs[addr.String()]; ok {
   657  		return ErrAddrBookSelf{addr}
   658  	}
   659  
   660  	if a.routabilityStrict && !addr.Routable() {
   661  		return ErrAddrBookNonRoutable{addr}
   662  	}
   663  
   664  	ka := a.addrLookup[addr.ID]
   665  	if ka != nil {
   666  		// If its already old and the addr is the same, ignore it.
   667  		if ka.isOld() && ka.Addr.Equals(addr) {
   668  			return nil
   669  		}
   670  		// Already in max new buckets.
   671  		if len(ka.Buckets) == maxNewBucketsPerAddress {
   672  			return nil
   673  		}
   674  		// The more entries we have, the less likely we are to add more.
   675  		factor := int32(2 * len(ka.Buckets))
   676  		if a.rand.Int31n(factor) != 0 {
   677  			return nil
   678  		}
   679  	} else {
   680  		ka = newKnownAddress(addr, src)
   681  	}
   682  
   683  	bucket, err := a.calcNewBucket(addr, src)
   684  	if err != nil {
   685  		return err
   686  	}
   687  	a.addToNewBucket(ka, bucket)
   688  	return nil
   689  }
   690  
   691  func (a *addrBook) randomPickAddresses(bucketType byte, num int) []*p2p.NetAddress {
   692  	var buckets []map[string]*knownAddress
   693  	switch bucketType {
   694  	case bucketTypeNew:
   695  		buckets = a.bucketsNew
   696  	case bucketTypeOld:
   697  		buckets = a.bucketsOld
   698  	default:
   699  		panic("unexpected bucketType")
   700  	}
   701  	total := 0
   702  	for _, bucket := range buckets {
   703  		total += len(bucket)
   704  	}
   705  	addresses := make([]*knownAddress, 0, total)
   706  	for _, bucket := range buckets {
   707  		for _, ka := range bucket {
   708  			addresses = append(addresses, ka)
   709  		}
   710  	}
   711  	selection := make([]*p2p.NetAddress, 0, num)
   712  	chosenSet := make(map[string]bool, num)
   713  	rand.Shuffle(total, func(i, j int) {
   714  		addresses[i], addresses[j] = addresses[j], addresses[i]
   715  	})
   716  	for _, addr := range addresses {
   717  		if chosenSet[addr.Addr.String()] {
   718  			continue
   719  		}
   720  		chosenSet[addr.Addr.String()] = true
   721  		selection = append(selection, addr.Addr)
   722  		if len(selection) >= num {
   723  			return selection
   724  		}
   725  	}
   726  	return selection
   727  }
   728  
   729  // Make space in the new buckets by expiring the really bad entries.
   730  // If no bad entries are available we remove the oldest.
   731  func (a *addrBook) expireNew(bucketIdx int) {
   732  	for addrStr, ka := range a.bucketsNew[bucketIdx] {
   733  		// If an entry is bad, throw it away
   734  		if ka.isBad() {
   735  			a.Logger.Debug(fmt.Sprintf("expiring bad address %v", addrStr))
   736  			a.removeFromBucket(ka, bucketTypeNew, bucketIdx)
   737  			return
   738  		}
   739  	}
   740  
   741  	// If we haven't thrown out a bad entry, throw out the oldest entry
   742  	oldest := a.pickOldest(bucketTypeNew, bucketIdx)
   743  	a.removeFromBucket(oldest, bucketTypeNew, bucketIdx)
   744  }
   745  
   746  // Promotes an address from new to old. If the destination bucket is full,
   747  // demote the oldest one to a "new" bucket.
   748  // TODO: Demote more probabilistically?
   749  func (a *addrBook) moveToOld(ka *knownAddress) error {
   750  	// Sanity check
   751  	if ka.isOld() {
   752  		a.Logger.Error(fmt.Sprintf("Cannot promote address that is already old %v", ka))
   753  		return nil
   754  	}
   755  	if len(ka.Buckets) == 0 {
   756  		a.Logger.Error(fmt.Sprintf("Cannot promote address that isn't in any new buckets %v", ka))
   757  		return nil
   758  	}
   759  
   760  	// Remove from all (new) buckets.
   761  	a.removeFromAllBuckets(ka)
   762  	// It's officially old now.
   763  	ka.BucketType = bucketTypeOld
   764  
   765  	// Try to add it to its oldBucket destination.
   766  	oldBucketIdx, err := a.calcOldBucket(ka.Addr)
   767  	if err != nil {
   768  		return err
   769  	}
   770  	added := a.addToOldBucket(ka, oldBucketIdx)
   771  	if !added {
   772  		// No room; move the oldest to a new bucket
   773  		oldest := a.pickOldest(bucketTypeOld, oldBucketIdx)
   774  		a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx)
   775  		newBucketIdx, err := a.calcNewBucket(oldest.Addr, oldest.Src)
   776  		if err != nil {
   777  			return err
   778  		}
   779  		a.addToNewBucket(oldest, newBucketIdx)
   780  
   781  		// Finally, add our ka to old bucket again.
   782  		added = a.addToOldBucket(ka, oldBucketIdx)
   783  		if !added {
   784  			a.Logger.Error(fmt.Sprintf("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx))
   785  		}
   786  	}
   787  	return nil
   788  }
   789  
   790  func (a *addrBook) removeAddress(addr *p2p.NetAddress) {
   791  	ka := a.addrLookup[addr.ID]
   792  	if ka == nil {
   793  		return
   794  	}
   795  	a.Logger.Debug("Remove address from book", "addr", addr)
   796  	a.removeFromAllBuckets(ka)
   797  }
   798  
   799  func (a *addrBook) addBadPeer(addr *p2p.NetAddress, banTime time.Duration) bool {
   800  	// check it exists in addrbook
   801  	ka := a.addrLookup[addr.ID]
   802  	// check address is not already there
   803  	if ka == nil {
   804  		return false
   805  	}
   806  
   807  	if _, alreadyBadPeer := a.badPeers[addr.ID]; !alreadyBadPeer {
   808  		// add to bad peer list
   809  		ka.ban(banTime)
   810  		a.badPeers[addr.ID] = ka
   811  		a.Logger.Error("Add address to blacklist", "addr", addr)
   812  	}
   813  	return true
   814  }
   815  
   816  //---------------------------------------------------------------------
   817  // calculate bucket placements
   818  
   819  // hash(key + sourcegroup + int64(hash(key + group + sourcegroup)) % bucket_per_group) % num_new_buckets
   820  func (a *addrBook) calcNewBucket(addr, src *p2p.NetAddress) (int, error) {
   821  	data1 := []byte{}
   822  	data1 = append(data1, []byte(a.key)...)
   823  	data1 = append(data1, []byte(a.groupKey(addr))...)
   824  	data1 = append(data1, []byte(a.groupKey(src))...)
   825  	hash1, err := a.hash(data1)
   826  	if err != nil {
   827  		return 0, err
   828  	}
   829  	hash64 := binary.BigEndian.Uint64(hash1)
   830  	hash64 %= newBucketsPerGroup
   831  	var hashbuf [8]byte
   832  	binary.BigEndian.PutUint64(hashbuf[:], hash64)
   833  	data2 := []byte{}
   834  	data2 = append(data2, []byte(a.key)...)
   835  	data2 = append(data2, a.groupKey(src)...)
   836  	data2 = append(data2, hashbuf[:]...)
   837  
   838  	hash2, err := a.hash(data2)
   839  	if err != nil {
   840  		return 0, err
   841  	}
   842  	result := int(binary.BigEndian.Uint64(hash2) % newBucketCount)
   843  	return result, nil
   844  }
   845  
   846  // hash(key + group + int64(hash(key + addr)) % buckets_per_group) % num_old_buckets
   847  func (a *addrBook) calcOldBucket(addr *p2p.NetAddress) (int, error) {
   848  	data1 := []byte{}
   849  	data1 = append(data1, []byte(a.key)...)
   850  	data1 = append(data1, []byte(addr.String())...)
   851  	hash1, err := a.hash(data1)
   852  	if err != nil {
   853  		return 0, err
   854  	}
   855  	hash64 := binary.BigEndian.Uint64(hash1)
   856  	hash64 %= oldBucketsPerGroup
   857  	var hashbuf [8]byte
   858  	binary.BigEndian.PutUint64(hashbuf[:], hash64)
   859  	data2 := []byte{}
   860  	data2 = append(data2, []byte(a.key)...)
   861  	data2 = append(data2, a.groupKey(addr)...)
   862  	data2 = append(data2, hashbuf[:]...)
   863  
   864  	hash2, err := a.hash(data2)
   865  	if err != nil {
   866  		return 0, err
   867  	}
   868  	result := int(binary.BigEndian.Uint64(hash2) % oldBucketCount)
   869  	return result, nil
   870  }
   871  
   872  // Return a string representing the network group of this address.
   873  // This is the /16 for IPv4 (e.g. 1.2.0.0), the /32 (/36 for he.net) for IPv6, the string
   874  // "local" for a local address and the string "unroutable" for an unroutable
   875  // address.
   876  func (a *addrBook) groupKey(na *p2p.NetAddress) string {
   877  	return groupKeyFor(na, a.routabilityStrict)
   878  }
   879  
   880  func groupKeyFor(na *p2p.NetAddress, routabilityStrict bool) string {
   881  	if routabilityStrict && na.Local() {
   882  		return "local"
   883  	}
   884  	if routabilityStrict && !na.Routable() {
   885  		return "unroutable"
   886  	}
   887  
   888  	if ipv4 := na.IP.To4(); ipv4 != nil {
   889  		return na.IP.Mask(net.CIDRMask(16, 32)).String()
   890  	}
   891  
   892  	if na.RFC6145() || na.RFC6052() {
   893  		// last four bytes are the ip address
   894  		ip := na.IP[12:16]
   895  		return ip.Mask(net.CIDRMask(16, 32)).String()
   896  	}
   897  
   898  	if na.RFC3964() {
   899  		ip := na.IP[2:6]
   900  		return ip.Mask(net.CIDRMask(16, 32)).String()
   901  	}
   902  
   903  	if na.RFC4380() {
   904  		// teredo tunnels have the last 4 bytes as the v4 address XOR
   905  		// 0xff.
   906  		ip := net.IP(make([]byte, 4))
   907  		for i, byte := range na.IP[12:16] {
   908  			ip[i] = byte ^ 0xff
   909  		}
   910  		return ip.Mask(net.CIDRMask(16, 32)).String()
   911  	}
   912  
   913  	if na.OnionCatTor() {
   914  		// group is keyed off the first 4 bits of the actual onion key.
   915  		return fmt.Sprintf("tor:%d", na.IP[6]&((1<<4)-1))
   916  	}
   917  
   918  	// OK, so now we know ourselves to be a IPv6 address.
   919  	// bitcoind uses /32 for everything, except for Hurricane Electric's
   920  	// (he.net) IP range, which it uses /36 for.
   921  	bits := 32
   922  	heNet := &net.IPNet{IP: net.ParseIP("2001:470::"), Mask: net.CIDRMask(32, 128)}
   923  	if heNet.Contains(na.IP) {
   924  		bits = 36
   925  	}
   926  	ipv6Mask := net.CIDRMask(bits, 128)
   927  	return na.IP.Mask(ipv6Mask).String()
   928  }
   929  
   930  func (a *addrBook) hash(b []byte) ([]byte, error) {
   931  	hasher, err := highwayhash.New64(a.hashKey)
   932  	if err != nil {
   933  		return nil, err
   934  	}
   935  	hasher.Write(b)
   936  	return hasher.Sum(nil), nil
   937  }