nodedb_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2015 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 enode
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io/ioutil"
  21. "net"
  22. "os"
  23. "path/filepath"
  24. "reflect"
  25. "testing"
  26. "time"
  27. )
  28. var nodeDBKeyTests = []struct {
  29. id ID
  30. field string
  31. key []byte
  32. }{
  33. {
  34. id: ID{},
  35. field: "version",
  36. key: []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e}, // field
  37. },
  38. {
  39. id: HexID("51232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  40. field: ":discover",
  41. key: []byte{
  42. 0x6e, 0x3a, // prefix
  43. 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // node id
  44. 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, //
  45. 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, //
  46. 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, //
  47. 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, // field
  48. },
  49. },
  50. }
  51. func TestDBKeys(t *testing.T) {
  52. for i, tt := range nodeDBKeyTests {
  53. if key := makeKey(tt.id, tt.field); !bytes.Equal(key, tt.key) {
  54. t.Errorf("make test %d: key mismatch: have 0x%x, want 0x%x", i, key, tt.key)
  55. }
  56. id, field := splitKey(tt.key)
  57. if !bytes.Equal(id[:], tt.id[:]) {
  58. t.Errorf("split test %d: id mismatch: have 0x%x, want 0x%x", i, id, tt.id)
  59. }
  60. if field != tt.field {
  61. t.Errorf("split test %d: field mismatch: have 0x%x, want 0x%x", i, field, tt.field)
  62. }
  63. }
  64. }
  65. var nodeDBInt64Tests = []struct {
  66. key []byte
  67. value int64
  68. }{
  69. {key: []byte{0x01}, value: 1},
  70. {key: []byte{0x02}, value: 2},
  71. {key: []byte{0x03}, value: 3},
  72. }
  73. func TestDBInt64(t *testing.T) {
  74. db, _ := OpenDB("")
  75. defer db.Close()
  76. tests := nodeDBInt64Tests
  77. for i := 0; i < len(tests); i++ {
  78. // Insert the next value
  79. if err := db.storeInt64(tests[i].key, tests[i].value); err != nil {
  80. t.Errorf("test %d: failed to store value: %v", i, err)
  81. }
  82. // Check all existing and non existing values
  83. for j := 0; j < len(tests); j++ {
  84. num := db.fetchInt64(tests[j].key)
  85. switch {
  86. case j <= i && num != tests[j].value:
  87. t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, tests[j].value)
  88. case j > i && num != 0:
  89. t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, 0)
  90. }
  91. }
  92. }
  93. }
  94. func TestDBFetchStore(t *testing.T) {
  95. node := NewV4(
  96. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  97. net.IP{192, 168, 0, 1},
  98. 30303,
  99. 30303,
  100. )
  101. inst := time.Now()
  102. num := 314
  103. db, _ := OpenDB("")
  104. defer db.Close()
  105. // Check fetch/store operations on a node ping object
  106. if stored := db.LastPingReceived(node.ID()); stored.Unix() != 0 {
  107. t.Errorf("ping: non-existing object: %v", stored)
  108. }
  109. if err := db.UpdateLastPingReceived(node.ID(), inst); err != nil {
  110. t.Errorf("ping: failed to update: %v", err)
  111. }
  112. if stored := db.LastPingReceived(node.ID()); stored.Unix() != inst.Unix() {
  113. t.Errorf("ping: value mismatch: have %v, want %v", stored, inst)
  114. }
  115. // Check fetch/store operations on a node pong object
  116. if stored := db.LastPongReceived(node.ID()); stored.Unix() != 0 {
  117. t.Errorf("pong: non-existing object: %v", stored)
  118. }
  119. if err := db.UpdateLastPongReceived(node.ID(), inst); err != nil {
  120. t.Errorf("pong: failed to update: %v", err)
  121. }
  122. if stored := db.LastPongReceived(node.ID()); stored.Unix() != inst.Unix() {
  123. t.Errorf("pong: value mismatch: have %v, want %v", stored, inst)
  124. }
  125. // Check fetch/store operations on a node findnode-failure object
  126. if stored := db.FindFails(node.ID()); stored != 0 {
  127. t.Errorf("find-node fails: non-existing object: %v", stored)
  128. }
  129. if err := db.UpdateFindFails(node.ID(), num); err != nil {
  130. t.Errorf("find-node fails: failed to update: %v", err)
  131. }
  132. if stored := db.FindFails(node.ID()); stored != num {
  133. t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num)
  134. }
  135. // Check fetch/store operations on an actual node object
  136. if stored := db.Node(node.ID()); stored != nil {
  137. t.Errorf("node: non-existing object: %v", stored)
  138. }
  139. if err := db.UpdateNode(node); err != nil {
  140. t.Errorf("node: failed to update: %v", err)
  141. }
  142. if stored := db.Node(node.ID()); stored == nil {
  143. t.Errorf("node: not found")
  144. } else if !reflect.DeepEqual(stored, node) {
  145. t.Errorf("node: data mismatch: have %v, want %v", stored, node)
  146. }
  147. }
  148. var nodeDBSeedQueryNodes = []struct {
  149. node *Node
  150. pong time.Time
  151. }{
  152. // This one should not be in the result set because its last
  153. // pong time is too far in the past.
  154. {
  155. node: NewV4(
  156. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  157. net.IP{127, 0, 0, 3},
  158. 30303,
  159. 30303,
  160. ),
  161. pong: time.Now().Add(-3 * time.Hour),
  162. },
  163. // This one shouldn't be in the result set because its
  164. // nodeID is the local node's ID.
  165. {
  166. node: NewV4(
  167. hexPubkey("ff93ff820abacd4351b0f14e47b324bc82ff014c226f3f66a53535734a3c150e7e38ca03ef0964ba55acddc768f5e99cd59dea95ddd4defbab1339c92fa319b2"),
  168. net.IP{127, 0, 0, 3},
  169. 30303,
  170. 30303,
  171. ),
  172. pong: time.Now().Add(-4 * time.Second),
  173. },
  174. // These should be in the result set.
  175. {
  176. node: NewV4(
  177. hexPubkey("c2b5eb3f5dde05f815b63777809ee3e7e0cbb20035a6b00ce327191e6eaa8f26a8d461c9112b7ab94698e7361fa19fd647e603e73239002946d76085b6f928d6"),
  178. net.IP{127, 0, 0, 1},
  179. 30303,
  180. 30303,
  181. ),
  182. pong: time.Now().Add(-2 * time.Second),
  183. },
  184. {
  185. node: NewV4(
  186. hexPubkey("6ca1d400c8ddf8acc94bcb0dd254911ad71a57bed5e0ae5aa205beed59b28c2339908e97990c493499613cff8ecf6c3dc7112a8ead220cdcd00d8847ca3db755"),
  187. net.IP{127, 0, 0, 2},
  188. 30303,
  189. 30303,
  190. ),
  191. pong: time.Now().Add(-3 * time.Second),
  192. },
  193. {
  194. node: NewV4(
  195. hexPubkey("234dc63fe4d131212b38236c4c3411288d7bec61cbf7b120ff12c43dc60c96182882f4291d209db66f8a38e986c9c010ff59231a67f9515c7d1668b86b221a47"),
  196. net.IP{127, 0, 0, 3},
  197. 30303,
  198. 30303,
  199. ),
  200. pong: time.Now().Add(-1 * time.Second),
  201. },
  202. {
  203. node: NewV4(
  204. hexPubkey("c013a50b4d1ebce5c377d8af8cb7114fd933ffc9627f96ad56d90fef5b7253ec736fd07ef9a81dc2955a997e54b7bf50afd0aa9f110595e2bec5bb7ce1657004"),
  205. net.IP{127, 0, 0, 3},
  206. 30303,
  207. 30303,
  208. ),
  209. pong: time.Now().Add(-2 * time.Second),
  210. },
  211. {
  212. node: NewV4(
  213. hexPubkey("f141087e3e08af1aeec261ff75f48b5b1637f594ea9ad670e50051646b0416daa3b134c28788cbe98af26992a47652889cd8577ccc108ac02c6a664db2dc1283"),
  214. net.IP{127, 0, 0, 3},
  215. 30303,
  216. 30303,
  217. ),
  218. pong: time.Now().Add(-2 * time.Second),
  219. },
  220. }
  221. func TestDBSeedQuery(t *testing.T) {
  222. // Querying seeds uses seeks an might not find all nodes
  223. // every time when the database is small. Run the test multiple
  224. // times to avoid flakes.
  225. const attempts = 15
  226. var err error
  227. for i := 0; i < attempts; i++ {
  228. if err = testSeedQuery(); err == nil {
  229. return
  230. }
  231. }
  232. if err != nil {
  233. t.Errorf("no successful run in %d attempts: %v", attempts, err)
  234. }
  235. }
  236. func testSeedQuery() error {
  237. db, _ := OpenDB("")
  238. defer db.Close()
  239. // Insert a batch of nodes for querying
  240. for i, seed := range nodeDBSeedQueryNodes {
  241. if err := db.UpdateNode(seed.node); err != nil {
  242. return fmt.Errorf("node %d: failed to insert: %v", i, err)
  243. }
  244. if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil {
  245. return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err)
  246. }
  247. }
  248. // Retrieve the entire batch and check for duplicates
  249. seeds := db.QuerySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour)
  250. have := make(map[ID]struct{})
  251. for _, seed := range seeds {
  252. have[seed.ID()] = struct{}{}
  253. }
  254. want := make(map[ID]struct{})
  255. for _, seed := range nodeDBSeedQueryNodes[1:] {
  256. want[seed.node.ID()] = struct{}{}
  257. }
  258. if len(seeds) != len(want) {
  259. return fmt.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want))
  260. }
  261. for id := range have {
  262. if _, ok := want[id]; !ok {
  263. return fmt.Errorf("extra seed: %v", id)
  264. }
  265. }
  266. for id := range want {
  267. if _, ok := have[id]; !ok {
  268. return fmt.Errorf("missing seed: %v", id)
  269. }
  270. }
  271. return nil
  272. }
  273. func TestDBPersistency(t *testing.T) {
  274. root, err := ioutil.TempDir("", "nodedb-")
  275. if err != nil {
  276. t.Fatalf("failed to create temporary data folder: %v", err)
  277. }
  278. defer os.RemoveAll(root)
  279. var (
  280. testKey = []byte("somekey")
  281. testInt = int64(314)
  282. )
  283. // Create a persistent database and store some values
  284. db, err := OpenDB(filepath.Join(root, "database"))
  285. if err != nil {
  286. t.Fatalf("failed to create persistent database: %v", err)
  287. }
  288. if err := db.storeInt64(testKey, testInt); err != nil {
  289. t.Fatalf("failed to store value: %v.", err)
  290. }
  291. db.Close()
  292. // Reopen the database and check the value
  293. db, err = OpenDB(filepath.Join(root, "database"))
  294. if err != nil {
  295. t.Fatalf("failed to open persistent database: %v", err)
  296. }
  297. if val := db.fetchInt64(testKey); val != testInt {
  298. t.Fatalf("value mismatch: have %v, want %v", val, testInt)
  299. }
  300. db.Close()
  301. }
  302. var nodeDBExpirationNodes = []struct {
  303. node *Node
  304. pong time.Time
  305. exp bool
  306. }{
  307. {
  308. node: NewV4(
  309. hexPubkey("8d110e2ed4b446d9b5fb50f117e5f37fb7597af455e1dab0e6f045a6eeaa786a6781141659020d38bdc5e698ed3d4d2bafa8b5061810dfa63e8ac038db2e9b67"),
  310. net.IP{127, 0, 0, 1},
  311. 30303,
  312. 30303,
  313. ),
  314. pong: time.Now().Add(-nodeDBNodeExpiration + time.Minute),
  315. exp: false,
  316. }, {
  317. node: NewV4(
  318. hexPubkey("913a205579c32425b220dfba999d215066e5bdbf900226b11da1907eae5e93eb40616d47412cf819664e9eacbdfcca6b0c6e07e09847a38472d4be46ab0c3672"),
  319. net.IP{127, 0, 0, 2},
  320. 30303,
  321. 30303,
  322. ),
  323. pong: time.Now().Add(-nodeDBNodeExpiration - time.Minute),
  324. exp: true,
  325. },
  326. }
  327. func TestDBExpiration(t *testing.T) {
  328. db, _ := OpenDB("")
  329. defer db.Close()
  330. // Add all the test nodes and set their last pong time
  331. for i, seed := range nodeDBExpirationNodes {
  332. if err := db.UpdateNode(seed.node); err != nil {
  333. t.Fatalf("node %d: failed to insert: %v", i, err)
  334. }
  335. if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil {
  336. t.Fatalf("node %d: failed to update bondTime: %v", i, err)
  337. }
  338. }
  339. // Expire some of them, and check the rest
  340. if err := db.expireNodes(); err != nil {
  341. t.Fatalf("failed to expire nodes: %v", err)
  342. }
  343. for i, seed := range nodeDBExpirationNodes {
  344. node := db.Node(seed.node.ID())
  345. if (node == nil && !seed.exp) || (node != nil && seed.exp) {
  346. t.Errorf("node %d: expiration mismatch: have %v, want %v", i, node, seed.exp)
  347. }
  348. }
  349. }