kademlia_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 kademlia
  17. import (
  18. "fmt"
  19. "math"
  20. "math/rand"
  21. "os"
  22. "path/filepath"
  23. "reflect"
  24. "testing"
  25. "testing/quick"
  26. "time"
  27. )
  28. var (
  29. quickrand = rand.New(rand.NewSource(time.Now().Unix()))
  30. quickcfgFindClosest = &quick.Config{MaxCount: 50, Rand: quickrand}
  31. quickcfgBootStrap = &quick.Config{MaxCount: 100, Rand: quickrand}
  32. )
  33. type testNode struct {
  34. addr Address
  35. }
  36. func (n *testNode) String() string {
  37. return fmt.Sprintf("%x", n.addr[:])
  38. }
  39. func (n *testNode) Addr() Address {
  40. return n.addr
  41. }
  42. func (n *testNode) Drop() {
  43. }
  44. func (n *testNode) Url() string {
  45. return ""
  46. }
  47. func (n *testNode) LastActive() time.Time {
  48. return time.Now()
  49. }
  50. func TestOn(t *testing.T) {
  51. addr, ok1 := gen(Address{}, quickrand).(Address)
  52. other, ok2 := gen(Address{}, quickrand).(Address)
  53. if !ok1 || !ok2 {
  54. t.Errorf("oops")
  55. }
  56. kad := New(addr, NewKadParams())
  57. err := kad.On(&testNode{addr: other}, nil)
  58. _ = err
  59. }
  60. func TestBootstrap(t *testing.T) {
  61. test := func(test *bootstrapTest) bool {
  62. // for any node kad.le, Target and N
  63. params := NewKadParams()
  64. params.MaxProx = test.MaxProx
  65. params.BucketSize = test.BucketSize
  66. params.ProxBinSize = test.BucketSize
  67. kad := New(test.Self, params)
  68. var err error
  69. for p := 0; p < 9; p++ {
  70. var nrs []*NodeRecord
  71. n := math.Pow(float64(2), float64(7-p))
  72. for i := 0; i < int(n); i++ {
  73. addr := RandomAddressAt(test.Self, p)
  74. nrs = append(nrs, &NodeRecord{
  75. Addr: addr,
  76. })
  77. }
  78. kad.Add(nrs)
  79. }
  80. node := &testNode{test.Self}
  81. n := 0
  82. for n < 100 {
  83. err = kad.On(node, nil)
  84. if err != nil {
  85. t.Fatalf("backend not accepting node: %v", err)
  86. }
  87. record, need, _ := kad.Suggest()
  88. if !need {
  89. break
  90. }
  91. n++
  92. if record == nil {
  93. continue
  94. }
  95. node = &testNode{record.Addr}
  96. }
  97. exp := test.BucketSize * (test.MaxProx + 1)
  98. if kad.Count() != exp {
  99. t.Errorf("incorrect number of peers, expected %d, got %d\n%v", exp, kad.Count(), kad)
  100. return false
  101. }
  102. return true
  103. }
  104. if err := quick.Check(test, quickcfgBootStrap); err != nil {
  105. t.Error(err)
  106. }
  107. }
  108. func TestFindClosest(t *testing.T) {
  109. test := func(test *FindClosestTest) bool {
  110. // for any node kad.le, Target and N
  111. params := NewKadParams()
  112. params.MaxProx = 7
  113. kad := New(test.Self, params)
  114. var err error
  115. for _, node := range test.All {
  116. err = kad.On(node, nil)
  117. if err != nil && err.Error() != "bucket full" {
  118. t.Fatalf("backend not accepting node: %v", err)
  119. }
  120. }
  121. if len(test.All) == 0 || test.N == 0 {
  122. return true
  123. }
  124. nodes := kad.FindClosest(test.Target, test.N)
  125. // check that the number of results is min(N, kad.len)
  126. wantN := test.N
  127. if tlen := kad.Count(); tlen < test.N {
  128. wantN = tlen
  129. }
  130. if len(nodes) != wantN {
  131. t.Errorf("wrong number of nodes: got %d, want %d", len(nodes), wantN)
  132. return false
  133. }
  134. if hasDuplicates(nodes) {
  135. t.Errorf("result contains duplicates")
  136. return false
  137. }
  138. if !sortedByDistanceTo(test.Target, nodes) {
  139. t.Errorf("result is not sorted by distance to target")
  140. return false
  141. }
  142. // check that the result nodes have minimum distance to target.
  143. farthestResult := nodes[len(nodes)-1].Addr()
  144. for i, b := range kad.buckets {
  145. for j, n := range b {
  146. if contains(nodes, n.Addr()) {
  147. continue // don't run the check below for nodes in result
  148. }
  149. if test.Target.ProxCmp(n.Addr(), farthestResult) < 0 {
  150. _ = i * j
  151. t.Errorf("kad.le contains node that is closer to target but it's not in result")
  152. return false
  153. }
  154. }
  155. }
  156. return true
  157. }
  158. if err := quick.Check(test, quickcfgFindClosest); err != nil {
  159. t.Error(err)
  160. }
  161. }
  162. type proxTest struct {
  163. add bool
  164. index int
  165. addr Address
  166. }
  167. var (
  168. addresses []Address
  169. )
  170. func TestProxAdjust(t *testing.T) {
  171. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  172. self := gen(Address{}, r).(Address)
  173. params := NewKadParams()
  174. params.MaxProx = 7
  175. kad := New(self, params)
  176. var err error
  177. for i := 0; i < 100; i++ {
  178. a := gen(Address{}, r).(Address)
  179. addresses = append(addresses, a)
  180. err = kad.On(&testNode{addr: a}, nil)
  181. if err != nil && err.Error() != "bucket full" {
  182. t.Fatalf("backend not accepting node: %v", err)
  183. }
  184. if !kad.proxCheck(t) {
  185. return
  186. }
  187. }
  188. test := func(test *proxTest) bool {
  189. node := &testNode{test.addr}
  190. if test.add {
  191. kad.On(node, nil)
  192. } else {
  193. kad.Off(node, nil)
  194. }
  195. return kad.proxCheck(t)
  196. }
  197. if err := quick.Check(test, quickcfgFindClosest); err != nil {
  198. t.Error(err)
  199. }
  200. }
  201. func TestSaveLoad(t *testing.T) {
  202. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  203. addresses := gen([]Address{}, r).([]Address)
  204. self := RandomAddress()
  205. params := NewKadParams()
  206. params.MaxProx = 7
  207. kad := New(self, params)
  208. var err error
  209. for _, a := range addresses {
  210. err = kad.On(&testNode{addr: a}, nil)
  211. if err != nil && err.Error() != "bucket full" {
  212. t.Fatalf("backend not accepting node: %v", err)
  213. }
  214. }
  215. nodes := kad.FindClosest(self, 100)
  216. path := filepath.Join(os.TempDir(), "bzz-kad-test-save-load.peers")
  217. err = kad.Save(path, nil)
  218. if err != nil && err.Error() != "bucket full" {
  219. t.Fatalf("unepected error saving kaddb: %v", err)
  220. }
  221. kad = New(self, params)
  222. err = kad.Load(path, nil)
  223. if err != nil && err.Error() != "bucket full" {
  224. t.Fatalf("unepected error loading kaddb: %v", err)
  225. }
  226. for _, b := range kad.db.Nodes {
  227. for _, node := range b {
  228. err = kad.On(&testNode{node.Addr}, nil)
  229. if err != nil && err.Error() != "bucket full" {
  230. t.Fatalf("backend not accepting node: %v", err)
  231. }
  232. }
  233. }
  234. loadednodes := kad.FindClosest(self, 100)
  235. for i, node := range loadednodes {
  236. if nodes[i].Addr() != node.Addr() {
  237. t.Errorf("node mismatch at %d/%d: %v != %v", i, len(nodes), nodes[i].Addr(), node.Addr())
  238. }
  239. }
  240. }
  241. func (self *Kademlia) proxCheck(t *testing.T) bool {
  242. var sum int
  243. for i, b := range self.buckets {
  244. l := len(b)
  245. // if we are in the high prox multibucket
  246. if i >= self.proxLimit {
  247. sum += l
  248. } else if l == 0 {
  249. t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), self.proxLimit, self)
  250. return false
  251. }
  252. }
  253. // check if merged high prox bucket does not exceed size
  254. if sum > 0 {
  255. if sum != self.proxSize {
  256. t.Errorf("proxSize incorrect, expected %v, got %v", sum, self.proxSize)
  257. return false
  258. }
  259. last := len(self.buckets[self.proxLimit])
  260. if last > 0 && sum >= self.ProxBinSize+last {
  261. t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", self.proxLimit, last, sum-last, self.ProxBinSize, self)
  262. return false
  263. }
  264. if self.proxLimit > 0 && sum < self.ProxBinSize {
  265. t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", self.proxLimit, sum, self.ProxBinSize)
  266. return false
  267. }
  268. }
  269. return true
  270. }
  271. type bootstrapTest struct {
  272. MaxProx int
  273. BucketSize int
  274. Self Address
  275. }
  276. func (*bootstrapTest) Generate(rand *rand.Rand, size int) reflect.Value {
  277. t := &bootstrapTest{
  278. Self: gen(Address{}, rand).(Address),
  279. MaxProx: 5 + rand.Intn(2),
  280. BucketSize: rand.Intn(3) + 1,
  281. }
  282. return reflect.ValueOf(t)
  283. }
  284. type FindClosestTest struct {
  285. Self Address
  286. Target Address
  287. All []Node
  288. N int
  289. }
  290. func (c FindClosestTest) String() string {
  291. return fmt.Sprintf("A: %064x\nT: %064x\n(%d)\n", c.Self[:], c.Target[:], c.N)
  292. }
  293. func (*FindClosestTest) Generate(rand *rand.Rand, size int) reflect.Value {
  294. t := &FindClosestTest{
  295. Self: gen(Address{}, rand).(Address),
  296. Target: gen(Address{}, rand).(Address),
  297. N: rand.Intn(bucketSize),
  298. }
  299. for _, a := range gen([]Address{}, rand).([]Address) {
  300. t.All = append(t.All, &testNode{addr: a})
  301. }
  302. return reflect.ValueOf(t)
  303. }
  304. func (*proxTest) Generate(rand *rand.Rand, size int) reflect.Value {
  305. var add bool
  306. if rand.Intn(1) == 0 {
  307. add = true
  308. }
  309. var t *proxTest
  310. if add {
  311. t = &proxTest{
  312. addr: gen(Address{}, rand).(Address),
  313. add: add,
  314. }
  315. } else {
  316. t = &proxTest{
  317. index: rand.Intn(len(addresses)),
  318. add: add,
  319. }
  320. }
  321. return reflect.ValueOf(t)
  322. }
  323. func hasDuplicates(slice []Node) bool {
  324. seen := make(map[Address]bool)
  325. for _, node := range slice {
  326. if seen[node.Addr()] {
  327. return true
  328. }
  329. seen[node.Addr()] = true
  330. }
  331. return false
  332. }
  333. func contains(nodes []Node, addr Address) bool {
  334. for _, n := range nodes {
  335. if n.Addr() == addr {
  336. return true
  337. }
  338. }
  339. return false
  340. }
  341. // gen wraps quick.Value so it's easier to use.
  342. // it generates a random value of the given value's type.
  343. func gen(typ interface{}, rand *rand.Rand) interface{} {
  344. v, ok := quick.Value(reflect.TypeOf(typ), rand)
  345. if !ok {
  346. panic(fmt.Sprintf("couldn't generate random value of type %T", typ))
  347. }
  348. return v.Interface()
  349. }