github.com/core-coin/go-core/v2@v2.1.9/p2p/dial_test.go (about) 1 // Copyright 2015 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "math/rand" 24 "net" 25 "reflect" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/core-coin/go-core/v2/common/mclock" 31 "github.com/core-coin/go-core/v2/internal/testlog" 32 "github.com/core-coin/go-core/v2/log" 33 "github.com/core-coin/go-core/v2/p2p/enode" 34 "github.com/core-coin/go-core/v2/p2p/netutil" 35 ) 36 37 // This test checks that dynamic dials are launched from discovery results. 38 func TestDialSchedDynDial(t *testing.T) { 39 t.Parallel() 40 41 config := dialConfig{ 42 maxActiveDials: 5, 43 maxDialPeers: 4, 44 } 45 runDialTest(t, config, []dialTestRound{ 46 // 3 out of 4 peers are connected, leaving 2 dial slots. 47 // 9 nodes are discovered, but only 2 are dialed. 48 { 49 peersAdded: []*conn{ 50 {flags: staticDialedConn, node: newNode(uintID(0x00), "")}, 51 {flags: dynDialedConn, node: newNode(uintID(0x01), "")}, 52 {flags: dynDialedConn, node: newNode(uintID(0x02), "")}, 53 }, 54 discovered: []*enode.Node{ 55 newNode(uintID(0x00), "127.0.0.1:30300"), // not dialed because already connected as static peer 56 newNode(uintID(0x02), "127.0.0.1:30300"), // ... 57 newNode(uintID(0x03), "127.0.0.1:30300"), 58 newNode(uintID(0x04), "127.0.0.1:30300"), 59 newNode(uintID(0x05), "127.0.0.1:30300"), // not dialed because there are only two slots 60 newNode(uintID(0x06), "127.0.0.1:30300"), // ... 61 newNode(uintID(0x07), "127.0.0.1:30300"), // ... 62 newNode(uintID(0x08), "127.0.0.1:30300"), // ... 63 }, 64 wantNewDials: []*enode.Node{ 65 newNode(uintID(0x03), "127.0.0.1:30300"), 66 newNode(uintID(0x04), "127.0.0.1:30300"), 67 }, 68 }, 69 70 // One dial completes, freeing one dial slot. 71 { 72 failed: []enode.ID{ 73 uintID(0x04), 74 }, 75 wantNewDials: []*enode.Node{ 76 newNode(uintID(0x05), "127.0.0.1:30300"), 77 }, 78 }, 79 80 // Dial to 0x03 completes, filling the last remaining peer slot. 81 { 82 succeeded: []enode.ID{ 83 uintID(0x03), 84 }, 85 failed: []enode.ID{ 86 uintID(0x05), 87 }, 88 discovered: []*enode.Node{ 89 newNode(uintID(0x09), "127.0.0.1:30300"), // not dialed because there are no free slots 90 }, 91 }, 92 93 // 3 peers drop off, creating 6 dial slots. Check that 5 of those slots 94 // (i.e. up to maxActiveDialTasks) are used. 95 { 96 peersRemoved: []enode.ID{ 97 uintID(0x00), 98 uintID(0x01), 99 uintID(0x02), 100 }, 101 discovered: []*enode.Node{ 102 newNode(uintID(0x0a), "127.0.0.1:30300"), 103 newNode(uintID(0x0b), "127.0.0.1:30300"), 104 newNode(uintID(0x0c), "127.0.0.1:30300"), 105 newNode(uintID(0x0d), "127.0.0.1:30300"), 106 newNode(uintID(0x0f), "127.0.0.1:30300"), 107 }, 108 wantNewDials: []*enode.Node{ 109 newNode(uintID(0x06), "127.0.0.1:30300"), 110 newNode(uintID(0x07), "127.0.0.1:30300"), 111 newNode(uintID(0x08), "127.0.0.1:30300"), 112 newNode(uintID(0x09), "127.0.0.1:30300"), 113 newNode(uintID(0x0a), "127.0.0.1:30300"), 114 }, 115 }, 116 }) 117 } 118 119 // This test checks that candidates that do not match the netrestrict list are not dialed. 120 func TestDialSchedNetRestrict(t *testing.T) { 121 t.Parallel() 122 123 nodes := []*enode.Node{ 124 newNode(uintID(0x01), "127.0.0.1:30300"), 125 newNode(uintID(0x02), "127.0.0.2:30300"), 126 newNode(uintID(0x03), "127.0.0.3:30300"), 127 newNode(uintID(0x04), "127.0.0.4:30300"), 128 newNode(uintID(0x05), "127.0.2.5:30300"), 129 newNode(uintID(0x06), "127.0.2.6:30300"), 130 newNode(uintID(0x07), "127.0.2.7:30300"), 131 newNode(uintID(0x08), "127.0.2.8:30300"), 132 } 133 config := dialConfig{ 134 netRestrict: new(netutil.Netlist), 135 maxActiveDials: 10, 136 maxDialPeers: 10, 137 } 138 config.netRestrict.Add("127.0.2.0/24") 139 runDialTest(t, config, []dialTestRound{ 140 { 141 discovered: nodes, 142 wantNewDials: nodes[4:8], 143 }, 144 { 145 succeeded: []enode.ID{ 146 nodes[4].ID(), 147 nodes[5].ID(), 148 nodes[6].ID(), 149 nodes[7].ID(), 150 }, 151 }, 152 }) 153 } 154 155 // This test checks that static dials work and obey the limits. 156 func TestDialSchedStaticDial(t *testing.T) { 157 t.Parallel() 158 159 config := dialConfig{ 160 maxActiveDials: 5, 161 maxDialPeers: 4, 162 } 163 runDialTest(t, config, []dialTestRound{ 164 // Static dials are launched for the nodes that 165 // aren't yet connected. 166 { 167 peersAdded: []*conn{ 168 {flags: dynDialedConn, node: newNode(uintID(0x01), "127.0.0.1:30300")}, 169 {flags: dynDialedConn, node: newNode(uintID(0x02), "127.0.0.2:30300")}, 170 }, 171 update: func(d *dialScheduler) { 172 // These two are not dialed because they're already connected 173 // as dynamic peers. 174 d.addStatic(newNode(uintID(0x01), "127.0.0.1:30300")) 175 d.addStatic(newNode(uintID(0x02), "127.0.0.2:30300")) 176 // These nodes will be dialed: 177 d.addStatic(newNode(uintID(0x03), "127.0.0.3:30300")) 178 d.addStatic(newNode(uintID(0x04), "127.0.0.4:30300")) 179 d.addStatic(newNode(uintID(0x05), "127.0.0.5:30300")) 180 d.addStatic(newNode(uintID(0x06), "127.0.0.6:30300")) 181 d.addStatic(newNode(uintID(0x07), "127.0.0.7:30300")) 182 d.addStatic(newNode(uintID(0x08), "127.0.0.8:30300")) 183 d.addStatic(newNode(uintID(0x09), "127.0.0.9:30300")) 184 }, 185 wantNewDials: []*enode.Node{ 186 newNode(uintID(0x03), "127.0.0.3:30300"), 187 newNode(uintID(0x04), "127.0.0.4:30300"), 188 newNode(uintID(0x05), "127.0.0.5:30300"), 189 newNode(uintID(0x06), "127.0.0.6:30300"), 190 }, 191 }, 192 // Dial to 0x03 completes, filling a peer slot. One slot remains, 193 // two dials are launched to attempt to fill it. 194 { 195 succeeded: []enode.ID{ 196 uintID(0x03), 197 }, 198 failed: []enode.ID{ 199 uintID(0x04), 200 uintID(0x05), 201 uintID(0x06), 202 }, 203 wantResolves: map[enode.ID]*enode.Node{ 204 uintID(0x04): nil, 205 uintID(0x05): nil, 206 uintID(0x06): nil, 207 }, 208 wantNewDials: []*enode.Node{ 209 newNode(uintID(0x08), "127.0.0.8:30300"), 210 newNode(uintID(0x09), "127.0.0.9:30300"), 211 }, 212 }, 213 // Peer 0x01 drops and 0x07 connects as inbound peer. 214 // Only 0x01 is dialed. 215 { 216 peersAdded: []*conn{ 217 {flags: inboundConn, node: newNode(uintID(0x07), "127.0.0.7:30300")}, 218 }, 219 peersRemoved: []enode.ID{ 220 uintID(0x01), 221 }, 222 wantNewDials: []*enode.Node{ 223 newNode(uintID(0x01), "127.0.0.1:30300"), 224 }, 225 }, 226 }) 227 } 228 229 // This test checks that removing static nodes stops connecting to them. 230 func TestDialSchedRemoveStatic(t *testing.T) { 231 t.Parallel() 232 233 config := dialConfig{ 234 maxActiveDials: 1, 235 maxDialPeers: 1, 236 } 237 runDialTest(t, config, []dialTestRound{ 238 // Add static nodes. 239 { 240 update: func(d *dialScheduler) { 241 d.addStatic(newNode(uintID(0x01), "127.0.0.1:30300")) 242 d.addStatic(newNode(uintID(0x02), "127.0.0.2:30300")) 243 d.addStatic(newNode(uintID(0x03), "127.0.0.3:30300")) 244 }, 245 wantNewDials: []*enode.Node{ 246 newNode(uintID(0x01), "127.0.0.1:30300"), 247 }, 248 }, 249 // Dial to 0x01 fails. 250 { 251 failed: []enode.ID{ 252 uintID(0x01), 253 }, 254 wantResolves: map[enode.ID]*enode.Node{ 255 uintID(0x01): nil, 256 }, 257 wantNewDials: []*enode.Node{ 258 newNode(uintID(0x02), "127.0.0.2:30300"), 259 }, 260 }, 261 // All static nodes are removed. 0x01 is in history, 0x02 is being 262 // dialed, 0x03 is in staticPool. 263 { 264 update: func(d *dialScheduler) { 265 d.removeStatic(newNode(uintID(0x01), "127.0.0.1:30300")) 266 d.removeStatic(newNode(uintID(0x02), "127.0.0.2:30300")) 267 d.removeStatic(newNode(uintID(0x03), "127.0.0.3:30300")) 268 }, 269 failed: []enode.ID{ 270 uintID(0x02), 271 }, 272 wantResolves: map[enode.ID]*enode.Node{ 273 uintID(0x02): nil, 274 }, 275 }, 276 // Since all static nodes are removed, they should not be dialed again. 277 {}, {}, {}, 278 }) 279 } 280 281 // This test checks that static dials are selected at random. 282 func TestDialSchedManyStaticNodes(t *testing.T) { 283 t.Parallel() 284 285 config := dialConfig{maxDialPeers: 2} 286 runDialTest(t, config, []dialTestRound{ 287 { 288 peersAdded: []*conn{ 289 {flags: dynDialedConn, node: newNode(uintID(0xFFFE), "")}, 290 {flags: dynDialedConn, node: newNode(uintID(0xFFFF), "")}, 291 }, 292 update: func(d *dialScheduler) { 293 for id := uint16(0); id < 2000; id++ { 294 n := newNode(uintID(id), "127.0.0.1:30300") 295 d.addStatic(n) 296 } 297 }, 298 }, 299 { 300 peersRemoved: []enode.ID{ 301 uintID(0xFFFE), 302 uintID(0xFFFF), 303 }, 304 wantNewDials: []*enode.Node{ 305 newNode(uintID(0x0085), "127.0.0.1:30300"), 306 newNode(uintID(0x02dc), "127.0.0.1:30300"), 307 newNode(uintID(0x0285), "127.0.0.1:30300"), 308 newNode(uintID(0x00cb), "127.0.0.1:30300"), 309 }, 310 }, 311 }) 312 } 313 314 // This test checks that past dials are not retried for some time. 315 func TestDialSchedHistory(t *testing.T) { 316 t.Parallel() 317 318 config := dialConfig{ 319 maxActiveDials: 3, 320 maxDialPeers: 3, 321 } 322 runDialTest(t, config, []dialTestRound{ 323 { 324 update: func(d *dialScheduler) { 325 d.addStatic(newNode(uintID(0x01), "127.0.0.1:30300")) 326 d.addStatic(newNode(uintID(0x02), "127.0.0.2:30300")) 327 d.addStatic(newNode(uintID(0x03), "127.0.0.3:30300")) 328 }, 329 wantNewDials: []*enode.Node{ 330 newNode(uintID(0x01), "127.0.0.1:30300"), 331 newNode(uintID(0x02), "127.0.0.2:30300"), 332 newNode(uintID(0x03), "127.0.0.3:30300"), 333 }, 334 }, 335 // No new tasks are launched in this round because all static 336 // nodes are either connected or still being dialed. 337 { 338 succeeded: []enode.ID{ 339 uintID(0x01), 340 uintID(0x02), 341 }, 342 failed: []enode.ID{ 343 uintID(0x03), 344 }, 345 wantResolves: map[enode.ID]*enode.Node{ 346 uintID(0x03): nil, 347 }, 348 }, 349 // Nothing happens in this round because we're waiting for 350 // node 0x3's history entry to expire. 351 {}, 352 // The cache entry for node 0x03 has expired and is retried. 353 { 354 wantNewDials: []*enode.Node{ 355 newNode(uintID(0x03), "127.0.0.3:30300"), 356 }, 357 }, 358 }) 359 } 360 361 func TestDialSchedResolve(t *testing.T) { 362 t.Parallel() 363 364 config := dialConfig{ 365 maxActiveDials: 1, 366 maxDialPeers: 1, 367 } 368 node := newNode(uintID(0x01), "") 369 resolved := newNode(uintID(0x01), "127.0.0.1:30300") 370 resolved2 := newNode(uintID(0x01), "127.0.0.55:30300") 371 runDialTest(t, config, []dialTestRound{ 372 { 373 update: func(d *dialScheduler) { 374 d.addStatic(node) 375 }, 376 wantResolves: map[enode.ID]*enode.Node{ 377 uintID(0x01): resolved, 378 }, 379 wantNewDials: []*enode.Node{ 380 resolved, 381 }, 382 }, 383 { 384 failed: []enode.ID{ 385 uintID(0x01), 386 }, 387 wantResolves: map[enode.ID]*enode.Node{ 388 uintID(0x01): resolved2, 389 }, 390 wantNewDials: []*enode.Node{ 391 resolved2, 392 }, 393 }, 394 }) 395 } 396 397 // ------- 398 // Code below here is the framework for the tests above. 399 400 type dialTestRound struct { 401 peersAdded []*conn 402 peersRemoved []enode.ID 403 update func(*dialScheduler) // called at beginning of round 404 discovered []*enode.Node // newly discovered nodes 405 succeeded []enode.ID // dials which succeed this round 406 failed []enode.ID // dials which fail this round 407 wantResolves map[enode.ID]*enode.Node 408 wantNewDials []*enode.Node // dials that should be launched in this round 409 } 410 411 func runDialTest(t *testing.T, config dialConfig, rounds []dialTestRound) { 412 var ( 413 clock = new(mclock.Simulated) 414 iterator = newDialTestIterator() 415 dialer = newDialTestDialer() 416 resolver = new(dialTestResolver) 417 peers = make(map[enode.ID]*conn) 418 setupCh = make(chan *conn) 419 ) 420 421 // Override config. 422 config.clock = clock 423 config.dialer = dialer 424 config.resolver = resolver 425 config.log = testlog.Logger(t, log.LvlTrace) 426 config.rand = rand.New(rand.NewSource(0x1111)) 427 428 // Set up the dialer. The setup function below runs on the dialTask 429 // goroutine and adds the peer. 430 var dialsched *dialScheduler 431 setup := func(fd net.Conn, f connFlag, node *enode.Node) error { 432 conn := &conn{flags: f, node: node} 433 dialsched.peerAdded(conn) 434 setupCh <- conn 435 return nil 436 } 437 dialsched = newDialScheduler(config, iterator, setup) 438 defer dialsched.stop() 439 440 for i, round := range rounds { 441 // Apply peer set updates. 442 for _, c := range round.peersAdded { 443 if peers[c.node.ID()] != nil { 444 t.Fatalf("round %d: peer %v already connected", i, c.node.ID()) 445 } 446 dialsched.peerAdded(c) 447 peers[c.node.ID()] = c 448 } 449 for _, id := range round.peersRemoved { 450 c := peers[id] 451 if c == nil { 452 t.Fatalf("round %d: can't remove non-existent peer %v", i, id) 453 } 454 dialsched.peerRemoved(c) 455 } 456 457 // Init round. 458 t.Logf("round %d (%d peers)", i, len(peers)) 459 resolver.setAnswers(round.wantResolves) 460 if round.update != nil { 461 round.update(dialsched) 462 } 463 iterator.addNodes(round.discovered) 464 465 // Unblock dialTask goroutines. 466 if err := dialer.completeDials(round.succeeded, nil); err != nil { 467 t.Fatalf("round %d: %v", i, err) 468 } 469 for range round.succeeded { 470 conn := <-setupCh 471 peers[conn.node.ID()] = conn 472 } 473 if err := dialer.completeDials(round.failed, errors.New("oops")); err != nil { 474 t.Fatalf("round %d: %v", i, err) 475 } 476 477 // Wait for new tasks. 478 if err := dialer.waitForDials(round.wantNewDials); err != nil { 479 t.Fatalf("round %d: %v", i, err) 480 } 481 if !resolver.checkCalls() { 482 t.Fatalf("unexpected calls to Resolve: %v", resolver.calls) 483 } 484 485 clock.Run(16 * time.Second) 486 } 487 } 488 489 // dialTestIterator is the input iterator for dialer tests. This works a bit like a channel 490 // with infinite buffer: nodes are added to the buffer with addNodes, which unblocks Next 491 // and returns them from the iterator. 492 type dialTestIterator struct { 493 cur *enode.Node 494 495 mu sync.Mutex 496 buf []*enode.Node 497 cond *sync.Cond 498 closed bool 499 } 500 501 func newDialTestIterator() *dialTestIterator { 502 it := &dialTestIterator{} 503 it.cond = sync.NewCond(&it.mu) 504 return it 505 } 506 507 // addNodes adds nodes to the iterator buffer and unblocks Next. 508 func (it *dialTestIterator) addNodes(nodes []*enode.Node) { 509 it.mu.Lock() 510 defer it.mu.Unlock() 511 512 it.buf = append(it.buf, nodes...) 513 it.cond.Signal() 514 } 515 516 // Node returns the current node. 517 func (it *dialTestIterator) Node() *enode.Node { 518 return it.cur 519 } 520 521 // Next moves to the next node. 522 func (it *dialTestIterator) Next() bool { 523 it.mu.Lock() 524 defer it.mu.Unlock() 525 526 it.cur = nil 527 for len(it.buf) == 0 && !it.closed { 528 it.cond.Wait() 529 } 530 if it.closed { 531 return false 532 } 533 it.cur = it.buf[0] 534 copy(it.buf[:], it.buf[1:]) 535 it.buf = it.buf[:len(it.buf)-1] 536 return true 537 } 538 539 // Close ends the iterator, unblocking Next. 540 func (it *dialTestIterator) Close() { 541 it.mu.Lock() 542 defer it.mu.Unlock() 543 544 it.closed = true 545 it.buf = nil 546 it.cond.Signal() 547 } 548 549 // dialTestDialer is the NodeDialer used by runDialTest. 550 type dialTestDialer struct { 551 init chan *dialTestReq 552 blocked map[enode.ID]*dialTestReq 553 } 554 555 type dialTestReq struct { 556 n *enode.Node 557 unblock chan error 558 } 559 560 func newDialTestDialer() *dialTestDialer { 561 return &dialTestDialer{ 562 init: make(chan *dialTestReq), 563 blocked: make(map[enode.ID]*dialTestReq), 564 } 565 } 566 567 // Dial implements NodeDialer. 568 func (d *dialTestDialer) Dial(ctx context.Context, n *enode.Node) (net.Conn, error) { 569 req := &dialTestReq{n: n, unblock: make(chan error, 1)} 570 select { 571 case d.init <- req: 572 select { 573 case err := <-req.unblock: 574 pipe, _ := net.Pipe() 575 return pipe, err 576 case <-ctx.Done(): 577 return nil, ctx.Err() 578 } 579 case <-ctx.Done(): 580 return nil, ctx.Err() 581 } 582 } 583 584 // waitForDials waits for calls to Dial with the given nodes as argument. 585 // Those calls will be held blocking until completeDials is called with the same nodes. 586 func (d *dialTestDialer) waitForDials(nodes []*enode.Node) error { 587 waitset := make(map[enode.ID]*enode.Node) 588 for _, n := range nodes { 589 waitset[n.ID()] = n 590 } 591 timeout := time.NewTimer(1 * time.Second) 592 defer timeout.Stop() 593 594 for len(waitset) > 0 { 595 select { 596 case req := <-d.init: 597 want, ok := waitset[req.n.ID()] 598 if !ok { 599 return fmt.Errorf("attempt to dial unexpected node %v", req.n.ID()) 600 } 601 if !reflect.DeepEqual(req.n, want) { 602 return fmt.Errorf("ENR of dialed node %v does not match test", req.n.ID()) 603 } 604 delete(waitset, req.n.ID()) 605 d.blocked[req.n.ID()] = req 606 case <-timeout.C: 607 var waitlist []enode.ID 608 for id := range waitset { 609 waitlist = append(waitlist, id) 610 } 611 return fmt.Errorf("timed out waiting for dials to %v", waitlist) 612 } 613 } 614 615 return d.checkUnexpectedDial() 616 } 617 618 func (d *dialTestDialer) checkUnexpectedDial() error { 619 select { 620 case req := <-d.init: 621 return fmt.Errorf("attempt to dial unexpected node %v", req.n.ID()) 622 case <-time.After(150 * time.Millisecond): 623 return nil 624 } 625 } 626 627 // completeDials unblocks calls to Dial for the given nodes. 628 func (d *dialTestDialer) completeDials(ids []enode.ID, err error) error { 629 for _, id := range ids { 630 req := d.blocked[id] 631 if req == nil { 632 return fmt.Errorf("can't complete dial to %v", id) 633 } 634 req.unblock <- err 635 } 636 return nil 637 } 638 639 // dialTestResolver tracks calls to resolve. 640 type dialTestResolver struct { 641 mu sync.Mutex 642 calls []enode.ID 643 answers map[enode.ID]*enode.Node 644 } 645 646 func (t *dialTestResolver) setAnswers(m map[enode.ID]*enode.Node) { 647 t.mu.Lock() 648 defer t.mu.Unlock() 649 650 t.answers = m 651 t.calls = nil 652 } 653 654 func (t *dialTestResolver) checkCalls() bool { 655 t.mu.Lock() 656 defer t.mu.Unlock() 657 658 for _, id := range t.calls { 659 if _, ok := t.answers[id]; !ok { 660 return false 661 } 662 } 663 return true 664 } 665 666 func (t *dialTestResolver) Resolve(n *enode.Node) *enode.Node { 667 t.mu.Lock() 668 defer t.mu.Unlock() 669 670 t.calls = append(t.calls, n.ID()) 671 return t.answers[n.ID()] 672 }