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.

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