github.com/okex/exchain@v1.8.0/libs/tendermint/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  	"encoding/binary"
     9  	"fmt"
    10  	"hash"
    11  	"math"
    12  	"math/rand"
    13  	"net"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/minio/highwayhash"
    18  	"github.com/okex/exchain/libs/tendermint/crypto"
    19  	tmmath "github.com/okex/exchain/libs/tendermint/libs/math"
    20  	tmrand "github.com/okex/exchain/libs/tendermint/libs/rand"
    21  	"github.com/okex/exchain/libs/tendermint/libs/service"
    22  	"github.com/okex/exchain/libs/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  	hasher            hash.Hash64
   105  
   106  	wg sync.WaitGroup
   107  }
   108  
   109  func mustNewHasher() hash.Hash64 {
   110  	key := crypto.CRandBytes(highwayhash.Size)
   111  	hasher, err := highwayhash.New64(key)
   112  	if err != nil {
   113  		panic(err)
   114  	}
   115  	return hasher
   116  }
   117  
   118  // NewAddrBook creates a new address book.
   119  // Use Start to begin processing asynchronous address updates.
   120  func NewAddrBook(filePath string, routabilityStrict bool) AddrBook {
   121  	am := &addrBook{
   122  		rand:              tmrand.NewRand(),
   123  		ourAddrs:          make(map[string]struct{}),
   124  		privateIDs:        make(map[p2p.ID]struct{}),
   125  		addrLookup:        make(map[p2p.ID]*knownAddress),
   126  		badPeers:          make(map[p2p.ID]*knownAddress),
   127  		filePath:          filePath,
   128  		routabilityStrict: routabilityStrict,
   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  	a.hasher = mustNewHasher()
   150  }
   151  
   152  // OnStart implements Service.
   153  func (a *addrBook) OnStart() error {
   154  	if err := a.BaseService.OnStart(); err != nil {
   155  		return err
   156  	}
   157  	a.loadFromFile(a.filePath)
   158  
   159  	// wg.Add to ensure that any invocation of .Wait()
   160  	// later on will wait for saveRoutine to terminate.
   161  	a.wg.Add(1)
   162  	go a.saveRoutine()
   163  
   164  	return nil
   165  }
   166  
   167  // OnStop implements Service.
   168  func (a *addrBook) OnStop() {
   169  	a.BaseService.OnStop()
   170  }
   171  
   172  func (a *addrBook) Wait() {
   173  	a.wg.Wait()
   174  }
   175  
   176  func (a *addrBook) FilePath() string {
   177  	return a.filePath
   178  }
   179  
   180  //-------------------------------------------------------
   181  
   182  // AddOurAddress one of our addresses.
   183  func (a *addrBook) AddOurAddress(addr *p2p.NetAddress) {
   184  	a.mtx.Lock()
   185  	defer a.mtx.Unlock()
   186  
   187  	a.Logger.Info("Add our address to book", "addr", addr)
   188  	a.ourAddrs[addr.String()] = struct{}{}
   189  }
   190  
   191  // OurAddress returns true if it is our address.
   192  func (a *addrBook) OurAddress(addr *p2p.NetAddress) bool {
   193  	a.mtx.Lock()
   194  	defer a.mtx.Unlock()
   195  
   196  	_, ok := a.ourAddrs[addr.String()]
   197  	return ok
   198  }
   199  
   200  func (a *addrBook) AddPrivateIDs(ids []string) {
   201  	a.mtx.Lock()
   202  	defer a.mtx.Unlock()
   203  
   204  	for _, id := range ids {
   205  		a.privateIDs[p2p.ID(id)] = struct{}{}
   206  	}
   207  }
   208  
   209  // AddAddress implements AddrBook
   210  // Add address to a "new" bucket. If it's already in one, only add it probabilistically.
   211  // Returns error if the addr is non-routable. Does not add self.
   212  // NOTE: addr must not be nil
   213  func (a *addrBook) AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error {
   214  	a.mtx.Lock()
   215  	defer a.mtx.Unlock()
   216  
   217  	return a.addAddress(addr, src)
   218  }
   219  
   220  // RemoveAddress implements AddrBook - removes the address from the book.
   221  func (a *addrBook) RemoveAddress(addr *p2p.NetAddress) {
   222  	a.mtx.Lock()
   223  	defer a.mtx.Unlock()
   224  
   225  	a.removeAddress(addr)
   226  }
   227  
   228  // IsGood returns true if peer was ever marked as good and haven't
   229  // done anything wrong since then.
   230  func (a *addrBook) IsGood(addr *p2p.NetAddress) bool {
   231  	a.mtx.Lock()
   232  	defer a.mtx.Unlock()
   233  
   234  	return a.addrLookup[addr.ID].isOld()
   235  }
   236  
   237  // IsBanned returns true if the peer is currently banned
   238  func (a *addrBook) IsBanned(addr *p2p.NetAddress) bool {
   239  	a.mtx.Lock()
   240  	_, ok := a.badPeers[addr.ID]
   241  	a.mtx.Unlock()
   242  
   243  	return ok
   244  }
   245  
   246  // HasAddress returns true if the address is in the book.
   247  func (a *addrBook) HasAddress(addr *p2p.NetAddress) bool {
   248  	a.mtx.Lock()
   249  	defer a.mtx.Unlock()
   250  
   251  	ka := a.addrLookup[addr.ID]
   252  	return ka != nil
   253  }
   254  
   255  // NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book.
   256  func (a *addrBook) NeedMoreAddrs() bool {
   257  	return a.Size() < needAddressThreshold
   258  }
   259  
   260  // Empty implements AddrBook - returns true if there are no addresses in the address book.
   261  // Does not count the peer appearing in its own address book, or private peers.
   262  func (a *addrBook) Empty() bool {
   263  	return a.Size() == 0
   264  }
   265  
   266  // PickAddress implements AddrBook. It picks an address to connect to.
   267  // The address is picked randomly from an old or new bucket according
   268  // to the biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to that range)
   269  // and determines how biased we are to pick an address from a new bucket.
   270  // PickAddress returns nil if the AddrBook is empty or if we try to pick
   271  // from an empty bucket.
   272  func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress {
   273  	a.mtx.Lock()
   274  	defer a.mtx.Unlock()
   275  
   276  	bookSize := a.size()
   277  	if bookSize <= 0 {
   278  		if bookSize < 0 {
   279  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   280  		}
   281  		return nil
   282  	}
   283  	if biasTowardsNewAddrs > 100 {
   284  		biasTowardsNewAddrs = 100
   285  	}
   286  	if biasTowardsNewAddrs < 0 {
   287  		biasTowardsNewAddrs = 0
   288  	}
   289  
   290  	// Bias between new and old addresses.
   291  	oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(biasTowardsNewAddrs))
   292  	newCorrelation := math.Sqrt(float64(a.nNew)) * float64(biasTowardsNewAddrs)
   293  
   294  	// pick a random peer from a random bucket
   295  	var bucket map[string]*knownAddress
   296  	pickFromOldBucket := (newCorrelation+oldCorrelation)*a.rand.Float64() < oldCorrelation
   297  	if (pickFromOldBucket && a.nOld == 0) ||
   298  		(!pickFromOldBucket && a.nNew == 0) {
   299  		return nil
   300  	}
   301  	// loop until we pick a random non-empty bucket
   302  	for len(bucket) == 0 {
   303  		if pickFromOldBucket {
   304  			bucket = a.bucketsOld[a.rand.Intn(len(a.bucketsOld))]
   305  		} else {
   306  			bucket = a.bucketsNew[a.rand.Intn(len(a.bucketsNew))]
   307  		}
   308  	}
   309  	// pick a random index and loop over the map to return that index
   310  	randIndex := a.rand.Intn(len(bucket))
   311  	for _, ka := range bucket {
   312  		if randIndex == 0 {
   313  			return ka.Addr
   314  		}
   315  		randIndex--
   316  	}
   317  	return nil
   318  }
   319  
   320  // MarkGood implements AddrBook - it marks the peer as good and
   321  // moves it into an "old" bucket.
   322  func (a *addrBook) MarkGood(id p2p.ID) {
   323  	a.mtx.Lock()
   324  	defer a.mtx.Unlock()
   325  
   326  	ka := a.addrLookup[id]
   327  	if ka == nil {
   328  		return
   329  	}
   330  	ka.markGood()
   331  	if ka.isNew() {
   332  		a.moveToOld(ka)
   333  	}
   334  }
   335  
   336  // MarkAttempt implements AddrBook - it marks that an attempt was made to connect to the address.
   337  func (a *addrBook) MarkAttempt(addr *p2p.NetAddress) {
   338  	a.mtx.Lock()
   339  	defer a.mtx.Unlock()
   340  
   341  	ka := a.addrLookup[addr.ID]
   342  	if ka == nil {
   343  		return
   344  	}
   345  	ka.markAttempt()
   346  }
   347  
   348  // MarkBad implements AddrBook. Kicks address out from book, places
   349  // the address in the badPeers pool.
   350  func (a *addrBook) MarkBad(addr *p2p.NetAddress, banTime time.Duration) {
   351  	a.mtx.Lock()
   352  	defer a.mtx.Unlock()
   353  
   354  	if a.addBadPeer(addr, banTime) {
   355  		a.removeAddress(addr)
   356  	}
   357  }
   358  
   359  // ReinstateBadPeers removes bad peers from ban list and places them into a new
   360  // bucket.
   361  func (a *addrBook) ReinstateBadPeers() {
   362  	a.mtx.Lock()
   363  	defer a.mtx.Unlock()
   364  
   365  	for _, ka := range a.badPeers {
   366  		if ka.isBanned() {
   367  			continue
   368  		}
   369  
   370  		bucket, err := a.calcNewBucket(ka.Addr, ka.Src)
   371  		if err != nil {
   372  			a.Logger.Error("Failed to calculate new bucket (bad peer won't be reinstantiated)",
   373  				"addr", ka.Addr, "err", err)
   374  			continue
   375  		}
   376  
   377  		a.addToNewBucket(ka, bucket)
   378  		delete(a.badPeers, ka.ID())
   379  
   380  		a.Logger.Info("Reinstated address", "addr", ka.Addr)
   381  	}
   382  }
   383  
   384  // GetSelection implements AddrBook.
   385  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   386  // Must never return a nil address.
   387  func (a *addrBook) GetSelection() []*p2p.NetAddress {
   388  	a.mtx.Lock()
   389  	defer a.mtx.Unlock()
   390  
   391  	bookSize := a.size()
   392  	if bookSize <= 0 {
   393  		if bookSize < 0 {
   394  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   395  		}
   396  		return nil
   397  	}
   398  
   399  	numAddresses := tmmath.MaxInt(
   400  		tmmath.MinInt(minGetSelection, bookSize),
   401  		bookSize*getSelectionPercent/100)
   402  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   403  
   404  	// XXX: instead of making a list of all addresses, shuffling, and slicing a random chunk,
   405  	// could we just select a random numAddresses of indexes?
   406  	allAddr := make([]*p2p.NetAddress, bookSize)
   407  	i := 0
   408  	for _, ka := range a.addrLookup {
   409  		allAddr[i] = ka.Addr
   410  		i++
   411  	}
   412  
   413  	// Fisher-Yates shuffle the array. We only need to do the first
   414  	// `numAddresses' since we are throwing the rest.
   415  	for i := 0; i < numAddresses; i++ {
   416  		// pick a number between current index and the end
   417  		j := tmrand.Intn(len(allAddr)-i) + i
   418  		allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
   419  	}
   420  
   421  	// slice off the limit we are willing to share.
   422  	return allAddr[:numAddresses]
   423  }
   424  
   425  func percentageOfNum(p, n int) int {
   426  	return int(math.Round((float64(p) / float64(100)) * float64(n)))
   427  }
   428  
   429  // GetSelectionWithBias implements AddrBook.
   430  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   431  // Must never return a nil address.
   432  //
   433  // Each address is picked randomly from an old or new bucket according to the
   434  // biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to
   435  // that range) and determines how biased we are to pick an address from a new
   436  // bucket.
   437  func (a *addrBook) GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress {
   438  	a.mtx.Lock()
   439  	defer a.mtx.Unlock()
   440  
   441  	bookSize := a.size()
   442  	if bookSize <= 0 {
   443  		if bookSize < 0 {
   444  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   445  		}
   446  		return nil
   447  	}
   448  
   449  	if biasTowardsNewAddrs > 100 {
   450  		biasTowardsNewAddrs = 100
   451  	}
   452  	if biasTowardsNewAddrs < 0 {
   453  		biasTowardsNewAddrs = 0
   454  	}
   455  
   456  	numAddresses := tmmath.MaxInt(
   457  		tmmath.MinInt(minGetSelection, bookSize),
   458  		bookSize*getSelectionPercent/100)
   459  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   460  
   461  	// number of new addresses that, if possible, should be in the beginning of the selection
   462  	// if there are no enough old addrs, will choose new addr instead.
   463  	numRequiredNewAdd := tmmath.MaxInt(percentageOfNum(biasTowardsNewAddrs, numAddresses), numAddresses-a.nOld)
   464  	selection := a.randomPickAddresses(bucketTypeNew, numRequiredNewAdd)
   465  	selection = append(selection, a.randomPickAddresses(bucketTypeOld, numAddresses-len(selection))...)
   466  	return selection
   467  }
   468  
   469  //------------------------------------------------
   470  
   471  // Size returns the number of addresses in the book.
   472  func (a *addrBook) Size() int {
   473  	a.mtx.Lock()
   474  	defer a.mtx.Unlock()
   475  
   476  	return a.size()
   477  }
   478  
   479  func (a *addrBook) size() int {
   480  	return a.nNew + a.nOld
   481  }
   482  
   483  //----------------------------------------------------------
   484  
   485  // Save persists the address book to disk.
   486  func (a *addrBook) Save() {
   487  	a.saveToFile(a.filePath) // thread safe
   488  }
   489  
   490  func (a *addrBook) saveRoutine() {
   491  	defer a.wg.Done()
   492  
   493  	saveFileTicker := time.NewTicker(dumpAddressInterval)
   494  out:
   495  	for {
   496  		select {
   497  		case <-saveFileTicker.C:
   498  			a.saveToFile(a.filePath)
   499  		case <-a.Quit():
   500  			break out
   501  		}
   502  	}
   503  	saveFileTicker.Stop()
   504  	a.saveToFile(a.filePath)
   505  }
   506  
   507  //----------------------------------------------------------
   508  
   509  func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress {
   510  	switch bucketType {
   511  	case bucketTypeNew:
   512  		return a.bucketsNew[bucketIdx]
   513  	case bucketTypeOld:
   514  		return a.bucketsOld[bucketIdx]
   515  	default:
   516  		panic("Invalid bucket type")
   517  	}
   518  }
   519  
   520  // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full.
   521  // NOTE: currently it always returns true.
   522  func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) {
   523  	// Sanity check
   524  	if ka.isOld() {
   525  		a.Logger.Error("Failed Sanity Check! Cant add old address to new bucket", "ka", ka, "bucket", bucketIdx)
   526  		return
   527  	}
   528  
   529  	addrStr := ka.Addr.String()
   530  	bucket := a.getBucket(bucketTypeNew, bucketIdx)
   531  
   532  	// Already exists?
   533  	if _, ok := bucket[addrStr]; ok {
   534  		return
   535  	}
   536  
   537  	// Enforce max addresses.
   538  	if len(bucket) > newBucketSize {
   539  		a.Logger.Info("new bucket is full, expiring new")
   540  		a.expireNew(bucketIdx)
   541  	}
   542  
   543  	// Add to bucket.
   544  	bucket[addrStr] = ka
   545  	// increment nNew if the peer doesnt already exist in a bucket
   546  	if ka.addBucketRef(bucketIdx) == 1 {
   547  		a.nNew++
   548  	}
   549  
   550  	// Add it to addrLookup
   551  	a.addrLookup[ka.ID()] = ka
   552  }
   553  
   554  // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full.
   555  func (a *addrBook) addToOldBucket(ka *knownAddress, bucketIdx int) bool {
   556  	// Sanity check
   557  	if ka.isNew() {
   558  		a.Logger.Error(fmt.Sprintf("Cannot add new address to old bucket: %v", ka))
   559  		return false
   560  	}
   561  	if len(ka.Buckets) != 0 {
   562  		a.Logger.Error(fmt.Sprintf("Cannot add already old address to another old bucket: %v", ka))
   563  		return false
   564  	}
   565  
   566  	addrStr := ka.Addr.String()
   567  	bucket := a.getBucket(bucketTypeOld, bucketIdx)
   568  
   569  	// Already exists?
   570  	if _, ok := bucket[addrStr]; ok {
   571  		return true
   572  	}
   573  
   574  	// Enforce max addresses.
   575  	if len(bucket) > oldBucketSize {
   576  		return false
   577  	}
   578  
   579  	// Add to bucket.
   580  	bucket[addrStr] = ka
   581  	if ka.addBucketRef(bucketIdx) == 1 {
   582  		a.nOld++
   583  	}
   584  
   585  	// Ensure in addrLookup
   586  	a.addrLookup[ka.ID()] = ka
   587  
   588  	return true
   589  }
   590  
   591  func (a *addrBook) removeFromBucket(ka *knownAddress, bucketType byte, bucketIdx int) {
   592  	if ka.BucketType != bucketType {
   593  		a.Logger.Error(fmt.Sprintf("Bucket type mismatch: %v", ka))
   594  		return
   595  	}
   596  	bucket := a.getBucket(bucketType, bucketIdx)
   597  	delete(bucket, ka.Addr.String())
   598  	if ka.removeBucketRef(bucketIdx) == 0 {
   599  		if bucketType == bucketTypeNew {
   600  			a.nNew--
   601  		} else {
   602  			a.nOld--
   603  		}
   604  		delete(a.addrLookup, ka.ID())
   605  	}
   606  }
   607  
   608  func (a *addrBook) removeFromAllBuckets(ka *knownAddress) {
   609  	for _, bucketIdx := range ka.Buckets {
   610  		bucket := a.getBucket(ka.BucketType, bucketIdx)
   611  		delete(bucket, ka.Addr.String())
   612  	}
   613  	ka.Buckets = nil
   614  	if ka.BucketType == bucketTypeNew {
   615  		a.nNew--
   616  	} else {
   617  		a.nOld--
   618  	}
   619  	delete(a.addrLookup, ka.ID())
   620  }
   621  
   622  //----------------------------------------------------------
   623  
   624  func (a *addrBook) pickOldest(bucketType byte, bucketIdx int) *knownAddress {
   625  	bucket := a.getBucket(bucketType, bucketIdx)
   626  	var oldest *knownAddress
   627  	for _, ka := range bucket {
   628  		if oldest == nil || ka.LastAttempt.Before(oldest.LastAttempt) {
   629  			oldest = ka
   630  		}
   631  	}
   632  	return oldest
   633  }
   634  
   635  // adds the address to a "new" bucket. if its already in one,
   636  // it only adds it probabilistically
   637  func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
   638  	if addr == nil || src == nil {
   639  		return ErrAddrBookNilAddr{addr, src}
   640  	}
   641  
   642  	if err := addr.Valid(); err != nil {
   643  		return ErrAddrBookInvalidAddr{Addr: addr, AddrErr: err}
   644  	}
   645  
   646  	if _, ok := a.badPeers[addr.ID]; ok {
   647  		return ErrAddressBanned{addr}
   648  	}
   649  
   650  	if _, ok := a.privateIDs[addr.ID]; ok {
   651  		return ErrAddrBookPrivate{addr}
   652  	}
   653  
   654  	if _, ok := a.privateIDs[src.ID]; ok {
   655  		return ErrAddrBookPrivateSrc{src}
   656  	}
   657  
   658  	// TODO: we should track ourAddrs by ID and by IP:PORT and refuse both.
   659  	if _, ok := a.ourAddrs[addr.String()]; ok {
   660  		return ErrAddrBookSelf{addr}
   661  	}
   662  
   663  	if a.routabilityStrict && !addr.Routable() {
   664  		return ErrAddrBookNonRoutable{addr}
   665  	}
   666  
   667  	ka := a.addrLookup[addr.ID]
   668  	if ka != nil {
   669  		// If its already old and the addr is the same, ignore it.
   670  		if ka.isOld() && (ka.Addr.Equals(addr) || ka.Addr.ID == addr.ID) {
   671  			return nil
   672  		}
   673  		// Already in max new buckets.
   674  		if len(ka.Buckets) == maxNewBucketsPerAddress {
   675  			return nil
   676  		}
   677  		// The more entries we have, the less likely we are to add more.
   678  		factor := int32(2 * len(ka.Buckets))
   679  		if a.rand.Int31n(factor) != 0 {
   680  			return nil
   681  		}
   682  	} else {
   683  		ka = newKnownAddress(addr, src)
   684  	}
   685  
   686  	bucket, err := a.calcNewBucket(addr, src)
   687  	if err != nil {
   688  		return err
   689  	}
   690  	a.addToNewBucket(ka, bucket)
   691  	return nil
   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  	a.hasher.Reset()
   935  	a.hasher.Write(b)
   936  	return a.hasher.Sum(nil), nil
   937  }