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.

684 lines
18 KiB

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