github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/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 ) 109 inst := time.Now() 110 num := 314 111 112 db, _ := OpenDB("") 113 defer db.Close() 114 115 // Check fetch/store operations on a node ping object 116 if stored := db.LastPingReceived(node.ID()); stored.Unix() != 0 { 117 t.Errorf("ping: non-existing object: %v", stored) 118 } 119 if err := db.UpdateLastPingReceived(node.ID(), inst); err != nil { 120 t.Errorf("ping: failed to update: %v", err) 121 } 122 if stored := db.LastPingReceived(node.ID()); stored.Unix() != inst.Unix() { 123 t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) 124 } 125 // Check fetch/store operations on a node pong object 126 if stored := db.LastPongReceived(node.ID()); stored.Unix() != 0 { 127 t.Errorf("pong: non-existing object: %v", stored) 128 } 129 if err := db.UpdateLastPongReceived(node.ID(), inst); err != nil { 130 t.Errorf("pong: failed to update: %v", err) 131 } 132 if stored := db.LastPongReceived(node.ID()); stored.Unix() != inst.Unix() { 133 t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) 134 } 135 // Check fetch/store operations on a node findnode-failure object 136 if stored := db.FindFails(node.ID()); stored != 0 { 137 t.Errorf("find-node fails: non-existing object: %v", stored) 138 } 139 if err := db.UpdateFindFails(node.ID(), num); err != nil { 140 t.Errorf("find-node fails: failed to update: %v", err) 141 } 142 if stored := db.FindFails(node.ID()); stored != num { 143 t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) 144 } 145 // Check fetch/store operations on an actual node object 146 if stored := db.Node(node.ID()); stored != nil { 147 t.Errorf("node: non-existing object: %v", stored) 148 } 149 if err := db.UpdateNode(node); err != nil { 150 t.Errorf("node: failed to update: %v", err) 151 } 152 if stored := db.Node(node.ID()); stored == nil { 153 t.Errorf("node: not found") 154 } else if !reflect.DeepEqual(stored, node) { 155 t.Errorf("node: data mismatch: have %v, want %v", stored, node) 156 } 157 } 158 159 var nodeDBSeedQueryNodes = []struct { 160 node *Node 161 pong time.Time 162 }{ 163 // This one should not be in the result set because its last 164 // pong time is too far in the past. 165 { 166 node: NewV4( 167 hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 168 net.IP{127, 0, 0, 3}, 169 30303, 170 30303, 171 ), 172 pong: time.Now().Add(-3 * time.Hour), 173 }, 174 // This one shouldn't be in the result set because its 175 // nodeID is the local node's ID. 176 { 177 node: NewV4( 178 hexPubkey("ff93ff820abacd4351b0f14e47b324bc82ff014c226f3f66a53535734a3c150e7e38ca03ef0964ba55acddc768f5e99cd59dea95ddd4defbab1339c92fa319b2"), 179 net.IP{127, 0, 0, 3}, 180 30303, 181 30303, 182 ), 183 pong: time.Now().Add(-4 * time.Second), 184 }, 185 186 // These should be in the result set. 187 { 188 node: NewV4( 189 hexPubkey("c2b5eb3f5dde05f815b63777809ee3e7e0cbb20035a6b00ce327191e6eaa8f26a8d461c9112b7ab94698e7361fa19fd647e603e73239002946d76085b6f928d6"), 190 net.IP{127, 0, 0, 1}, 191 30303, 192 30303, 193 ), 194 pong: time.Now().Add(-2 * time.Second), 195 }, 196 { 197 node: NewV4( 198 hexPubkey("6ca1d400c8ddf8acc94bcb0dd254911ad71a57bed5e0ae5aa205beed59b28c2339908e97990c493499613cff8ecf6c3dc7112a8ead220cdcd00d8847ca3db755"), 199 net.IP{127, 0, 0, 2}, 200 30303, 201 30303, 202 ), 203 pong: time.Now().Add(-3 * time.Second), 204 }, 205 { 206 node: NewV4( 207 hexPubkey("234dc63fe4d131212b38236c4c3411288d7bec61cbf7b120ff12c43dc60c96182882f4291d209db66f8a38e986c9c010ff59231a67f9515c7d1668b86b221a47"), 208 net.IP{127, 0, 0, 3}, 209 30303, 210 30303, 211 ), 212 pong: time.Now().Add(-1 * time.Second), 213 }, 214 { 215 node: NewV4( 216 hexPubkey("c013a50b4d1ebce5c377d8af8cb7114fd933ffc9627f96ad56d90fef5b7253ec736fd07ef9a81dc2955a997e54b7bf50afd0aa9f110595e2bec5bb7ce1657004"), 217 net.IP{127, 0, 0, 3}, 218 30303, 219 30303, 220 ), 221 pong: time.Now().Add(-2 * time.Second), 222 }, 223 { 224 node: NewV4( 225 hexPubkey("f141087e3e08af1aeec261ff75f48b5b1637f594ea9ad670e50051646b0416daa3b134c28788cbe98af26992a47652889cd8577ccc108ac02c6a664db2dc1283"), 226 net.IP{127, 0, 0, 3}, 227 30303, 228 30303, 229 ), 230 pong: time.Now().Add(-2 * time.Second), 231 }, 232 } 233 234 func TestDBSeedQuery(t *testing.T) { 235 // Querying seeds uses seeks an might not find all nodes 236 // every time when the database is small. Run the test multiple 237 // times to avoid flakes. 238 const attempts = 15 239 var err error 240 for i := 0; i < attempts; i++ { 241 if err = testSeedQuery(); err == nil { 242 return 243 } 244 } 245 if err != nil { 246 t.Errorf("no successful run in %d attempts: %v", attempts, err) 247 } 248 } 249 250 func testSeedQuery() error { 251 db, _ := OpenDB("") 252 defer db.Close() 253 254 // Insert a batch of nodes for querying 255 for i, seed := range nodeDBSeedQueryNodes { 256 if err := db.UpdateNode(seed.node); err != nil { 257 return fmt.Errorf("node %d: failed to insert: %v", i, err) 258 } 259 if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { 260 return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) 261 } 262 } 263 264 // Retrieve the entire batch and check for duplicates 265 seeds := db.QuerySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) 266 have := make(map[ID]struct{}) 267 for _, seed := range seeds { 268 have[seed.ID()] = struct{}{} 269 } 270 want := make(map[ID]struct{}) 271 for _, seed := range nodeDBSeedQueryNodes[1:] { 272 want[seed.node.ID()] = struct{}{} 273 } 274 if len(seeds) != len(want) { 275 return fmt.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) 276 } 277 for id := range have { 278 if _, ok := want[id]; !ok { 279 return fmt.Errorf("extra seed: %v", id) 280 } 281 } 282 for id := range want { 283 if _, ok := have[id]; !ok { 284 return fmt.Errorf("missing seed: %v", id) 285 } 286 } 287 return nil 288 } 289 290 func TestDBPersistency(t *testing.T) { 291 root, err := ioutil.TempDir("", "nodedb-") 292 if err != nil { 293 t.Fatalf("failed to create temporary data folder: %v", err) 294 } 295 defer os.RemoveAll(root) 296 297 var ( 298 testKey = []byte("somekey") 299 testInt = int64(314) 300 ) 301 302 // Create a persistent database and store some values 303 db, err := OpenDB(filepath.Join(root, "database")) 304 if err != nil { 305 t.Fatalf("failed to create persistent database: %v", err) 306 } 307 if err := db.storeInt64(testKey, testInt); err != nil { 308 t.Fatalf("failed to store value: %v.", err) 309 } 310 db.Close() 311 312 // Reopen the database and check the value 313 db, err = OpenDB(filepath.Join(root, "database")) 314 if err != nil { 315 t.Fatalf("failed to open persistent database: %v", err) 316 } 317 if val := db.fetchInt64(testKey); val != testInt { 318 t.Fatalf("value mismatch: have %v, want %v", val, testInt) 319 } 320 db.Close() 321 } 322 323 var nodeDBExpirationNodes = []struct { 324 node *Node 325 pong time.Time 326 exp bool 327 }{ 328 { 329 node: NewV4( 330 hexPubkey("8d110e2ed4b446d9b5fb50f117e5f37fb7597af455e1dab0e6f045a6eeaa786a6781141659020d38bdc5e698ed3d4d2bafa8b5061810dfa63e8ac038db2e9b67"), 331 net.IP{127, 0, 0, 1}, 332 30303, 333 30303, 334 ), 335 pong: time.Now().Add(-dbNodeExpiration + time.Minute), 336 exp: false, 337 }, { 338 node: NewV4( 339 hexPubkey("913a205579c32425b220dfba999d215066e5bdbf900226b11da1907eae5e93eb40616d47412cf819664e9eacbdfcca6b0c6e07e09847a38472d4be46ab0c3672"), 340 net.IP{127, 0, 0, 2}, 341 30303, 342 30303, 343 ), 344 pong: time.Now().Add(-dbNodeExpiration - time.Minute), 345 exp: true, 346 }, 347 } 348 349 func TestDBExpiration(t *testing.T) { 350 db, _ := OpenDB("") 351 defer db.Close() 352 353 // Add all the test nodes and set their last pong time 354 for i, seed := range nodeDBExpirationNodes { 355 if err := db.UpdateNode(seed.node); err != nil { 356 t.Fatalf("node %d: failed to insert: %v", i, err) 357 } 358 if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { 359 t.Fatalf("node %d: failed to update bondTime: %v", i, err) 360 } 361 } 362 // Expire some of them, and check the rest 363 if err := db.expireNodes(); err != nil { 364 t.Fatalf("failed to expire nodes: %v", err) 365 } 366 for i, seed := range nodeDBExpirationNodes { 367 node := db.Node(seed.node.ID()) 368 if (node == nil && !seed.exp) || (node != nil && seed.exp) { 369 t.Errorf("node %d: expiration mismatch: have %v, want %v", i, node, seed.exp) 370 } 371 } 372 }