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