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 }