You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

834 lines
22 KiB

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