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