github.com/josephingithub/mev-geth@v1.9.6/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 new tasks: %s", i, 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 type fakeTable []*enode.Node 85 86 func (t fakeTable) Self() *enode.Node { return new(enode.Node) } 87 func (t fakeTable) Close() {} 88 func (t fakeTable) LookupRandom() []*enode.Node { return nil } 89 func (t fakeTable) Resolve(*enode.Node) *enode.Node { return nil } 90 func (t fakeTable) ReadRandomNodes(buf []*enode.Node) int { return copy(buf, t) } 91 92 // This test checks that dynamic dials are launched from discovery results. 93 func TestDialStateDynDial(t *testing.T) { 94 config := &Config{Logger: testlog.Logger(t, log.LvlTrace)} 95 runDialTest(t, dialtest{ 96 init: newDialState(enode.ID{}, fakeTable{}, 5, config), 97 rounds: []round{ 98 // A discovery query is launched. 99 { 100 peers: []*Peer{ 101 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 102 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 103 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 104 }, 105 new: []task{&discoverTask{}}, 106 }, 107 // Dynamic dials are launched when it completes. 108 { 109 peers: []*Peer{ 110 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 111 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 112 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 113 }, 114 done: []task{ 115 &discoverTask{results: []*enode.Node{ 116 newNode(uintID(2), nil), // this one is already connected and not dialed. 117 newNode(uintID(3), nil), 118 newNode(uintID(4), nil), 119 newNode(uintID(5), nil), 120 newNode(uintID(6), nil), // these are not tried because max dyn dials is 5 121 newNode(uintID(7), nil), // ... 122 }}, 123 }, 124 new: []task{ 125 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 126 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 127 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 128 }, 129 }, 130 // Some of the dials complete but no new ones are launched yet because 131 // the sum of active dial count and dynamic peer count is == maxDynDials. 132 { 133 peers: []*Peer{ 134 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 135 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 136 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 137 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, 138 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, 139 }, 140 done: []task{ 141 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 142 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 143 }, 144 }, 145 // No new dial tasks are launched in the this round because 146 // maxDynDials has been reached. 147 { 148 peers: []*Peer{ 149 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 150 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 151 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 152 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, 153 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, 154 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, 155 }, 156 done: []task{ 157 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 158 }, 159 new: []task{ 160 &waitExpireTask{Duration: 19 * time.Second}, 161 }, 162 }, 163 // In this round, the peer with id 2 drops off. The query 164 // results from last discovery lookup are reused. 165 { 166 peers: []*Peer{ 167 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 168 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 169 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, 170 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, 171 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, 172 }, 173 new: []task{ 174 &dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)}, 175 }, 176 }, 177 // More peers (3,4) drop off and dial for ID 6 completes. 178 // The last query result from the discovery lookup is reused 179 // and a new one is spawned because more candidates are needed. 180 { 181 peers: []*Peer{ 182 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 183 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 184 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, 185 }, 186 done: []task{ 187 &dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)}, 188 }, 189 new: []task{ 190 &dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)}, 191 &discoverTask{}, 192 }, 193 }, 194 // Peer 7 is connected, but there still aren't enough dynamic peers 195 // (4 out of 5). However, a discovery is already running, so ensure 196 // no new is started. 197 { 198 peers: []*Peer{ 199 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 200 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 201 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, 202 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}}, 203 }, 204 done: []task{ 205 &dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)}, 206 }, 207 }, 208 // Finish the running node discovery with an empty set. A new lookup 209 // should be immediately requested. 210 { 211 peers: []*Peer{ 212 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, 213 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 214 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, 215 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}}, 216 }, 217 done: []task{ 218 &discoverTask{}, 219 }, 220 new: []task{ 221 &discoverTask{}, 222 }, 223 }, 224 }, 225 }) 226 } 227 228 // Tests that bootnodes are dialed if no peers are connectd, but not otherwise. 229 func TestDialStateDynDialBootnode(t *testing.T) { 230 config := &Config{ 231 BootstrapNodes: []*enode.Node{ 232 newNode(uintID(1), nil), 233 newNode(uintID(2), nil), 234 newNode(uintID(3), nil), 235 }, 236 Logger: testlog.Logger(t, log.LvlTrace), 237 } 238 table := fakeTable{ 239 newNode(uintID(4), nil), 240 newNode(uintID(5), nil), 241 newNode(uintID(6), nil), 242 newNode(uintID(7), nil), 243 newNode(uintID(8), nil), 244 } 245 runDialTest(t, dialtest{ 246 init: newDialState(enode.ID{}, table, 5, config), 247 rounds: []round{ 248 // 2 dynamic dials attempted, bootnodes pending fallback interval 249 { 250 new: []task{ 251 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 252 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 253 &discoverTask{}, 254 }, 255 }, 256 // No dials succeed, bootnodes still pending fallback interval 257 { 258 done: []task{ 259 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 260 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 261 }, 262 }, 263 // No dials succeed, bootnodes still pending fallback interval 264 {}, 265 // No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached 266 { 267 new: []task{ 268 &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, 269 }, 270 }, 271 // No dials succeed, 2nd bootnode is attempted 272 { 273 done: []task{ 274 &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, 275 }, 276 new: []task{ 277 &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, 278 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 279 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 280 }, 281 }, 282 // No dials succeed, 3rd bootnode is attempted 283 { 284 done: []task{ 285 &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, 286 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 287 }, 288 new: []task{ 289 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 290 }, 291 }, 292 // No dials succeed, 1st bootnode is attempted again, expired random nodes retried 293 { 294 done: []task{ 295 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 296 }, 297 new: []task{}, 298 }, 299 // Random dial succeeds, no more bootnodes are attempted 300 { 301 new: []task{ 302 &waitExpireTask{3 * time.Second}, 303 }, 304 peers: []*Peer{ 305 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, 306 }, 307 done: []task{ 308 &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, 309 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 310 }, 311 }, 312 }, 313 }) 314 } 315 316 func TestDialStateDynDialFromTable(t *testing.T) { 317 // This table always returns the same random nodes 318 // in the order given below. 319 table := fakeTable{ 320 newNode(uintID(1), nil), 321 newNode(uintID(2), nil), 322 newNode(uintID(3), nil), 323 newNode(uintID(4), nil), 324 newNode(uintID(5), nil), 325 newNode(uintID(6), nil), 326 newNode(uintID(7), nil), 327 newNode(uintID(8), nil), 328 } 329 330 runDialTest(t, dialtest{ 331 init: newDialState(enode.ID{}, table, 10, &Config{Logger: testlog.Logger(t, log.LvlTrace)}), 332 rounds: []round{ 333 // 5 out of 8 of the nodes returned by ReadRandomNodes are dialed. 334 { 335 new: []task{ 336 &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, 337 &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, 338 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 339 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 340 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 341 &discoverTask{}, 342 }, 343 }, 344 // Dialing nodes 1,2 succeeds. Dials from the lookup are launched. 345 { 346 peers: []*Peer{ 347 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 348 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 349 }, 350 done: []task{ 351 &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, 352 &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, 353 &discoverTask{results: []*enode.Node{ 354 newNode(uintID(10), nil), 355 newNode(uintID(11), nil), 356 newNode(uintID(12), nil), 357 }}, 358 }, 359 new: []task{ 360 &dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)}, 361 &dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)}, 362 &dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)}, 363 &discoverTask{}, 364 }, 365 }, 366 // Dialing nodes 3,4,5 fails. The dials from the lookup succeed. 367 { 368 peers: []*Peer{ 369 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 370 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 371 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, 372 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, 373 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, 374 }, 375 done: []task{ 376 &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, 377 &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, 378 &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, 379 &dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)}, 380 &dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)}, 381 &dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)}, 382 }, 383 }, 384 // Waiting for expiry. No waitExpireTask is launched because the 385 // discovery query is still running. 386 { 387 peers: []*Peer{ 388 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 389 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 390 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, 391 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, 392 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, 393 }, 394 }, 395 // Nodes 3,4 are not tried again because only the first two 396 // returned random nodes (nodes 1,2) are tried and they're 397 // already connected. 398 { 399 peers: []*Peer{ 400 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 401 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 402 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, 403 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, 404 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, 405 }, 406 }, 407 }, 408 }) 409 } 410 411 func newNode(id enode.ID, ip net.IP) *enode.Node { 412 var r enr.Record 413 if ip != nil { 414 r.Set(enr.IP(ip)) 415 } 416 return enode.SignNull(&r, id) 417 } 418 419 // This test checks that candidates that do not match the netrestrict list are not dialed. 420 func TestDialStateNetRestrict(t *testing.T) { 421 // This table always returns the same random nodes 422 // in the order given below. 423 table := fakeTable{ 424 newNode(uintID(1), net.ParseIP("127.0.0.1")), 425 newNode(uintID(2), net.ParseIP("127.0.0.2")), 426 newNode(uintID(3), net.ParseIP("127.0.0.3")), 427 newNode(uintID(4), net.ParseIP("127.0.0.4")), 428 newNode(uintID(5), net.ParseIP("127.0.2.5")), 429 newNode(uintID(6), net.ParseIP("127.0.2.6")), 430 newNode(uintID(7), net.ParseIP("127.0.2.7")), 431 newNode(uintID(8), net.ParseIP("127.0.2.8")), 432 } 433 restrict := new(netutil.Netlist) 434 restrict.Add("127.0.2.0/24") 435 436 runDialTest(t, dialtest{ 437 init: newDialState(enode.ID{}, table, 10, &Config{NetRestrict: restrict}), 438 rounds: []round{ 439 { 440 new: []task{ 441 &dialTask{flags: dynDialedConn, dest: table[4]}, 442 &discoverTask{}, 443 }, 444 }, 445 }, 446 }) 447 } 448 449 // This test checks that static dials are launched. 450 func TestDialStateStaticDial(t *testing.T) { 451 config := &Config{ 452 StaticNodes: []*enode.Node{ 453 newNode(uintID(1), nil), 454 newNode(uintID(2), nil), 455 newNode(uintID(3), nil), 456 newNode(uintID(4), nil), 457 newNode(uintID(5), nil), 458 }, 459 Logger: testlog.Logger(t, log.LvlTrace), 460 } 461 runDialTest(t, dialtest{ 462 init: newDialState(enode.ID{}, fakeTable{}, 0, config), 463 rounds: []round{ 464 // Static dials are launched for the nodes that 465 // aren't yet connected. 466 { 467 peers: []*Peer{ 468 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 469 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 470 }, 471 new: []task{ 472 &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, 473 &dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)}, 474 &dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)}, 475 }, 476 }, 477 // No new tasks are launched in this round because all static 478 // nodes are either connected or still being dialed. 479 { 480 peers: []*Peer{ 481 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 482 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 483 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, 484 }, 485 done: []task{ 486 &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, 487 }, 488 }, 489 // No new dial tasks are launched because all static 490 // nodes are now connected. 491 { 492 peers: []*Peer{ 493 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 494 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 495 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, 496 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}}, 497 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, 498 }, 499 done: []task{ 500 &dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)}, 501 &dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)}, 502 }, 503 new: []task{ 504 &waitExpireTask{Duration: 19 * time.Second}, 505 }, 506 }, 507 // Wait a round for dial history to expire, no new tasks should spawn. 508 { 509 peers: []*Peer{ 510 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 511 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, 512 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, 513 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}}, 514 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, 515 }, 516 }, 517 // If a static node is dropped, it should be immediately redialed, 518 // irrespective whether it was originally static or dynamic. 519 { 520 done: []task{ 521 &waitExpireTask{Duration: 19 * time.Second}, 522 }, 523 peers: []*Peer{ 524 {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, 525 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, 526 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, 527 }, 528 new: []task{ 529 &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, 530 }, 531 }, 532 }, 533 }) 534 } 535 536 // This test checks that past dials are not retried for some time. 537 func TestDialStateCache(t *testing.T) { 538 config := &Config{ 539 StaticNodes: []*enode.Node{ 540 newNode(uintID(1), nil), 541 newNode(uintID(2), nil), 542 newNode(uintID(3), nil), 543 }, 544 Logger: testlog.Logger(t, log.LvlTrace), 545 } 546 runDialTest(t, dialtest{ 547 init: newDialState(enode.ID{}, fakeTable{}, 0, config), 548 rounds: []round{ 549 // Static dials are launched for the nodes that 550 // aren't yet connected. 551 { 552 peers: nil, 553 new: []task{ 554 &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, 555 &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, 556 &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, 557 }, 558 }, 559 // No new tasks are launched in this round because all static 560 // nodes are either connected or still being dialed. 561 { 562 peers: []*Peer{ 563 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, 564 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, 565 }, 566 done: []task{ 567 &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, 568 &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, 569 }, 570 }, 571 // A salvage task is launched to wait for node 3's history 572 // entry to expire. 573 { 574 peers: []*Peer{ 575 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, 576 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, 577 }, 578 done: []task{ 579 &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, 580 }, 581 new: []task{ 582 &waitExpireTask{Duration: 19 * time.Second}, 583 }, 584 }, 585 // Still waiting for node 3's entry to expire in the cache. 586 { 587 peers: []*Peer{ 588 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, 589 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, 590 }, 591 }, 592 { 593 peers: []*Peer{ 594 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, 595 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, 596 }, 597 }, 598 // The cache entry for node 3 has expired and is retried. 599 { 600 done: []task{ 601 &waitExpireTask{Duration: 19 * time.Second}, 602 }, 603 peers: []*Peer{ 604 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, 605 {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, 606 }, 607 new: []task{ 608 &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, 609 }, 610 }, 611 }, 612 }) 613 } 614 615 func TestDialResolve(t *testing.T) { 616 config := &Config{ 617 Logger: testlog.Logger(t, log.LvlTrace), 618 Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}, 619 } 620 resolved := newNode(uintID(1), net.IP{127, 0, 55, 234}) 621 table := &resolveMock{answer: resolved} 622 state := newDialState(enode.ID{}, table, 0, config) 623 624 // Check that the task is generated with an incomplete ID. 625 dest := newNode(uintID(1), nil) 626 state.addStatic(dest) 627 tasks := state.newTasks(0, nil, time.Time{}) 628 if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) { 629 t.Fatalf("expected dial task, got %#v", tasks) 630 } 631 632 // Now run the task, it should resolve the ID once. 633 srv := &Server{ntab: table, log: config.Logger, Config: *config} 634 tasks[0].Do(srv) 635 if !reflect.DeepEqual(table.resolveCalls, []*enode.Node{dest}) { 636 t.Fatalf("wrong resolve calls, got %v", table.resolveCalls) 637 } 638 639 // Report it as done to the dialer, which should update the static node record. 640 state.taskDone(tasks[0], time.Now()) 641 if state.static[uintID(1)].dest != resolved { 642 t.Fatalf("state.dest not updated") 643 } 644 } 645 646 // compares task lists but doesn't care about the order. 647 func sametasks(a, b []task) bool { 648 if len(a) != len(b) { 649 return false 650 } 651 next: 652 for _, ta := range a { 653 for _, tb := range b { 654 if reflect.DeepEqual(ta, tb) { 655 continue next 656 } 657 } 658 return false 659 } 660 return true 661 } 662 663 func uintID(i uint32) enode.ID { 664 var id enode.ID 665 binary.BigEndian.PutUint32(id[:], i) 666 return id 667 } 668 669 // implements discoverTable for TestDialResolve 670 type resolveMock struct { 671 resolveCalls []*enode.Node 672 answer *enode.Node 673 } 674 675 func (t *resolveMock) Resolve(n *enode.Node) *enode.Node { 676 t.resolveCalls = append(t.resolveCalls, n) 677 return t.answer 678 } 679 680 func (t *resolveMock) Self() *enode.Node { return new(enode.Node) } 681 func (t *resolveMock) Close() {} 682 func (t *resolveMock) LookupRandom() []*enode.Node { return nil } 683 func (t *resolveMock) ReadRandomNodes(buf []*enode.Node) int { return 0 }