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