github.com/number571/tendermint@v0.34.11-gost/internal/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  	mrand "math/rand"
    13  	"net"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/number571/tendermint/crypto"
    18  	tmsync "github.com/number571/tendermint/internal/libs/sync"
    19  	"github.com/number571/tendermint/internal/p2p"
    20  	tmmath "github.com/number571/tendermint/libs/math"
    21  	tmrand "github.com/number571/tendermint/libs/rand"
    22  	"github.com/number571/tendermint/libs/service"
    23  	"github.com/number571/tendermint/types"
    24  	"github.com/minio/highwayhash"
    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(types.NodeID)
    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  	ourAddrs   map[string]struct{}
    93  	privateIDs map[types.NodeID]struct{}
    94  	addrLookup map[types.NodeID]*knownAddress // new & old
    95  	badPeers   map[types.NodeID]*knownAddress // blacklisted peers
    96  	bucketsOld []map[string]*knownAddress
    97  	bucketsNew []map[string]*knownAddress
    98  	nOld       int
    99  	nNew       int
   100  
   101  	// immutable after creation
   102  	filePath          string
   103  	key               string // random prefix for bucket placement
   104  	routabilityStrict bool
   105  	hasher            hash.Hash64
   106  
   107  	wg sync.WaitGroup
   108  }
   109  
   110  func mustNewHasher() hash.Hash64 {
   111  	key := crypto.CRandBytes(highwayhash.Size)
   112  	hasher, err := highwayhash.New64(key)
   113  	if err != nil {
   114  		panic(err)
   115  	}
   116  	return hasher
   117  }
   118  
   119  // NewAddrBook creates a new address book.
   120  // Use Start to begin processing asynchronous address updates.
   121  func NewAddrBook(filePath string, routabilityStrict bool) AddrBook {
   122  	am := &addrBook{
   123  		ourAddrs:          make(map[string]struct{}),
   124  		privateIDs:        make(map[types.NodeID]struct{}),
   125  		addrLookup:        make(map[types.NodeID]*knownAddress),
   126  		badPeers:          make(map[types.NodeID]*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[types.NodeID(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  // nolint:gosec // G404: Use of weak random number generator
   273  func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress {
   274  	a.mtx.Lock()
   275  	defer a.mtx.Unlock()
   276  
   277  	bookSize := a.size()
   278  	if bookSize <= 0 {
   279  		if bookSize < 0 {
   280  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   281  		}
   282  		return nil
   283  	}
   284  	if biasTowardsNewAddrs > 100 {
   285  		biasTowardsNewAddrs = 100
   286  	}
   287  	if biasTowardsNewAddrs < 0 {
   288  		biasTowardsNewAddrs = 0
   289  	}
   290  
   291  	// Bias between new and old addresses.
   292  	oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(biasTowardsNewAddrs))
   293  	newCorrelation := math.Sqrt(float64(a.nNew)) * float64(biasTowardsNewAddrs)
   294  
   295  	// pick a random peer from a random bucket
   296  	var bucket map[string]*knownAddress
   297  	pickFromOldBucket := (newCorrelation+oldCorrelation)*mrand.Float64() < oldCorrelation
   298  	if (pickFromOldBucket && a.nOld == 0) ||
   299  		(!pickFromOldBucket && a.nNew == 0) {
   300  		return nil
   301  	}
   302  	// loop until we pick a random non-empty bucket
   303  	for len(bucket) == 0 {
   304  		if pickFromOldBucket {
   305  			bucket = a.bucketsOld[mrand.Intn(len(a.bucketsOld))]
   306  		} else {
   307  			bucket = a.bucketsNew[mrand.Intn(len(a.bucketsNew))]
   308  		}
   309  	}
   310  	// pick a random index and loop over the map to return that index
   311  	randIndex := mrand.Intn(len(bucket))
   312  	for _, ka := range bucket {
   313  		if randIndex == 0 {
   314  			return ka.Addr
   315  		}
   316  		randIndex--
   317  	}
   318  	return nil
   319  }
   320  
   321  // MarkGood implements AddrBook - it marks the peer as good and
   322  // moves it into an "old" bucket.
   323  func (a *addrBook) MarkGood(id types.NodeID) {
   324  	a.mtx.Lock()
   325  	defer a.mtx.Unlock()
   326  
   327  	ka := a.addrLookup[id]
   328  	if ka == nil {
   329  		return
   330  	}
   331  	ka.markGood()
   332  	if ka.isNew() {
   333  		if err := a.moveToOld(ka); err != nil {
   334  			a.Logger.Error("Error moving address to old", "err", err)
   335  		}
   336  	}
   337  }
   338  
   339  // MarkAttempt implements AddrBook - it marks that an attempt was made to connect to the address.
   340  func (a *addrBook) MarkAttempt(addr *p2p.NetAddress) {
   341  	a.mtx.Lock()
   342  	defer a.mtx.Unlock()
   343  
   344  	ka := a.addrLookup[addr.ID]
   345  	if ka == nil {
   346  		return
   347  	}
   348  	ka.markAttempt()
   349  }
   350  
   351  // MarkBad implements AddrBook. Kicks address out from book, places
   352  // the address in the badPeers pool.
   353  func (a *addrBook) MarkBad(addr *p2p.NetAddress, banTime time.Duration) {
   354  	a.mtx.Lock()
   355  	defer a.mtx.Unlock()
   356  
   357  	if a.addBadPeer(addr, banTime) {
   358  		a.removeAddress(addr)
   359  	}
   360  }
   361  
   362  // ReinstateBadPeers removes bad peers from ban list and places them into a new
   363  // bucket.
   364  func (a *addrBook) ReinstateBadPeers() {
   365  	a.mtx.Lock()
   366  	defer a.mtx.Unlock()
   367  
   368  	for _, ka := range a.badPeers {
   369  		if ka.isBanned() {
   370  			continue
   371  		}
   372  
   373  		bucket, err := a.calcNewBucket(ka.Addr, ka.Src)
   374  		if err != nil {
   375  			a.Logger.Error("Failed to calculate new bucket (bad peer won't be reinstantiated)",
   376  				"addr", ka.Addr, "err", err)
   377  			continue
   378  		}
   379  
   380  		if err := a.addToNewBucket(ka, bucket); err != nil {
   381  			a.Logger.Error("Error adding peer to new bucket", "err", err)
   382  		}
   383  		delete(a.badPeers, ka.ID())
   384  
   385  		a.Logger.Info("Reinstated address", "addr", ka.Addr)
   386  	}
   387  }
   388  
   389  // GetSelection implements AddrBook.
   390  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   391  // Must never return a nil address.
   392  func (a *addrBook) GetSelection() []*p2p.NetAddress {
   393  	a.mtx.Lock()
   394  	defer a.mtx.Unlock()
   395  
   396  	bookSize := a.size()
   397  	if bookSize <= 0 {
   398  		if bookSize < 0 {
   399  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   400  		}
   401  		return nil
   402  	}
   403  
   404  	numAddresses := tmmath.MaxInt(
   405  		tmmath.MinInt(minGetSelection, bookSize),
   406  		bookSize*getSelectionPercent/100)
   407  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   408  
   409  	// XXX: instead of making a list of all addresses, shuffling, and slicing a random chunk,
   410  	// could we just select a random numAddresses of indexes?
   411  	allAddr := make([]*p2p.NetAddress, bookSize)
   412  	i := 0
   413  	for _, ka := range a.addrLookup {
   414  		allAddr[i] = ka.Addr
   415  		i++
   416  	}
   417  
   418  	// Fisher-Yates shuffle the array. We only need to do the first
   419  	// `numAddresses' since we are throwing the rest.
   420  	for i := 0; i < numAddresses; i++ {
   421  		// pick a number between current index and the end
   422  		// nolint:gosec // G404: Use of weak random number generator
   423  		j := mrand.Intn(len(allAddr)-i) + i
   424  		allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
   425  	}
   426  
   427  	// slice off the limit we are willing to share.
   428  	return allAddr[:numAddresses]
   429  }
   430  
   431  func percentageOfNum(p, n int) int {
   432  	return int(math.Round((float64(p) / float64(100)) * float64(n)))
   433  }
   434  
   435  // GetSelectionWithBias implements AddrBook.
   436  // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
   437  // Must never return a nil address.
   438  //
   439  // Each address is picked randomly from an old or new bucket according to the
   440  // biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to
   441  // that range) and determines how biased we are to pick an address from a new
   442  // bucket.
   443  func (a *addrBook) GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress {
   444  	a.mtx.Lock()
   445  	defer a.mtx.Unlock()
   446  
   447  	bookSize := a.size()
   448  	if bookSize <= 0 {
   449  		if bookSize < 0 {
   450  			panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld))
   451  		}
   452  		return nil
   453  	}
   454  
   455  	if biasTowardsNewAddrs > 100 {
   456  		biasTowardsNewAddrs = 100
   457  	}
   458  	if biasTowardsNewAddrs < 0 {
   459  		biasTowardsNewAddrs = 0
   460  	}
   461  
   462  	numAddresses := tmmath.MaxInt(
   463  		tmmath.MinInt(minGetSelection, bookSize),
   464  		bookSize*getSelectionPercent/100)
   465  	numAddresses = tmmath.MinInt(maxGetSelection, numAddresses)
   466  
   467  	// number of new addresses that, if possible, should be in the beginning of the selection
   468  	// if there are no enough old addrs, will choose new addr instead.
   469  	numRequiredNewAdd := tmmath.MaxInt(percentageOfNum(biasTowardsNewAddrs, numAddresses), numAddresses-a.nOld)
   470  	selection := a.randomPickAddresses(bucketTypeNew, numRequiredNewAdd)
   471  	selection = append(selection, a.randomPickAddresses(bucketTypeOld, numAddresses-len(selection))...)
   472  	return selection
   473  }
   474  
   475  //------------------------------------------------
   476  
   477  // Size returns the number of addresses in the book.
   478  func (a *addrBook) Size() int {
   479  	a.mtx.Lock()
   480  	defer a.mtx.Unlock()
   481  
   482  	return a.size()
   483  }
   484  
   485  func (a *addrBook) size() int {
   486  	return a.nNew + a.nOld
   487  }
   488  
   489  //----------------------------------------------------------
   490  
   491  // Save persists the address book to disk.
   492  func (a *addrBook) Save() {
   493  	a.saveToFile(a.filePath) // thread safe
   494  }
   495  
   496  func (a *addrBook) saveRoutine() {
   497  	defer a.wg.Done()
   498  
   499  	saveFileTicker := time.NewTicker(dumpAddressInterval)
   500  out:
   501  	for {
   502  		select {
   503  		case <-saveFileTicker.C:
   504  			a.saveToFile(a.filePath)
   505  		case <-a.Quit():
   506  			break out
   507  		}
   508  	}
   509  	saveFileTicker.Stop()
   510  	a.saveToFile(a.filePath)
   511  }
   512  
   513  //----------------------------------------------------------
   514  
   515  func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress {
   516  	switch bucketType {
   517  	case bucketTypeNew:
   518  		return a.bucketsNew[bucketIdx]
   519  	case bucketTypeOld:
   520  		return a.bucketsOld[bucketIdx]
   521  	default:
   522  		panic("Invalid bucket type")
   523  	}
   524  }
   525  
   526  // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full.
   527  // NOTE: currently it always returns true.
   528  func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) error {
   529  	// Consistency check to ensure we don't add an already known address
   530  	if ka.isOld() {
   531  		return errAddrBookOldAddressNewBucket{ka.Addr, bucketIdx}
   532  	}
   533  
   534  	addrStr := ka.Addr.String()
   535  	bucket := a.getBucket(bucketTypeNew, bucketIdx)
   536  
   537  	// Already exists?
   538  	if _, ok := bucket[addrStr]; ok {
   539  		return nil
   540  	}
   541  
   542  	// Enforce max addresses.
   543  	if len(bucket) > newBucketSize {
   544  		a.Logger.Info("new bucket is full, expiring new")
   545  		a.expireNew(bucketIdx)
   546  	}
   547  
   548  	// Add to bucket.
   549  	bucket[addrStr] = ka
   550  	// increment nNew if the peer doesnt already exist in a bucket
   551  	if ka.addBucketRef(bucketIdx) == 1 {
   552  		a.nNew++
   553  	}
   554  
   555  	// Add it to addrLookup
   556  	a.addrLookup[ka.ID()] = ka
   557  	return nil
   558  }
   559  
   560  // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full.
   561  func (a *addrBook) addToOldBucket(ka *knownAddress, bucketIdx int) bool {
   562  	// Sanity check
   563  	if ka.isNew() {
   564  		a.Logger.Error(fmt.Sprintf("Cannot add new address to old bucket: %v", ka))
   565  		return false
   566  	}
   567  	if len(ka.Buckets) != 0 {
   568  		a.Logger.Error(fmt.Sprintf("Cannot add already old address to another old bucket: %v", ka))
   569  		return false
   570  	}
   571  
   572  	addrStr := ka.Addr.String()
   573  	bucket := a.getBucket(bucketTypeOld, bucketIdx)
   574  
   575  	// Already exists?
   576  	if _, ok := bucket[addrStr]; ok {
   577  		return true
   578  	}
   579  
   580  	// Enforce max addresses.
   581  	if len(bucket) > oldBucketSize {
   582  		return false
   583  	}
   584  
   585  	// Add to bucket.
   586  	bucket[addrStr] = ka
   587  	if ka.addBucketRef(bucketIdx) == 1 {
   588  		a.nOld++
   589  	}
   590  
   591  	// Ensure in addrLookup
   592  	a.addrLookup[ka.ID()] = ka
   593  
   594  	return true
   595  }
   596  
   597  func (a *addrBook) removeFromBucket(ka *knownAddress, bucketType byte, bucketIdx int) {
   598  	if ka.BucketType != bucketType {
   599  		a.Logger.Error(fmt.Sprintf("Bucket type mismatch: %v", ka))
   600  		return
   601  	}
   602  	bucket := a.getBucket(bucketType, bucketIdx)
   603  	delete(bucket, ka.Addr.String())
   604  	if ka.removeBucketRef(bucketIdx) == 0 {
   605  		if bucketType == bucketTypeNew {
   606  			a.nNew--
   607  		} else {
   608  			a.nOld--
   609  		}
   610  		delete(a.addrLookup, ka.ID())
   611  	}
   612  }
   613  
   614  func (a *addrBook) removeFromAllBuckets(ka *knownAddress) {
   615  	for _, bucketIdx := range ka.Buckets {
   616  		bucket := a.getBucket(ka.BucketType, bucketIdx)
   617  		delete(bucket, ka.Addr.String())
   618  	}
   619  	ka.Buckets = nil
   620  	if ka.BucketType == bucketTypeNew {
   621  		a.nNew--
   622  	} else {
   623  		a.nOld--
   624  	}
   625  	delete(a.addrLookup, ka.ID())
   626  }
   627  
   628  //----------------------------------------------------------
   629  
   630  func (a *addrBook) pickOldest(bucketType byte, bucketIdx int) *knownAddress {
   631  	bucket := a.getBucket(bucketType, bucketIdx)
   632  	var oldest *knownAddress
   633  	for _, ka := range bucket {
   634  		if oldest == nil || ka.LastAttempt.Before(oldest.LastAttempt) {
   635  			oldest = ka
   636  		}
   637  	}
   638  	return oldest
   639  }
   640  
   641  // adds the address to a "new" bucket. if its already in one,
   642  // it only adds it probabilistically
   643  func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
   644  	if addr == nil || src == nil {
   645  		return ErrAddrBookNilAddr{addr, src}
   646  	}
   647  
   648  	if err := addr.Valid(); err != nil {
   649  		return ErrAddrBookInvalidAddr{Addr: addr, AddrErr: err}
   650  	}
   651  
   652  	if _, ok := a.badPeers[addr.ID]; ok {
   653  		return ErrAddressBanned{addr}
   654  	}
   655  
   656  	if _, ok := a.privateIDs[addr.ID]; ok {
   657  		return ErrAddrBookPrivate{addr}
   658  	}
   659  
   660  	if _, ok := a.privateIDs[src.ID]; ok {
   661  		return ErrAddrBookPrivateSrc{src}
   662  	}
   663  
   664  	// TODO: we should track ourAddrs by ID and by IP:PORT and refuse both.
   665  	if _, ok := a.ourAddrs[addr.String()]; ok {
   666  		return ErrAddrBookSelf{addr}
   667  	}
   668  
   669  	if a.routabilityStrict && !addr.Routable() {
   670  		return ErrAddrBookNonRoutable{addr}
   671  	}
   672  
   673  	ka := a.addrLookup[addr.ID]
   674  	if ka != nil {
   675  		// If its already old and the address ID's are the same, ignore it.
   676  		// Thereby avoiding issues with a node on the network attempting to change
   677  		// the IP of a known node ID. (Which could yield an eclipse attack on the node)
   678  		if ka.isOld() && ka.Addr.ID == addr.ID {
   679  			return nil
   680  		}
   681  		// Already in max new buckets.
   682  		if len(ka.Buckets) == maxNewBucketsPerAddress {
   683  			return nil
   684  		}
   685  		// The more entries we have, the less likely we are to add more.
   686  		factor := int32(2 * len(ka.Buckets))
   687  		// nolint:gosec // G404: Use of weak random number generator
   688  		if mrand.Int31n(factor) != 0 {
   689  			return nil
   690  		}
   691  	} else {
   692  		ka = newKnownAddress(addr, src)
   693  	}
   694  
   695  	bucket, err := a.calcNewBucket(addr, src)
   696  	if err != nil {
   697  		return err
   698  	}
   699  	return a.addToNewBucket(ka, bucket)
   700  }
   701  
   702  func (a *addrBook) randomPickAddresses(bucketType byte, num int) []*p2p.NetAddress {
   703  	var buckets []map[string]*knownAddress
   704  	switch bucketType {
   705  	case bucketTypeNew:
   706  		buckets = a.bucketsNew
   707  	case bucketTypeOld:
   708  		buckets = a.bucketsOld
   709  	default:
   710  		panic("unexpected bucketType")
   711  	}
   712  	total := 0
   713  	for _, bucket := range buckets {
   714  		total += len(bucket)
   715  	}
   716  	addresses := make([]*knownAddress, 0, total)
   717  	for _, bucket := range buckets {
   718  		for _, ka := range bucket {
   719  			addresses = append(addresses, ka)
   720  		}
   721  	}
   722  	selection := make([]*p2p.NetAddress, 0, num)
   723  	chosenSet := make(map[string]bool, num)
   724  	rand := tmrand.NewRand()
   725  	rand.Shuffle(total, func(i, j int) {
   726  		addresses[i], addresses[j] = addresses[j], addresses[i]
   727  	})
   728  	for _, addr := range addresses {
   729  		if chosenSet[addr.Addr.String()] {
   730  			continue
   731  		}
   732  		chosenSet[addr.Addr.String()] = true
   733  		selection = append(selection, addr.Addr)
   734  		if len(selection) >= num {
   735  			return selection
   736  		}
   737  	}
   738  	return selection
   739  }
   740  
   741  // Make space in the new buckets by expiring the really bad entries.
   742  // If no bad entries are available we remove the oldest.
   743  func (a *addrBook) expireNew(bucketIdx int) {
   744  	for addrStr, ka := range a.bucketsNew[bucketIdx] {
   745  		// If an entry is bad, throw it away
   746  		if ka.isBad() {
   747  			a.Logger.Info(fmt.Sprintf("expiring bad address %v", addrStr))
   748  			a.removeFromBucket(ka, bucketTypeNew, bucketIdx)
   749  			return
   750  		}
   751  	}
   752  
   753  	// If we haven't thrown out a bad entry, throw out the oldest entry
   754  	oldest := a.pickOldest(bucketTypeNew, bucketIdx)
   755  	a.removeFromBucket(oldest, bucketTypeNew, bucketIdx)
   756  }
   757  
   758  // Promotes an address from new to old. If the destination bucket is full,
   759  // demote the oldest one to a "new" bucket.
   760  // TODO: Demote more probabilistically?
   761  func (a *addrBook) moveToOld(ka *knownAddress) error {
   762  	// Sanity check
   763  	if ka.isOld() {
   764  		a.Logger.Error(fmt.Sprintf("Cannot promote address that is already old %v", ka))
   765  		return nil
   766  	}
   767  	if len(ka.Buckets) == 0 {
   768  		a.Logger.Error(fmt.Sprintf("Cannot promote address that isn't in any new buckets %v", ka))
   769  		return nil
   770  	}
   771  
   772  	// Remove from all (new) buckets.
   773  	a.removeFromAllBuckets(ka)
   774  	// It's officially old now.
   775  	ka.BucketType = bucketTypeOld
   776  
   777  	// Try to add it to its oldBucket destination.
   778  	oldBucketIdx, err := a.calcOldBucket(ka.Addr)
   779  	if err != nil {
   780  		return err
   781  	}
   782  	added := a.addToOldBucket(ka, oldBucketIdx)
   783  	if !added {
   784  		// No room; move the oldest to a new bucket
   785  		oldest := a.pickOldest(bucketTypeOld, oldBucketIdx)
   786  		a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx)
   787  		newBucketIdx, err := a.calcNewBucket(oldest.Addr, oldest.Src)
   788  		if err != nil {
   789  			return err
   790  		}
   791  		if err := a.addToNewBucket(oldest, newBucketIdx); err != nil {
   792  			a.Logger.Error("Error adding peer to old bucket", "err", err)
   793  		}
   794  
   795  		// Finally, add our ka to old bucket again.
   796  		added = a.addToOldBucket(ka, oldBucketIdx)
   797  		if !added {
   798  			a.Logger.Error(fmt.Sprintf("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx))
   799  		}
   800  	}
   801  	return nil
   802  }
   803  
   804  func (a *addrBook) removeAddress(addr *p2p.NetAddress) {
   805  	ka := a.addrLookup[addr.ID]
   806  	if ka == nil {
   807  		return
   808  	}
   809  	a.Logger.Info("Remove address from book", "addr", addr)
   810  	a.removeFromAllBuckets(ka)
   811  }
   812  
   813  func (a *addrBook) addBadPeer(addr *p2p.NetAddress, banTime time.Duration) bool {
   814  	// check it exists in addrbook
   815  	ka := a.addrLookup[addr.ID]
   816  	// check address is not already there
   817  	if ka == nil {
   818  		return false
   819  	}
   820  
   821  	if _, alreadyBadPeer := a.badPeers[addr.ID]; !alreadyBadPeer {
   822  		// add to bad peer list
   823  		ka.ban(banTime)
   824  		a.badPeers[addr.ID] = ka
   825  		a.Logger.Info("Add address to blacklist", "addr", addr)
   826  	}
   827  	return true
   828  }
   829  
   830  //---------------------------------------------------------------------
   831  // calculate bucket placements
   832  
   833  // hash(key + sourcegroup + int64(hash(key + group + sourcegroup)) % bucket_per_group) % num_new_buckets
   834  func (a *addrBook) calcNewBucket(addr, src *p2p.NetAddress) (int, error) {
   835  	data1 := []byte{}
   836  	data1 = append(data1, []byte(a.key)...)
   837  	data1 = append(data1, []byte(a.groupKey(addr))...)
   838  	data1 = append(data1, []byte(a.groupKey(src))...)
   839  	hash1, err := a.hash(data1)
   840  	if err != nil {
   841  		return 0, err
   842  	}
   843  	hash64 := binary.BigEndian.Uint64(hash1)
   844  	hash64 %= newBucketsPerGroup
   845  	var hashbuf [8]byte
   846  	binary.BigEndian.PutUint64(hashbuf[:], hash64)
   847  	data2 := []byte{}
   848  	data2 = append(data2, []byte(a.key)...)
   849  	data2 = append(data2, a.groupKey(src)...)
   850  	data2 = append(data2, hashbuf[:]...)
   851  
   852  	hash2, err := a.hash(data2)
   853  	if err != nil {
   854  		return 0, err
   855  	}
   856  	result := int(binary.BigEndian.Uint64(hash2) % newBucketCount)
   857  	return result, nil
   858  }
   859  
   860  // hash(key + group + int64(hash(key + addr)) % buckets_per_group) % num_old_buckets
   861  func (a *addrBook) calcOldBucket(addr *p2p.NetAddress) (int, error) {
   862  	data1 := []byte{}
   863  	data1 = append(data1, []byte(a.key)...)
   864  	data1 = append(data1, []byte(addr.String())...)
   865  	hash1, err := a.hash(data1)
   866  	if err != nil {
   867  		return 0, err
   868  	}
   869  	hash64 := binary.BigEndian.Uint64(hash1)
   870  	hash64 %= oldBucketsPerGroup
   871  	var hashbuf [8]byte
   872  	binary.BigEndian.PutUint64(hashbuf[:], hash64)
   873  	data2 := []byte{}
   874  	data2 = append(data2, []byte(a.key)...)
   875  	data2 = append(data2, a.groupKey(addr)...)
   876  	data2 = append(data2, hashbuf[:]...)
   877  
   878  	hash2, err := a.hash(data2)
   879  	if err != nil {
   880  		return 0, err
   881  	}
   882  	result := int(binary.BigEndian.Uint64(hash2) % oldBucketCount)
   883  	return result, nil
   884  }
   885  
   886  // Return a string representing the network group of this address.
   887  // This is the /16 for IPv4 (e.g. 1.2.0.0), the /32 (/36 for he.net) for IPv6, the string
   888  // "local" for a local address and the string "unroutable" for an unroutable
   889  // address.
   890  func (a *addrBook) groupKey(na *p2p.NetAddress) string {
   891  	return groupKeyFor(na, a.routabilityStrict)
   892  }
   893  
   894  func groupKeyFor(na *p2p.NetAddress, routabilityStrict bool) string {
   895  	if routabilityStrict && na.Local() {
   896  		return "local"
   897  	}
   898  	if routabilityStrict && !na.Routable() {
   899  		return "unroutable"
   900  	}
   901  
   902  	if ipv4 := na.IP.To4(); ipv4 != nil {
   903  		return na.IP.Mask(net.CIDRMask(16, 32)).String()
   904  	}
   905  
   906  	if na.RFC6145() || na.RFC6052() {
   907  		// last four bytes are the ip address
   908  		ip := na.IP[12:16]
   909  		return ip.Mask(net.CIDRMask(16, 32)).String()
   910  	}
   911  
   912  	if na.RFC3964() {
   913  		ip := na.IP[2:6]
   914  		return ip.Mask(net.CIDRMask(16, 32)).String()
   915  	}
   916  
   917  	if na.RFC4380() {
   918  		// teredo tunnels have the last 4 bytes as the v4 address XOR
   919  		// 0xff.
   920  		ip := net.IP(make([]byte, 4))
   921  		for i, byte := range na.IP[12:16] {
   922  			ip[i] = byte ^ 0xff
   923  		}
   924  		return ip.Mask(net.CIDRMask(16, 32)).String()
   925  	}
   926  
   927  	if na.OnionCatTor() {
   928  		// group is keyed off the first 4 bits of the actual onion key.
   929  		return fmt.Sprintf("tor:%d", na.IP[6]&((1<<4)-1))
   930  	}
   931  
   932  	// OK, so now we know ourselves to be a IPv6 address.
   933  	// bitcoind uses /32 for everything, except for Hurricane Electric's
   934  	// (he.net) IP range, which it uses /36 for.
   935  	bits := 32
   936  	heNet := &net.IPNet{IP: net.ParseIP("2001:470::"), Mask: net.CIDRMask(32, 128)}
   937  	if heNet.Contains(na.IP) {
   938  		bits = 36
   939  	}
   940  	ipv6Mask := net.CIDRMask(bits, 128)
   941  	return na.IP.Mask(ipv6Mask).String()
   942  }
   943  
   944  func (a *addrBook) hash(b []byte) ([]byte, error) {
   945  	a.hasher.Reset()
   946  	a.hasher.Write(b)
   947  	return a.hasher.Sum(nil), nil
   948  }