github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/p2p/dial_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 p2p 18 19 import ( 20 "encoding/binary" 21 "net" 22 "reflect" 23 "testing" 24 "time" 25 26 "github.com/davecgh/go-spew/spew" 27 "github.com/ethereum/go-ethereum/p2p/discover" 28 "github.com/ethereum/go-ethereum/p2p/netutil" 29 ) 30 31 func init() { 32 spew.Config.Indent = "\t" 33 } 34 35 type dialtest struct { 36 init *dialstate // state before and after the test. 37 rounds []round 38 } 39 40 type round struct { 41 peers []*Peer // current peer set 42 done []task // tasks that got done this round 43 new []task // the result must match this one 44 } 45 46 func runDialTest(t *testing.T, test dialtest) { 47 var ( 48 vtime time.Time 49 running int 50 ) 51 pm := func(ps []*Peer) map[discover.NodeID]*Peer { 52 m := make(map[discover.NodeID]*Peer) 53 for _, p := range ps { 54 m[p.rw.id] = p 55 } 56 return m 57 } 58 for i, round := range test.rounds { 59 for _, task := range round.done { 60 running-- 61 if running < 0 { 62 panic("running task counter underflow") 63 } 64 test.init.taskDone(task, vtime) 65 } 66 67 new := test.init.newTasks(running, pm(round.peers), vtime) 68 if !sametasks(new, round.new) { 69 t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n", 70 i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running)) 71 } 72 73 // Time advances by 16 seconds on every round. 74 vtime = vtime.Add(16 * time.Second) 75 running += len(new) 76 } 77 } 78 79 type fakeTable []*discover.Node 80 81 func (t fakeTable) Self() *discover.Node { return new(discover.Node) } 82 func (t fakeTable) Close() {} 83 func (t fakeTable) Lookup(discover.NodeID) []*discover.Node { return nil } 84 func (t fakeTable) Resolve(discover.NodeID) *discover.Node { return nil } 85 func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) } 86 87 // This test checks that dynamic dials are launched from discovery results. 88 func TestDialStateDynDial(t *testing.T) { 89 runDialTest(t, dialtest{ 90 init: newDialState(nil, fakeTable{}, 5, nil), 91 rounds: []round{ 92 // A discovery query is launched. 93 { 94 peers: []*Peer{ 95 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 96 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 97 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 98 }, 99 new: []task{&discoverTask{}}, 100 }, 101 // Dynamic dials are launched when it completes. 102 { 103 peers: []*Peer{ 104 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 105 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 106 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 107 }, 108 done: []task{ 109 &discoverTask{results: []*discover.Node{ 110 {ID: uintID(2)}, // this one is already connected and not dialed. 111 {ID: uintID(3)}, 112 {ID: uintID(4)}, 113 {ID: uintID(5)}, 114 {ID: uintID(6)}, // these are not tried because max dyn dials is 5 115 {ID: uintID(7)}, // ... 116 }}, 117 }, 118 new: []task{ 119 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 120 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 121 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 122 }, 123 }, 124 // Some of the dials complete but no new ones are launched yet because 125 // the sum of active dial count and dynamic peer count is == maxDynDials. 126 { 127 peers: []*Peer{ 128 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 129 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 130 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 131 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 132 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 133 }, 134 done: []task{ 135 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 136 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 137 }, 138 }, 139 // No new dial tasks are launched in the this round because 140 // maxDynDials has been reached. 141 { 142 peers: []*Peer{ 143 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 144 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 145 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 146 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 147 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 148 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 149 }, 150 done: []task{ 151 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 152 }, 153 new: []task{ 154 &waitExpireTask{Duration: 14 * time.Second}, 155 }, 156 }, 157 // In this round, the peer with id 2 drops off. The query 158 // results from last discovery lookup are reused. 159 { 160 peers: []*Peer{ 161 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 162 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 163 {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, 164 {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, 165 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 166 }, 167 new: []task{ 168 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, 169 }, 170 }, 171 // More peers (3,4) drop off and dial for ID 6 completes. 172 // The last query result from the discovery lookup is reused 173 // and a new one is spawned because more candidates are needed. 174 { 175 peers: []*Peer{ 176 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 177 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 178 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 179 }, 180 done: []task{ 181 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, 182 }, 183 new: []task{ 184 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, 185 &discoverTask{}, 186 }, 187 }, 188 // Peer 7 is connected, but there still aren't enough dynamic peers 189 // (4 out of 5). However, a discovery is already running, so ensure 190 // no new is started. 191 { 192 peers: []*Peer{ 193 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 194 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 195 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 196 {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, 197 }, 198 done: []task{ 199 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, 200 }, 201 }, 202 // Finish the running node discovery with an empty set. A new lookup 203 // should be immediately requested. 204 { 205 peers: []*Peer{ 206 {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, 207 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 208 {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, 209 {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, 210 }, 211 done: []task{ 212 &discoverTask{}, 213 }, 214 new: []task{ 215 &discoverTask{}, 216 }, 217 }, 218 }, 219 }) 220 } 221 222 func TestDialStateDynDialFromTable(t *testing.T) { 223 // This table always returns the same random nodes 224 // in the order given below. 225 table := fakeTable{ 226 {ID: uintID(1)}, 227 {ID: uintID(2)}, 228 {ID: uintID(3)}, 229 {ID: uintID(4)}, 230 {ID: uintID(5)}, 231 {ID: uintID(6)}, 232 {ID: uintID(7)}, 233 {ID: uintID(8)}, 234 } 235 236 runDialTest(t, dialtest{ 237 init: newDialState(nil, table, 10, nil), 238 rounds: []round{ 239 // 5 out of 8 of the nodes returned by ReadRandomNodes are dialed. 240 { 241 new: []task{ 242 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 243 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 244 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 245 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 246 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 247 &discoverTask{}, 248 }, 249 }, 250 // Dialing nodes 1,2 succeeds. Dials from the lookup are launched. 251 { 252 peers: []*Peer{ 253 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 254 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 255 }, 256 done: []task{ 257 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, 258 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, 259 &discoverTask{results: []*discover.Node{ 260 {ID: uintID(10)}, 261 {ID: uintID(11)}, 262 {ID: uintID(12)}, 263 }}, 264 }, 265 new: []task{ 266 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, 267 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, 268 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, 269 &discoverTask{}, 270 }, 271 }, 272 // Dialing nodes 3,4,5 fails. The dials from the lookup succeed. 273 { 274 peers: []*Peer{ 275 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 276 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 277 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 278 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 279 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 280 }, 281 done: []task{ 282 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, 283 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, 284 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, 285 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, 286 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, 287 &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, 288 }, 289 }, 290 // Waiting for expiry. No waitExpireTask is launched because the 291 // discovery query is still running. 292 { 293 peers: []*Peer{ 294 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 295 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 296 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 297 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 298 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 299 }, 300 }, 301 // Nodes 3,4 are not tried again because only the first two 302 // returned random nodes (nodes 1,2) are tried and they're 303 // already connected. 304 { 305 peers: []*Peer{ 306 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 307 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 308 {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, 309 {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, 310 {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, 311 }, 312 }, 313 }, 314 }) 315 } 316 317 // This test checks that candidates that do not match the netrestrict list are not dialed. 318 func TestDialStateNetRestrict(t *testing.T) { 319 // This table always returns the same random nodes 320 // in the order given below. 321 table := fakeTable{ 322 {ID: uintID(1), IP: net.ParseIP("127.0.0.1")}, 323 {ID: uintID(2), IP: net.ParseIP("127.0.0.2")}, 324 {ID: uintID(3), IP: net.ParseIP("127.0.0.3")}, 325 {ID: uintID(4), IP: net.ParseIP("127.0.0.4")}, 326 {ID: uintID(5), IP: net.ParseIP("127.0.2.5")}, 327 {ID: uintID(6), IP: net.ParseIP("127.0.2.6")}, 328 {ID: uintID(7), IP: net.ParseIP("127.0.2.7")}, 329 {ID: uintID(8), IP: net.ParseIP("127.0.2.8")}, 330 } 331 restrict := new(netutil.Netlist) 332 restrict.Add("127.0.2.0/24") 333 334 runDialTest(t, dialtest{ 335 init: newDialState(nil, table, 10, restrict), 336 rounds: []round{ 337 { 338 new: []task{ 339 &dialTask{flags: dynDialedConn, dest: table[4]}, 340 &discoverTask{}, 341 }, 342 }, 343 }, 344 }) 345 } 346 347 // This test checks that static dials are launched. 348 func TestDialStateStaticDial(t *testing.T) { 349 wantStatic := []*discover.Node{ 350 {ID: uintID(1)}, 351 {ID: uintID(2)}, 352 {ID: uintID(3)}, 353 {ID: uintID(4)}, 354 {ID: uintID(5)}, 355 } 356 357 runDialTest(t, dialtest{ 358 init: newDialState(wantStatic, fakeTable{}, 0, nil), 359 rounds: []round{ 360 // Static dials are launched for the nodes that 361 // aren't yet connected. 362 { 363 peers: []*Peer{ 364 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 365 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 366 }, 367 new: []task{ 368 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 369 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 370 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, 371 }, 372 }, 373 // No new tasks are launched in this round because all static 374 // nodes are either connected or still being dialed. 375 { 376 peers: []*Peer{ 377 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 378 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 379 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 380 }, 381 done: []task{ 382 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 383 }, 384 }, 385 // No new dial tasks are launched because all static 386 // nodes are now connected. 387 { 388 peers: []*Peer{ 389 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 390 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 391 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 392 {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, 393 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 394 }, 395 done: []task{ 396 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 397 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, 398 }, 399 new: []task{ 400 &waitExpireTask{Duration: 14 * time.Second}, 401 }, 402 }, 403 // Wait a round for dial history to expire, no new tasks should spawn. 404 { 405 peers: []*Peer{ 406 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 407 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 408 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 409 {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, 410 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 411 }, 412 }, 413 // If a static node is dropped, it should be immediately redialed, 414 // irrespective whether it was originally static or dynamic. 415 { 416 peers: []*Peer{ 417 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 418 {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, 419 {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, 420 }, 421 new: []task{ 422 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 423 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, 424 }, 425 }, 426 }, 427 }) 428 } 429 430 // This test checks that past dials are not retried for some time. 431 func TestDialStateCache(t *testing.T) { 432 wantStatic := []*discover.Node{ 433 {ID: uintID(1)}, 434 {ID: uintID(2)}, 435 {ID: uintID(3)}, 436 } 437 438 runDialTest(t, dialtest{ 439 init: newDialState(wantStatic, fakeTable{}, 0, nil), 440 rounds: []round{ 441 // Static dials are launched for the nodes that 442 // aren't yet connected. 443 { 444 peers: nil, 445 new: []task{ 446 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 447 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 448 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 449 }, 450 }, 451 // No new tasks are launched in this round because all static 452 // nodes are either connected or still being dialed. 453 { 454 peers: []*Peer{ 455 {rw: &conn{flags: staticDialedConn, id: uintID(1)}}, 456 {rw: &conn{flags: staticDialedConn, id: uintID(2)}}, 457 }, 458 done: []task{ 459 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, 460 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, 461 }, 462 }, 463 // A salvage task is launched to wait for node 3's history 464 // entry to expire. 465 { 466 peers: []*Peer{ 467 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 468 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 469 }, 470 done: []task{ 471 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 472 }, 473 new: []task{ 474 &waitExpireTask{Duration: 14 * time.Second}, 475 }, 476 }, 477 // Still waiting for node 3's entry to expire in the cache. 478 { 479 peers: []*Peer{ 480 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 481 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 482 }, 483 }, 484 // The cache entry for node 3 has expired and is retried. 485 { 486 peers: []*Peer{ 487 {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, 488 {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, 489 }, 490 new: []task{ 491 &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, 492 }, 493 }, 494 }, 495 }) 496 } 497 498 func TestDialResolve(t *testing.T) { 499 resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444) 500 table := &resolveMock{answer: resolved} 501 state := newDialState(nil, table, 0, nil) 502 503 // Check that the task is generated with an incomplete ID. 504 dest := discover.NewNode(uintID(1), nil, 0, 0) 505 state.addStatic(dest) 506 tasks := state.newTasks(0, nil, time.Time{}) 507 if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) { 508 t.Fatalf("expected dial task, got %#v", tasks) 509 } 510 511 // Now run the task, it should resolve the ID once. 512 config := Config{Dialer: &net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}} 513 srv := &Server{ntab: table, Config: config} 514 tasks[0].Do(srv) 515 if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) { 516 t.Fatalf("wrong resolve calls, got %v", table.resolveCalls) 517 } 518 519 // Report it as done to the dialer, which should update the static node record. 520 state.taskDone(tasks[0], time.Now()) 521 if state.static[uintID(1)].dest != resolved { 522 t.Fatalf("state.dest not updated") 523 } 524 } 525 526 // compares task lists but doesn't care about the order. 527 func sametasks(a, b []task) bool { 528 if len(a) != len(b) { 529 return false 530 } 531 next: 532 for _, ta := range a { 533 for _, tb := range b { 534 if reflect.DeepEqual(ta, tb) { 535 continue next 536 } 537 } 538 return false 539 } 540 return true 541 } 542 543 func uintID(i uint32) discover.NodeID { 544 var id discover.NodeID 545 binary.BigEndian.PutUint32(id[:], i) 546 return id 547 } 548 549 // implements discoverTable for TestDialResolve 550 type resolveMock struct { 551 resolveCalls []discover.NodeID 552 answer *discover.Node 553 } 554 555 func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node { 556 t.resolveCalls = append(t.resolveCalls, id) 557 return t.answer 558 } 559 560 func (t *resolveMock) Self() *discover.Node { return new(discover.Node) } 561 func (t *resolveMock) Close() {} 562 func (t *resolveMock) Bootstrap([]*discover.Node) {} 563 func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node { return nil } 564 func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }