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