table.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package discv5 is a prototype implementation of Discvery v5.
  17. // Deprecated: do not use this package.
  18. package discv5
  19. import (
  20. "crypto/rand"
  21. "encoding/binary"
  22. "fmt"
  23. "net"
  24. "sort"
  25. "github.com/ethereum/go-ethereum/common"
  26. )
  27. const (
  28. alpha = 3 // Kademlia concurrency factor
  29. bucketSize = 16 // Kademlia bucket size
  30. hashBits = len(common.Hash{}) * 8
  31. nBuckets = hashBits + 1 // Number of buckets
  32. maxFindnodeFailures = 5
  33. )
  34. type Table struct {
  35. count int // number of nodes
  36. buckets [nBuckets]*bucket // index of known nodes by distance
  37. nodeAddedHook func(*Node) // for testing
  38. self *Node // metadata of the local node
  39. }
  40. // bucket contains nodes, ordered by their last activity. the entry
  41. // that was most recently active is the first element in entries.
  42. type bucket struct {
  43. entries []*Node
  44. replacements []*Node
  45. }
  46. func newTable(ourID NodeID, ourAddr *net.UDPAddr) *Table {
  47. self := NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port))
  48. tab := &Table{self: self}
  49. for i := range tab.buckets {
  50. tab.buckets[i] = new(bucket)
  51. }
  52. return tab
  53. }
  54. const printTable = false
  55. // chooseBucketRefreshTarget selects random refresh targets to keep all Kademlia
  56. // buckets filled with live connections and keep the network topology healthy.
  57. // This requires selecting addresses closer to our own with a higher probability
  58. // in order to refresh closer buckets too.
  59. //
  60. // This algorithm approximates the distance distribution of existing nodes in the
  61. // table by selecting a random node from the table and selecting a target address
  62. // with a distance less than twice of that of the selected node.
  63. // This algorithm will be improved later to specifically target the least recently
  64. // used buckets.
  65. func (tab *Table) chooseBucketRefreshTarget() common.Hash {
  66. entries := 0
  67. if printTable {
  68. fmt.Println()
  69. }
  70. for i, b := range &tab.buckets {
  71. entries += len(b.entries)
  72. if printTable {
  73. for _, e := range b.entries {
  74. fmt.Println(i, e.state, e.addr().String(), e.ID.String(), e.sha.Hex())
  75. }
  76. }
  77. }
  78. prefix := binary.BigEndian.Uint64(tab.self.sha[0:8])
  79. dist := ^uint64(0)
  80. entry := int(randUint(uint32(entries + 1)))
  81. for _, b := range &tab.buckets {
  82. if entry < len(b.entries) {
  83. n := b.entries[entry]
  84. dist = binary.BigEndian.Uint64(n.sha[0:8]) ^ prefix
  85. break
  86. }
  87. entry -= len(b.entries)
  88. }
  89. ddist := ^uint64(0)
  90. if dist+dist > dist {
  91. ddist = dist
  92. }
  93. targetPrefix := prefix ^ randUint64n(ddist)
  94. var target common.Hash
  95. binary.BigEndian.PutUint64(target[0:8], targetPrefix)
  96. rand.Read(target[8:])
  97. return target
  98. }
  99. // readRandomNodes fills the given slice with random nodes from the
  100. // table. It will not write the same node more than once. The nodes in
  101. // the slice are copies and can be modified by the caller.
  102. func (tab *Table) readRandomNodes(buf []*Node) (n int) {
  103. // TODO: tree-based buckets would help here
  104. // Find all non-empty buckets and get a fresh slice of their entries.
  105. var buckets [][]*Node
  106. for _, b := range &tab.buckets {
  107. if len(b.entries) > 0 {
  108. buckets = append(buckets, b.entries)
  109. }
  110. }
  111. if len(buckets) == 0 {
  112. return 0
  113. }
  114. // Shuffle the buckets.
  115. for i := uint32(len(buckets)) - 1; i > 0; i-- {
  116. j := randUint(i)
  117. buckets[i], buckets[j] = buckets[j], buckets[i]
  118. }
  119. // Move head of each bucket into buf, removing buckets that become empty.
  120. var i, j int
  121. for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) {
  122. b := buckets[j]
  123. buf[i] = &(*b[0])
  124. buckets[j] = b[1:]
  125. if len(b) == 1 {
  126. buckets = append(buckets[:j], buckets[j+1:]...)
  127. }
  128. if len(buckets) == 0 {
  129. break
  130. }
  131. }
  132. return i + 1
  133. }
  134. func randUint(max uint32) uint32 {
  135. if max < 2 {
  136. return 0
  137. }
  138. var b [4]byte
  139. rand.Read(b[:])
  140. return binary.BigEndian.Uint32(b[:]) % max
  141. }
  142. func randUint64n(max uint64) uint64 {
  143. if max < 2 {
  144. return 0
  145. }
  146. var b [8]byte
  147. rand.Read(b[:])
  148. return binary.BigEndian.Uint64(b[:]) % max
  149. }
  150. // closest returns the n nodes in the table that are closest to the
  151. // given id. The caller must hold tab.mutex.
  152. func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance {
  153. // This is a very wasteful way to find the closest nodes but
  154. // obviously correct. I believe that tree-based buckets would make
  155. // this easier to implement efficiently.
  156. close := &nodesByDistance{target: target}
  157. for _, b := range &tab.buckets {
  158. for _, n := range b.entries {
  159. close.push(n, nresults)
  160. }
  161. }
  162. return close
  163. }
  164. // add attempts to add the given node its corresponding bucket. If the
  165. // bucket has space available, adding the node succeeds immediately.
  166. // Otherwise, the node is added to the replacement cache for the bucket.
  167. func (tab *Table) add(n *Node) (contested *Node) {
  168. //fmt.Println("add", n.addr().String(), n.ID.String(), n.sha.Hex())
  169. if n.ID == tab.self.ID {
  170. return
  171. }
  172. b := tab.buckets[logdist(tab.self.sha, n.sha)]
  173. switch {
  174. case b.bump(n):
  175. // n exists in b.
  176. return nil
  177. case len(b.entries) < bucketSize:
  178. // b has space available.
  179. b.addFront(n)
  180. tab.count++
  181. if tab.nodeAddedHook != nil {
  182. tab.nodeAddedHook(n)
  183. }
  184. return nil
  185. default:
  186. // b has no space left, add to replacement cache
  187. // and revalidate the last entry.
  188. // TODO: drop previous node
  189. b.replacements = append(b.replacements, n)
  190. if len(b.replacements) > bucketSize {
  191. copy(b.replacements, b.replacements[1:])
  192. b.replacements = b.replacements[:len(b.replacements)-1]
  193. }
  194. return b.entries[len(b.entries)-1]
  195. }
  196. }
  197. // stuff adds nodes the table to the end of their corresponding bucket
  198. // if the bucket is not full.
  199. func (tab *Table) stuff(nodes []*Node) {
  200. outer:
  201. for _, n := range nodes {
  202. if n.ID == tab.self.ID {
  203. continue // don't add self
  204. }
  205. bucket := tab.buckets[logdist(tab.self.sha, n.sha)]
  206. for i := range bucket.entries {
  207. if bucket.entries[i].ID == n.ID {
  208. continue outer // already in bucket
  209. }
  210. }
  211. if len(bucket.entries) < bucketSize {
  212. bucket.entries = append(bucket.entries, n)
  213. tab.count++
  214. if tab.nodeAddedHook != nil {
  215. tab.nodeAddedHook(n)
  216. }
  217. }
  218. }
  219. }
  220. // delete removes an entry from the node table (used to evacuate
  221. // failed/non-bonded discovery peers).
  222. func (tab *Table) delete(node *Node) {
  223. //fmt.Println("delete", node.addr().String(), node.ID.String(), node.sha.Hex())
  224. bucket := tab.buckets[logdist(tab.self.sha, node.sha)]
  225. for i := range bucket.entries {
  226. if bucket.entries[i].ID == node.ID {
  227. bucket.entries = append(bucket.entries[:i], bucket.entries[i+1:]...)
  228. tab.count--
  229. return
  230. }
  231. }
  232. }
  233. func (tab *Table) deleteReplace(node *Node) {
  234. b := tab.buckets[logdist(tab.self.sha, node.sha)]
  235. i := 0
  236. for i < len(b.entries) {
  237. if b.entries[i].ID == node.ID {
  238. b.entries = append(b.entries[:i], b.entries[i+1:]...)
  239. tab.count--
  240. } else {
  241. i++
  242. }
  243. }
  244. // refill from replacement cache
  245. // TODO: maybe use random index
  246. if len(b.entries) < bucketSize && len(b.replacements) > 0 {
  247. ri := len(b.replacements) - 1
  248. b.addFront(b.replacements[ri])
  249. tab.count++
  250. b.replacements[ri] = nil
  251. b.replacements = b.replacements[:ri]
  252. }
  253. }
  254. func (b *bucket) addFront(n *Node) {
  255. b.entries = append(b.entries, nil)
  256. copy(b.entries[1:], b.entries)
  257. b.entries[0] = n
  258. }
  259. func (b *bucket) bump(n *Node) bool {
  260. for i := range b.entries {
  261. if b.entries[i].ID == n.ID {
  262. // move it to the front
  263. copy(b.entries[1:], b.entries[:i])
  264. b.entries[0] = n
  265. return true
  266. }
  267. }
  268. return false
  269. }
  270. // nodesByDistance is a list of nodes, ordered by
  271. // distance to target.
  272. type nodesByDistance struct {
  273. entries []*Node
  274. target common.Hash
  275. }
  276. // push adds the given node to the list, keeping the total size below maxElems.
  277. func (h *nodesByDistance) push(n *Node, maxElems int) {
  278. ix := sort.Search(len(h.entries), func(i int) bool {
  279. return distcmp(h.target, h.entries[i].sha, n.sha) > 0
  280. })
  281. if len(h.entries) < maxElems {
  282. h.entries = append(h.entries, n)
  283. }
  284. if ix == len(h.entries) {
  285. // farther away than all nodes we already have.
  286. // if there was room for it, the node is now the last element.
  287. } else {
  288. // slide existing entries down to make room
  289. // this will overwrite the entry we just appended.
  290. copy(h.entries[ix+1:], h.entries[ix:])
  291. h.entries[ix] = n
  292. }
  293. }