dial_test.go 18 KB

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