dial_test.go 22 KB

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