table.go 8.9 KB

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