You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1881 lines
61 KiB

  1. package p2p_test
  2. import (
  3. "context"
  4. "errors"
  5. "strings"
  6. "testing"
  7. "time"
  8. "github.com/fortytw2/leaktest"
  9. "github.com/stretchr/testify/require"
  10. dbm "github.com/tendermint/tm-db"
  11. "github.com/tendermint/tendermint/internal/p2p"
  12. "github.com/tendermint/tendermint/types"
  13. )
  14. // FIXME: We should probably have some randomized property-based tests for the
  15. // PeerManager too, which runs a bunch of random operations with random peers
  16. // and ensures certain invariants always hold. The logic can be complex, with
  17. // many interactions, and it's hard to cover all scenarios with handwritten
  18. // tests.
  19. func TestPeerManagerOptions_Validate(t *testing.T) {
  20. nodeID := types.NodeID("00112233445566778899aabbccddeeff00112233")
  21. testcases := map[string]struct {
  22. options p2p.PeerManagerOptions
  23. ok bool
  24. }{
  25. "zero options is valid": {p2p.PeerManagerOptions{}, true},
  26. // PersistentPeers
  27. "valid PersistentPeers NodeID": {p2p.PeerManagerOptions{
  28. PersistentPeers: []types.NodeID{"00112233445566778899aabbccddeeff00112233"},
  29. }, true},
  30. "invalid PersistentPeers NodeID": {p2p.PeerManagerOptions{
  31. PersistentPeers: []types.NodeID{"foo"},
  32. }, false},
  33. "uppercase PersistentPeers NodeID": {p2p.PeerManagerOptions{
  34. PersistentPeers: []types.NodeID{"00112233445566778899AABBCCDDEEFF00112233"},
  35. }, false},
  36. "PersistentPeers at MaxConnected": {p2p.PeerManagerOptions{
  37. PersistentPeers: []types.NodeID{nodeID, nodeID, nodeID},
  38. MaxConnected: 3,
  39. }, true},
  40. "PersistentPeers above MaxConnected": {p2p.PeerManagerOptions{
  41. PersistentPeers: []types.NodeID{nodeID, nodeID, nodeID},
  42. MaxConnected: 2,
  43. }, false},
  44. "PersistentPeers above MaxConnected below MaxConnectedUpgrade": {p2p.PeerManagerOptions{
  45. PersistentPeers: []types.NodeID{nodeID, nodeID, nodeID},
  46. MaxConnected: 2,
  47. MaxConnectedUpgrade: 2,
  48. }, false},
  49. // MaxPeers
  50. "MaxPeers without MaxConnected": {p2p.PeerManagerOptions{
  51. MaxPeers: 3,
  52. }, false},
  53. "MaxPeers below MaxConnected+MaxConnectedUpgrade": {p2p.PeerManagerOptions{
  54. MaxPeers: 2,
  55. MaxConnected: 2,
  56. MaxConnectedUpgrade: 1,
  57. }, false},
  58. "MaxPeers at MaxConnected+MaxConnectedUpgrade": {p2p.PeerManagerOptions{
  59. MaxPeers: 3,
  60. MaxConnected: 2,
  61. MaxConnectedUpgrade: 1,
  62. }, true},
  63. // MaxRetryTime
  64. "MaxRetryTime below MinRetryTime": {p2p.PeerManagerOptions{
  65. MinRetryTime: 7 * time.Second,
  66. MaxRetryTime: 5 * time.Second,
  67. }, false},
  68. "MaxRetryTime at MinRetryTime": {p2p.PeerManagerOptions{
  69. MinRetryTime: 5 * time.Second,
  70. MaxRetryTime: 5 * time.Second,
  71. }, true},
  72. "MaxRetryTime without MinRetryTime": {p2p.PeerManagerOptions{
  73. MaxRetryTime: 5 * time.Second,
  74. }, false},
  75. // MaxRetryTimePersistent
  76. "MaxRetryTimePersistent below MinRetryTime": {p2p.PeerManagerOptions{
  77. MinRetryTime: 7 * time.Second,
  78. MaxRetryTimePersistent: 5 * time.Second,
  79. }, false},
  80. "MaxRetryTimePersistent at MinRetryTime": {p2p.PeerManagerOptions{
  81. MinRetryTime: 5 * time.Second,
  82. MaxRetryTimePersistent: 5 * time.Second,
  83. }, true},
  84. "MaxRetryTimePersistent without MinRetryTime": {p2p.PeerManagerOptions{
  85. MaxRetryTimePersistent: 5 * time.Second,
  86. }, false},
  87. }
  88. for name, tc := range testcases {
  89. tc := tc
  90. t.Run(name, func(t *testing.T) {
  91. err := tc.options.Validate()
  92. if tc.ok {
  93. require.NoError(t, err)
  94. } else {
  95. require.Error(t, err)
  96. }
  97. })
  98. }
  99. }
  100. func TestNewPeerManager(t *testing.T) {
  101. // Zero options should be valid.
  102. _, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  103. require.NoError(t, err)
  104. // Invalid options should error.
  105. _, err = p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  106. PersistentPeers: []types.NodeID{"foo"},
  107. })
  108. require.Error(t, err)
  109. // Invalid database should error.
  110. _, err = p2p.NewPeerManager(selfID, nil, p2p.PeerManagerOptions{})
  111. require.Error(t, err)
  112. // Empty self ID should error.
  113. _, err = p2p.NewPeerManager("", nil, p2p.PeerManagerOptions{})
  114. require.Error(t, err)
  115. }
  116. func TestNewPeerManager_Persistence(t *testing.T) {
  117. aID := types.NodeID(strings.Repeat("a", 40))
  118. aAddresses := []p2p.NodeAddress{
  119. {Protocol: "tcp", NodeID: aID, Hostname: "127.0.0.1", Port: 26657, Path: "/path"},
  120. {Protocol: "memory", NodeID: aID},
  121. }
  122. bID := types.NodeID(strings.Repeat("b", 40))
  123. bAddresses := []p2p.NodeAddress{
  124. {Protocol: "tcp", NodeID: bID, Hostname: "b10c::1", Port: 26657, Path: "/path"},
  125. {Protocol: "memory", NodeID: bID},
  126. }
  127. cID := types.NodeID(strings.Repeat("c", 40))
  128. cAddresses := []p2p.NodeAddress{
  129. {Protocol: "tcp", NodeID: cID, Hostname: "host.domain", Port: 80},
  130. {Protocol: "memory", NodeID: cID},
  131. }
  132. // Create an initial peer manager and add the peers.
  133. db := dbm.NewMemDB()
  134. peerManager, err := p2p.NewPeerManager(selfID, db, p2p.PeerManagerOptions{
  135. PersistentPeers: []types.NodeID{aID},
  136. PeerScores: map[types.NodeID]p2p.PeerScore{bID: 1},
  137. })
  138. require.NoError(t, err)
  139. for _, addr := range append(append(aAddresses, bAddresses...), cAddresses...) {
  140. added, err := peerManager.Add(addr)
  141. require.NoError(t, err)
  142. require.True(t, added)
  143. }
  144. require.ElementsMatch(t, aAddresses, peerManager.Addresses(aID))
  145. require.ElementsMatch(t, bAddresses, peerManager.Addresses(bID))
  146. require.ElementsMatch(t, cAddresses, peerManager.Addresses(cID))
  147. require.Equal(t, map[types.NodeID]p2p.PeerScore{
  148. aID: p2p.PeerScorePersistent,
  149. bID: 1,
  150. cID: 0,
  151. }, peerManager.Scores())
  152. // Creating a new peer manager with the same database should retain the
  153. // peers, but they should have updated scores from the new PersistentPeers
  154. // configuration.
  155. peerManager, err = p2p.NewPeerManager(selfID, db, p2p.PeerManagerOptions{
  156. PersistentPeers: []types.NodeID{bID},
  157. PeerScores: map[types.NodeID]p2p.PeerScore{cID: 1},
  158. })
  159. require.NoError(t, err)
  160. require.ElementsMatch(t, aAddresses, peerManager.Addresses(aID))
  161. require.ElementsMatch(t, bAddresses, peerManager.Addresses(bID))
  162. require.ElementsMatch(t, cAddresses, peerManager.Addresses(cID))
  163. require.Equal(t, map[types.NodeID]p2p.PeerScore{
  164. aID: 0,
  165. bID: p2p.PeerScorePersistent,
  166. cID: 1,
  167. }, peerManager.Scores())
  168. }
  169. func TestNewPeerManager_SelfIDChange(t *testing.T) {
  170. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  171. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  172. db := dbm.NewMemDB()
  173. peerManager, err := p2p.NewPeerManager(selfID, db, p2p.PeerManagerOptions{})
  174. require.NoError(t, err)
  175. added, err := peerManager.Add(a)
  176. require.NoError(t, err)
  177. require.True(t, added)
  178. added, err = peerManager.Add(b)
  179. require.NoError(t, err)
  180. require.True(t, added)
  181. require.ElementsMatch(t, []types.NodeID{a.NodeID, b.NodeID}, peerManager.Peers())
  182. // If we change our selfID to one of the peers in the peer store, it
  183. // should be removed from the store.
  184. peerManager, err = p2p.NewPeerManager(a.NodeID, db, p2p.PeerManagerOptions{})
  185. require.NoError(t, err)
  186. require.Equal(t, []types.NodeID{b.NodeID}, peerManager.Peers())
  187. }
  188. func TestPeerManager_Add(t *testing.T) {
  189. aID := types.NodeID(strings.Repeat("a", 40))
  190. bID := types.NodeID(strings.Repeat("b", 40))
  191. cID := types.NodeID(strings.Repeat("c", 40))
  192. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  193. PersistentPeers: []types.NodeID{aID, cID},
  194. MaxPeers: 2,
  195. MaxConnected: 2,
  196. })
  197. require.NoError(t, err)
  198. // Adding a couple of addresses should work.
  199. aAddresses := []p2p.NodeAddress{
  200. {Protocol: "tcp", NodeID: aID, Hostname: "localhost"},
  201. {Protocol: "memory", NodeID: aID},
  202. }
  203. for _, addr := range aAddresses {
  204. added, err := peerManager.Add(addr)
  205. require.NoError(t, err)
  206. require.True(t, added)
  207. }
  208. require.ElementsMatch(t, aAddresses, peerManager.Addresses(aID))
  209. // Adding a different peer should be fine.
  210. bAddress := p2p.NodeAddress{Protocol: "tcp", NodeID: bID, Hostname: "localhost"}
  211. added, err := peerManager.Add(bAddress)
  212. require.NoError(t, err)
  213. require.True(t, added)
  214. require.Equal(t, []p2p.NodeAddress{bAddress}, peerManager.Addresses(bID))
  215. require.ElementsMatch(t, aAddresses, peerManager.Addresses(aID))
  216. // Adding an existing address again should be a noop.
  217. added, err = peerManager.Add(aAddresses[0])
  218. require.NoError(t, err)
  219. require.False(t, added)
  220. require.ElementsMatch(t, aAddresses, peerManager.Addresses(aID))
  221. // Adding a third peer with MaxPeers=2 should cause bID, which is
  222. // the lowest-scored peer (not in PersistentPeers), to be removed.
  223. added, err = peerManager.Add(p2p.NodeAddress{
  224. Protocol: "tcp", NodeID: cID, Hostname: "localhost"})
  225. require.NoError(t, err)
  226. require.True(t, added)
  227. require.ElementsMatch(t, []types.NodeID{aID, cID}, peerManager.Peers())
  228. // Adding an invalid address should error.
  229. _, err = peerManager.Add(p2p.NodeAddress{Path: "foo"})
  230. require.Error(t, err)
  231. // Adding self should error
  232. _, err = peerManager.Add(p2p.NodeAddress{Protocol: "memory", NodeID: selfID})
  233. require.Error(t, err)
  234. }
  235. func TestPeerManager_DialNext(t *testing.T) {
  236. ctx, cancel := context.WithCancel(context.Background())
  237. defer cancel()
  238. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  239. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  240. require.NoError(t, err)
  241. // Add an address. DialNext should return it.
  242. added, err := peerManager.Add(a)
  243. require.NoError(t, err)
  244. require.True(t, added)
  245. address, err := peerManager.DialNext(ctx)
  246. require.NoError(t, err)
  247. require.Equal(t, a, address)
  248. // Since there are no more undialed peers, the next call should block
  249. // until it times out.
  250. timeoutCtx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
  251. defer cancel()
  252. _, err = peerManager.DialNext(timeoutCtx)
  253. require.Error(t, err)
  254. require.Equal(t, context.DeadlineExceeded, err)
  255. }
  256. func TestPeerManager_DialNext_Retry(t *testing.T) {
  257. ctx, cancel := context.WithCancel(context.Background())
  258. defer cancel()
  259. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  260. options := p2p.PeerManagerOptions{
  261. MinRetryTime: 100 * time.Millisecond,
  262. MaxRetryTime: 500 * time.Millisecond,
  263. }
  264. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), options)
  265. require.NoError(t, err)
  266. added, err := peerManager.Add(a)
  267. require.NoError(t, err)
  268. require.True(t, added)
  269. // Do five dial retries (six dials total). The retry time should double for
  270. // each failure. At the forth retry, MaxRetryTime should kick in.
  271. ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
  272. defer cancel()
  273. for i := 0; i <= 5; i++ {
  274. start := time.Now()
  275. dial, err := peerManager.DialNext(ctx)
  276. require.NoError(t, err)
  277. require.Equal(t, a, dial)
  278. elapsed := time.Since(start).Round(time.Millisecond)
  279. switch i {
  280. case 0:
  281. require.LessOrEqual(t, elapsed, options.MinRetryTime)
  282. case 1:
  283. require.GreaterOrEqual(t, elapsed, options.MinRetryTime)
  284. case 2:
  285. require.GreaterOrEqual(t, elapsed, 2*options.MinRetryTime)
  286. case 3:
  287. require.GreaterOrEqual(t, elapsed, 4*options.MinRetryTime)
  288. case 4, 5:
  289. require.GreaterOrEqual(t, elapsed, options.MaxRetryTime)
  290. require.LessOrEqual(t, elapsed, 8*options.MinRetryTime)
  291. default:
  292. require.Fail(t, "unexpected retry")
  293. }
  294. require.NoError(t, peerManager.DialFailed(ctx, a))
  295. }
  296. }
  297. func TestPeerManager_DialNext_WakeOnAdd(t *testing.T) {
  298. ctx, cancel := context.WithCancel(context.Background())
  299. defer cancel()
  300. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  301. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  302. require.NoError(t, err)
  303. // Spawn a goroutine to add a peer after a delay.
  304. go func() {
  305. time.Sleep(200 * time.Millisecond)
  306. added, err := peerManager.Add(a)
  307. require.NoError(t, err)
  308. require.True(t, added)
  309. }()
  310. // This will block until peer is added above.
  311. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  312. defer cancel()
  313. dial, err := peerManager.DialNext(ctx)
  314. require.NoError(t, err)
  315. require.Equal(t, a, dial)
  316. }
  317. func TestPeerManager_DialNext_WakeOnDialFailed(t *testing.T) {
  318. ctx, cancel := context.WithCancel(context.Background())
  319. defer cancel()
  320. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  321. MaxConnected: 1,
  322. })
  323. require.NoError(t, err)
  324. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  325. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  326. // Add and dial a.
  327. added, err := peerManager.Add(a)
  328. require.NoError(t, err)
  329. require.True(t, added)
  330. dial, err := peerManager.TryDialNext()
  331. require.NoError(t, err)
  332. require.Equal(t, a, dial)
  333. // Add b. We shouldn't be able to dial it, due to MaxConnected.
  334. added, err = peerManager.Add(b)
  335. require.NoError(t, err)
  336. require.True(t, added)
  337. dial, err = peerManager.TryDialNext()
  338. require.NoError(t, err)
  339. require.Zero(t, dial)
  340. // Spawn a goroutine to fail a's dial attempt.
  341. sig := make(chan struct{})
  342. go func() {
  343. defer close(sig)
  344. time.Sleep(200 * time.Millisecond)
  345. require.NoError(t, peerManager.DialFailed(ctx, a))
  346. }()
  347. // This should make b available for dialing (not a, retries are disabled).
  348. opctx, opcancel := context.WithTimeout(ctx, 3*time.Second)
  349. defer opcancel()
  350. dial, err = peerManager.DialNext(opctx)
  351. require.NoError(t, err)
  352. require.Equal(t, b, dial)
  353. <-sig
  354. }
  355. func TestPeerManager_DialNext_WakeOnDialFailedRetry(t *testing.T) {
  356. ctx, cancel := context.WithCancel(context.Background())
  357. defer cancel()
  358. options := p2p.PeerManagerOptions{MinRetryTime: 200 * time.Millisecond}
  359. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), options)
  360. require.NoError(t, err)
  361. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  362. // Add a, dial it, and mark it a failure. This will start a retry timer.
  363. added, err := peerManager.Add(a)
  364. require.NoError(t, err)
  365. require.True(t, added)
  366. dial, err := peerManager.TryDialNext()
  367. require.NoError(t, err)
  368. require.Equal(t, a, dial)
  369. require.NoError(t, peerManager.DialFailed(ctx, dial))
  370. failed := time.Now()
  371. // The retry timer should unblock DialNext and make a available again after
  372. // the retry time passes.
  373. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  374. defer cancel()
  375. dial, err = peerManager.DialNext(ctx)
  376. require.NoError(t, err)
  377. require.Equal(t, a, dial)
  378. require.GreaterOrEqual(t, time.Since(failed), options.MinRetryTime)
  379. }
  380. func TestPeerManager_DialNext_WakeOnDisconnected(t *testing.T) {
  381. ctx, cancel := context.WithCancel(context.Background())
  382. defer cancel()
  383. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  384. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  385. require.NoError(t, err)
  386. added, err := peerManager.Add(a)
  387. require.NoError(t, err)
  388. require.True(t, added)
  389. err = peerManager.Accepted(a.NodeID)
  390. require.NoError(t, err)
  391. dial, err := peerManager.TryDialNext()
  392. require.NoError(t, err)
  393. require.Zero(t, dial)
  394. dctx, dcancel := context.WithTimeout(ctx, 300*time.Millisecond)
  395. defer dcancel()
  396. go func() {
  397. time.Sleep(200 * time.Millisecond)
  398. peerManager.Disconnected(dctx, a.NodeID)
  399. }()
  400. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  401. defer cancel()
  402. dial, err = peerManager.DialNext(ctx)
  403. require.NoError(t, err)
  404. require.Equal(t, a, dial)
  405. }
  406. func TestPeerManager_TryDialNext_MaxConnected(t *testing.T) {
  407. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  408. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  409. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  410. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  411. MaxConnected: 2,
  412. })
  413. require.NoError(t, err)
  414. // Add a and connect to it.
  415. added, err := peerManager.Add(a)
  416. require.NoError(t, err)
  417. require.True(t, added)
  418. dial, err := peerManager.TryDialNext()
  419. require.NoError(t, err)
  420. require.Equal(t, a, dial)
  421. require.NoError(t, peerManager.Dialed(a))
  422. // Add b and start dialing it.
  423. added, err = peerManager.Add(b)
  424. require.NoError(t, err)
  425. require.True(t, added)
  426. dial, err = peerManager.TryDialNext()
  427. require.NoError(t, err)
  428. require.Equal(t, b, dial)
  429. // At this point, adding c will not allow dialing it.
  430. added, err = peerManager.Add(c)
  431. require.NoError(t, err)
  432. require.True(t, added)
  433. dial, err = peerManager.TryDialNext()
  434. require.NoError(t, err)
  435. require.Zero(t, dial)
  436. }
  437. func TestPeerManager_TryDialNext_MaxConnectedUpgrade(t *testing.T) {
  438. ctx, cancel := context.WithCancel(context.Background())
  439. defer cancel()
  440. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  441. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  442. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  443. d := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("d", 40))}
  444. e := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("e", 40))}
  445. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  446. PeerScores: map[types.NodeID]p2p.PeerScore{
  447. a.NodeID: 0,
  448. b.NodeID: 1,
  449. c.NodeID: 2,
  450. d.NodeID: 3,
  451. e.NodeID: 0,
  452. },
  453. PersistentPeers: []types.NodeID{c.NodeID, d.NodeID},
  454. MaxConnected: 2,
  455. MaxConnectedUpgrade: 1,
  456. })
  457. require.NoError(t, err)
  458. // Add a and connect to it.
  459. added, err := peerManager.Add(a)
  460. require.NoError(t, err)
  461. require.True(t, added)
  462. dial, err := peerManager.TryDialNext()
  463. require.NoError(t, err)
  464. require.Equal(t, a, dial)
  465. require.NoError(t, peerManager.Dialed(a))
  466. // Add b and start dialing it.
  467. added, err = peerManager.Add(b)
  468. require.NoError(t, err)
  469. require.True(t, added)
  470. dial, err = peerManager.TryDialNext()
  471. require.NoError(t, err)
  472. require.Equal(t, b, dial)
  473. // Even though we are at capacity, we should be allowed to dial c for an
  474. // upgrade of a, since it's higher-scored.
  475. added, err = peerManager.Add(c)
  476. require.NoError(t, err)
  477. require.True(t, added)
  478. dial, err = peerManager.TryDialNext()
  479. require.NoError(t, err)
  480. require.Equal(t, c, dial)
  481. // However, since we're using all upgrade slots now, we can't add and dial
  482. // d, even though it's also higher-scored.
  483. added, err = peerManager.Add(d)
  484. require.NoError(t, err)
  485. require.True(t, added)
  486. dial, err = peerManager.TryDialNext()
  487. require.NoError(t, err)
  488. require.Zero(t, dial)
  489. // We go through with c's upgrade.
  490. require.NoError(t, peerManager.Dialed(c))
  491. // Still can't dial d.
  492. dial, err = peerManager.TryDialNext()
  493. require.NoError(t, err)
  494. require.Zero(t, dial)
  495. // Now, if we disconnect a, we should be allowed to dial d because we have a
  496. // free upgrade slot.
  497. peerManager.Disconnected(ctx, a.NodeID)
  498. dial, err = peerManager.TryDialNext()
  499. require.NoError(t, err)
  500. require.Equal(t, d, dial)
  501. require.NoError(t, peerManager.Dialed(d))
  502. // However, if we disconnect b (such that only c and d are connected), we
  503. // should not be allowed to dial e even though there are upgrade slots,
  504. // because there are no lower-scored nodes that can be upgraded.
  505. peerManager.Disconnected(ctx, b.NodeID)
  506. added, err = peerManager.Add(e)
  507. require.NoError(t, err)
  508. require.True(t, added)
  509. dial, err = peerManager.TryDialNext()
  510. require.NoError(t, err)
  511. require.Zero(t, dial)
  512. }
  513. func TestPeerManager_TryDialNext_UpgradeReservesPeer(t *testing.T) {
  514. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  515. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  516. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  517. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  518. PeerScores: map[types.NodeID]p2p.PeerScore{b.NodeID: 1, c.NodeID: 1},
  519. MaxConnected: 1,
  520. MaxConnectedUpgrade: 2,
  521. })
  522. require.NoError(t, err)
  523. // Add a and connect to it.
  524. added, err := peerManager.Add(a)
  525. require.NoError(t, err)
  526. require.True(t, added)
  527. dial, err := peerManager.TryDialNext()
  528. require.NoError(t, err)
  529. require.Equal(t, a, dial)
  530. require.NoError(t, peerManager.Dialed(a))
  531. // Add b and start dialing it. This will claim a for upgrading.
  532. added, err = peerManager.Add(b)
  533. require.NoError(t, err)
  534. require.True(t, added)
  535. dial, err = peerManager.TryDialNext()
  536. require.NoError(t, err)
  537. require.Equal(t, b, dial)
  538. // Adding c and dialing it will fail, because a is the only connected
  539. // peer that can be upgraded, and b is already trying to upgrade it.
  540. added, err = peerManager.Add(c)
  541. require.NoError(t, err)
  542. require.True(t, added)
  543. dial, err = peerManager.TryDialNext()
  544. require.NoError(t, err)
  545. require.Empty(t, dial)
  546. }
  547. func TestPeerManager_TryDialNext_DialingConnected(t *testing.T) {
  548. aID := types.NodeID(strings.Repeat("a", 40))
  549. a := p2p.NodeAddress{Protocol: "memory", NodeID: aID}
  550. aTCP := p2p.NodeAddress{Protocol: "tcp", NodeID: aID, Hostname: "localhost"}
  551. bID := types.NodeID(strings.Repeat("b", 40))
  552. b := p2p.NodeAddress{Protocol: "memory", NodeID: bID}
  553. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  554. MaxConnected: 2,
  555. })
  556. require.NoError(t, err)
  557. // Add a and dial it.
  558. added, err := peerManager.Add(a)
  559. require.NoError(t, err)
  560. require.True(t, added)
  561. dial, err := peerManager.TryDialNext()
  562. require.NoError(t, err)
  563. require.Equal(t, a, dial)
  564. // Adding a's TCP address will not dispense a, since it's already dialing.
  565. added, err = peerManager.Add(aTCP)
  566. require.NoError(t, err)
  567. require.True(t, added)
  568. dial, err = peerManager.TryDialNext()
  569. require.NoError(t, err)
  570. require.Zero(t, dial)
  571. // Marking a as dialed will still not dispense it.
  572. require.NoError(t, peerManager.Dialed(a))
  573. dial, err = peerManager.TryDialNext()
  574. require.NoError(t, err)
  575. require.Zero(t, dial)
  576. // Adding b and accepting a connection from it will not dispense it either.
  577. added, err = peerManager.Add(b)
  578. require.NoError(t, err)
  579. require.True(t, added)
  580. require.NoError(t, peerManager.Accepted(bID))
  581. dial, err = peerManager.TryDialNext()
  582. require.NoError(t, err)
  583. require.Zero(t, dial)
  584. }
  585. func TestPeerManager_TryDialNext_Multiple(t *testing.T) {
  586. ctx, cancel := context.WithCancel(context.Background())
  587. defer cancel()
  588. aID := types.NodeID(strings.Repeat("a", 40))
  589. bID := types.NodeID(strings.Repeat("b", 40))
  590. addresses := []p2p.NodeAddress{
  591. {Protocol: "memory", NodeID: aID},
  592. {Protocol: "memory", NodeID: bID},
  593. {Protocol: "tcp", NodeID: aID, Hostname: "127.0.0.1"},
  594. {Protocol: "tcp", NodeID: bID, Hostname: "::1"},
  595. }
  596. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  597. require.NoError(t, err)
  598. for _, address := range addresses {
  599. added, err := peerManager.Add(address)
  600. require.NoError(t, err)
  601. require.True(t, added)
  602. }
  603. // All addresses should be dispensed as long as dialing them has failed.
  604. dial := []p2p.NodeAddress{}
  605. for range addresses {
  606. address, err := peerManager.TryDialNext()
  607. require.NoError(t, err)
  608. require.NotZero(t, address)
  609. require.NoError(t, peerManager.DialFailed(ctx, address))
  610. dial = append(dial, address)
  611. }
  612. require.ElementsMatch(t, dial, addresses)
  613. address, err := peerManager.TryDialNext()
  614. require.NoError(t, err)
  615. require.Zero(t, address)
  616. }
  617. func TestPeerManager_DialFailed(t *testing.T) {
  618. // DialFailed is tested through other tests, we'll just check a few basic
  619. // things here, e.g. reporting unknown addresses.
  620. aID := types.NodeID(strings.Repeat("a", 40))
  621. a := p2p.NodeAddress{Protocol: "memory", NodeID: aID}
  622. bID := types.NodeID(strings.Repeat("b", 40))
  623. b := p2p.NodeAddress{Protocol: "memory", NodeID: bID}
  624. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  625. require.NoError(t, err)
  626. added, err := peerManager.Add(a)
  627. require.NoError(t, err)
  628. require.True(t, added)
  629. ctx, cancel := context.WithCancel(context.Background())
  630. defer cancel()
  631. // Dialing and then calling DialFailed with a different address (same
  632. // NodeID) should unmark as dialing and allow us to dial the other address
  633. // again, but not register the failed address.
  634. dial, err := peerManager.TryDialNext()
  635. require.NoError(t, err)
  636. require.Equal(t, a, dial)
  637. require.NoError(t, peerManager.DialFailed(ctx, p2p.NodeAddress{
  638. Protocol: "tcp", NodeID: aID, Hostname: "localhost"}))
  639. require.Equal(t, []p2p.NodeAddress{a}, peerManager.Addresses(aID))
  640. dial, err = peerManager.TryDialNext()
  641. require.NoError(t, err)
  642. require.Equal(t, a, dial)
  643. // Calling DialFailed on same address twice should be fine.
  644. require.NoError(t, peerManager.DialFailed(ctx, a))
  645. require.NoError(t, peerManager.DialFailed(ctx, a))
  646. // DialFailed on an unknown peer shouldn't error or add it.
  647. require.NoError(t, peerManager.DialFailed(ctx, b))
  648. require.Equal(t, []types.NodeID{aID}, peerManager.Peers())
  649. }
  650. func TestPeerManager_DialFailed_UnreservePeer(t *testing.T) {
  651. ctx, cancel := context.WithCancel(context.Background())
  652. defer cancel()
  653. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  654. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  655. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  656. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  657. PeerScores: map[types.NodeID]p2p.PeerScore{b.NodeID: 1, c.NodeID: 1},
  658. MaxConnected: 1,
  659. MaxConnectedUpgrade: 2,
  660. })
  661. require.NoError(t, err)
  662. // Add a and connect to it.
  663. added, err := peerManager.Add(a)
  664. require.NoError(t, err)
  665. require.True(t, added)
  666. dial, err := peerManager.TryDialNext()
  667. require.NoError(t, err)
  668. require.Equal(t, a, dial)
  669. require.NoError(t, peerManager.Dialed(a))
  670. // Add b and start dialing it. This will claim a for upgrading.
  671. added, err = peerManager.Add(b)
  672. require.NoError(t, err)
  673. require.True(t, added)
  674. dial, err = peerManager.TryDialNext()
  675. require.NoError(t, err)
  676. require.Equal(t, b, dial)
  677. // Adding c and dialing it will fail, even though it could upgrade a and we
  678. // have free upgrade slots, because a is the only connected peer that can be
  679. // upgraded and b is already trying to upgrade it.
  680. added, err = peerManager.Add(c)
  681. require.NoError(t, err)
  682. require.True(t, added)
  683. dial, err = peerManager.TryDialNext()
  684. require.NoError(t, err)
  685. require.Empty(t, dial)
  686. // Failing b's dial will now make c available for dialing.
  687. require.NoError(t, peerManager.DialFailed(ctx, b))
  688. dial, err = peerManager.TryDialNext()
  689. require.NoError(t, err)
  690. require.Equal(t, c, dial)
  691. }
  692. func TestPeerManager_Dialed_Connected(t *testing.T) {
  693. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  694. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  695. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  696. require.NoError(t, err)
  697. // Marking a as dialed twice should error.
  698. added, err := peerManager.Add(a)
  699. require.NoError(t, err)
  700. require.True(t, added)
  701. dial, err := peerManager.TryDialNext()
  702. require.NoError(t, err)
  703. require.Equal(t, a, dial)
  704. require.NoError(t, peerManager.Dialed(a))
  705. require.Error(t, peerManager.Dialed(a))
  706. // Accepting a connection from b and then trying to mark it as dialed should fail.
  707. added, err = peerManager.Add(b)
  708. require.NoError(t, err)
  709. require.True(t, added)
  710. dial, err = peerManager.TryDialNext()
  711. require.NoError(t, err)
  712. require.Equal(t, b, dial)
  713. require.NoError(t, peerManager.Accepted(b.NodeID))
  714. require.Error(t, peerManager.Dialed(b))
  715. }
  716. func TestPeerManager_Dialed_Self(t *testing.T) {
  717. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  718. require.NoError(t, err)
  719. // Dialing self should error.
  720. _, err = peerManager.Add(p2p.NodeAddress{Protocol: "memory", NodeID: selfID})
  721. require.Error(t, err)
  722. }
  723. func TestPeerManager_Dialed_MaxConnected(t *testing.T) {
  724. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  725. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  726. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  727. MaxConnected: 1,
  728. })
  729. require.NoError(t, err)
  730. // Start to dial a.
  731. added, err := peerManager.Add(a)
  732. require.NoError(t, err)
  733. require.True(t, added)
  734. dial, err := peerManager.TryDialNext()
  735. require.NoError(t, err)
  736. require.Equal(t, a, dial)
  737. // Marking b as dialed in the meanwhile (even without TryDialNext)
  738. // should be fine.
  739. added, err = peerManager.Add(b)
  740. require.NoError(t, err)
  741. require.True(t, added)
  742. require.NoError(t, peerManager.Dialed(b))
  743. // Completing the dial for a should now error.
  744. require.Error(t, peerManager.Dialed(a))
  745. }
  746. func TestPeerManager_Dialed_MaxConnectedUpgrade(t *testing.T) {
  747. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  748. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  749. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  750. d := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("d", 40))}
  751. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  752. MaxConnected: 2,
  753. MaxConnectedUpgrade: 1,
  754. PeerScores: map[types.NodeID]p2p.PeerScore{c.NodeID: 1, d.NodeID: 1},
  755. })
  756. require.NoError(t, err)
  757. // Dialing a and b is fine.
  758. added, err := peerManager.Add(a)
  759. require.NoError(t, err)
  760. require.True(t, added)
  761. require.NoError(t, peerManager.Dialed(a))
  762. added, err = peerManager.Add(b)
  763. require.NoError(t, err)
  764. require.True(t, added)
  765. require.NoError(t, peerManager.Dialed(b))
  766. // Starting an upgrade of c should be fine.
  767. added, err = peerManager.Add(c)
  768. require.NoError(t, err)
  769. require.True(t, added)
  770. dial, err := peerManager.TryDialNext()
  771. require.NoError(t, err)
  772. require.Equal(t, c, dial)
  773. require.NoError(t, peerManager.Dialed(c))
  774. // Trying to mark d dialed should fail, since there are no more upgrade
  775. // slots and a/b haven't been evicted yet.
  776. added, err = peerManager.Add(d)
  777. require.NoError(t, err)
  778. require.True(t, added)
  779. require.Error(t, peerManager.Dialed(d))
  780. }
  781. func TestPeerManager_Dialed_Unknown(t *testing.T) {
  782. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  783. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  784. require.NoError(t, err)
  785. // Marking an unknown node as dialed should error.
  786. require.Error(t, peerManager.Dialed(a))
  787. }
  788. func TestPeerManager_Dialed_Upgrade(t *testing.T) {
  789. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  790. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  791. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  792. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  793. MaxConnected: 1,
  794. MaxConnectedUpgrade: 2,
  795. PeerScores: map[types.NodeID]p2p.PeerScore{b.NodeID: 1, c.NodeID: 1},
  796. })
  797. require.NoError(t, err)
  798. // Dialing a is fine.
  799. added, err := peerManager.Add(a)
  800. require.NoError(t, err)
  801. require.True(t, added)
  802. require.NoError(t, peerManager.Dialed(a))
  803. // Upgrading it with b should work, since b has a higher score.
  804. added, err = peerManager.Add(b)
  805. require.NoError(t, err)
  806. require.True(t, added)
  807. dial, err := peerManager.TryDialNext()
  808. require.NoError(t, err)
  809. require.Equal(t, b, dial)
  810. require.NoError(t, peerManager.Dialed(b))
  811. // a hasn't been evicted yet, but c shouldn't be allowed to upgrade anyway
  812. // since it's about to be evicted.
  813. added, err = peerManager.Add(c)
  814. require.NoError(t, err)
  815. require.True(t, added)
  816. dial, err = peerManager.TryDialNext()
  817. require.NoError(t, err)
  818. require.Empty(t, dial)
  819. // a should now be evicted.
  820. evict, err := peerManager.TryEvictNext()
  821. require.NoError(t, err)
  822. require.Equal(t, a.NodeID, evict)
  823. }
  824. func TestPeerManager_Dialed_UpgradeEvenLower(t *testing.T) {
  825. ctx, cancel := context.WithCancel(context.Background())
  826. defer cancel()
  827. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  828. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  829. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  830. d := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("d", 40))}
  831. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  832. MaxConnected: 2,
  833. MaxConnectedUpgrade: 1,
  834. PeerScores: map[types.NodeID]p2p.PeerScore{
  835. a.NodeID: 3,
  836. b.NodeID: 2,
  837. c.NodeID: 10,
  838. d.NodeID: 1,
  839. },
  840. })
  841. require.NoError(t, err)
  842. // Connect to a and b.
  843. added, err := peerManager.Add(a)
  844. require.NoError(t, err)
  845. require.True(t, added)
  846. require.NoError(t, peerManager.Dialed(a))
  847. added, err = peerManager.Add(b)
  848. require.NoError(t, err)
  849. require.True(t, added)
  850. require.NoError(t, peerManager.Dialed(b))
  851. // Start an upgrade with c, which should pick b to upgrade (since it
  852. // has score 2).
  853. added, err = peerManager.Add(c)
  854. require.NoError(t, err)
  855. require.True(t, added)
  856. dial, err := peerManager.TryDialNext()
  857. require.NoError(t, err)
  858. require.Equal(t, c, dial)
  859. // In the meanwhile, a disconnects and d connects. d is even lower-scored
  860. // than b (1 vs 2), which is currently being upgraded.
  861. peerManager.Disconnected(ctx, a.NodeID)
  862. added, err = peerManager.Add(d)
  863. require.NoError(t, err)
  864. require.True(t, added)
  865. require.NoError(t, peerManager.Accepted(d.NodeID))
  866. // Once c completes the upgrade of b, it should instead evict d,
  867. // since it has en even lower score.
  868. require.NoError(t, peerManager.Dialed(c))
  869. evict, err := peerManager.TryEvictNext()
  870. require.NoError(t, err)
  871. require.Equal(t, d.NodeID, evict)
  872. }
  873. func TestPeerManager_Dialed_UpgradeNoEvict(t *testing.T) {
  874. ctx, cancel := context.WithCancel(context.Background())
  875. defer cancel()
  876. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  877. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  878. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  879. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  880. MaxConnected: 2,
  881. MaxConnectedUpgrade: 1,
  882. PeerScores: map[types.NodeID]p2p.PeerScore{
  883. a.NodeID: 1,
  884. b.NodeID: 2,
  885. c.NodeID: 3,
  886. },
  887. })
  888. require.NoError(t, err)
  889. // Connect to a and b.
  890. added, err := peerManager.Add(a)
  891. require.NoError(t, err)
  892. require.True(t, added)
  893. require.NoError(t, peerManager.Dialed(a))
  894. added, err = peerManager.Add(b)
  895. require.NoError(t, err)
  896. require.True(t, added)
  897. require.NoError(t, peerManager.Dialed(b))
  898. // Start an upgrade with c, which should pick a to upgrade.
  899. added, err = peerManager.Add(c)
  900. require.NoError(t, err)
  901. require.True(t, added)
  902. dial, err := peerManager.TryDialNext()
  903. require.NoError(t, err)
  904. require.Equal(t, c, dial)
  905. // In the meanwhile, b disconnects.
  906. peerManager.Disconnected(ctx, b.NodeID)
  907. // Once c completes the upgrade of b, there is no longer a need to
  908. // evict anything since we're at capacity.
  909. // since it has en even lower score.
  910. require.NoError(t, peerManager.Dialed(c))
  911. evict, err := peerManager.TryEvictNext()
  912. require.NoError(t, err)
  913. require.Zero(t, evict)
  914. }
  915. func TestPeerManager_Accepted(t *testing.T) {
  916. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  917. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  918. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  919. d := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("d", 40))}
  920. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  921. require.NoError(t, err)
  922. // Accepting a connection from self should error.
  923. require.Error(t, peerManager.Accepted(selfID))
  924. // Accepting a connection from a known peer should work.
  925. added, err := peerManager.Add(a)
  926. require.NoError(t, err)
  927. require.True(t, added)
  928. require.NoError(t, peerManager.Accepted(a.NodeID))
  929. // Accepting a connection from an already accepted peer should error.
  930. require.Error(t, peerManager.Accepted(a.NodeID))
  931. // Accepting a connection from an unknown peer should work and register it.
  932. require.NoError(t, peerManager.Accepted(b.NodeID))
  933. require.ElementsMatch(t, []types.NodeID{a.NodeID, b.NodeID}, peerManager.Peers())
  934. // Accepting a connection from a peer that's being dialed should work, and
  935. // should cause the dial to fail.
  936. added, err = peerManager.Add(c)
  937. require.NoError(t, err)
  938. require.True(t, added)
  939. dial, err := peerManager.TryDialNext()
  940. require.NoError(t, err)
  941. require.Equal(t, c, dial)
  942. require.NoError(t, peerManager.Accepted(c.NodeID))
  943. require.Error(t, peerManager.Dialed(c))
  944. // Accepting a connection from a peer that's been dialed should fail.
  945. added, err = peerManager.Add(d)
  946. require.NoError(t, err)
  947. require.True(t, added)
  948. dial, err = peerManager.TryDialNext()
  949. require.NoError(t, err)
  950. require.Equal(t, d, dial)
  951. require.NoError(t, peerManager.Dialed(d))
  952. require.Error(t, peerManager.Accepted(d.NodeID))
  953. }
  954. func TestPeerManager_Accepted_MaxConnected(t *testing.T) {
  955. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  956. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  957. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  958. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  959. MaxConnected: 2,
  960. })
  961. require.NoError(t, err)
  962. // Connect to a and b.
  963. added, err := peerManager.Add(a)
  964. require.NoError(t, err)
  965. require.True(t, added)
  966. require.NoError(t, peerManager.Dialed(a))
  967. added, err = peerManager.Add(b)
  968. require.NoError(t, err)
  969. require.True(t, added)
  970. require.NoError(t, peerManager.Accepted(b.NodeID))
  971. // Accepting c should now fail.
  972. added, err = peerManager.Add(c)
  973. require.NoError(t, err)
  974. require.True(t, added)
  975. require.Error(t, peerManager.Accepted(c.NodeID))
  976. }
  977. func TestPeerManager_Accepted_MaxConnectedUpgrade(t *testing.T) {
  978. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  979. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  980. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  981. d := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("d", 40))}
  982. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  983. PeerScores: map[types.NodeID]p2p.PeerScore{
  984. c.NodeID: 1,
  985. d.NodeID: 2,
  986. },
  987. MaxConnected: 1,
  988. MaxConnectedUpgrade: 1,
  989. })
  990. require.NoError(t, err)
  991. // Dial a.
  992. added, err := peerManager.Add(a)
  993. require.NoError(t, err)
  994. require.True(t, added)
  995. require.NoError(t, peerManager.Dialed(a))
  996. // Accepting b should fail, since it's not an upgrade over a.
  997. added, err = peerManager.Add(b)
  998. require.NoError(t, err)
  999. require.True(t, added)
  1000. require.Error(t, peerManager.Accepted(b.NodeID))
  1001. // Accepting c should work, since it upgrades a.
  1002. added, err = peerManager.Add(c)
  1003. require.NoError(t, err)
  1004. require.True(t, added)
  1005. require.NoError(t, peerManager.Accepted(c.NodeID))
  1006. // a still hasn't been evicted, so accepting b should still fail.
  1007. _, err = peerManager.Add(b)
  1008. require.NoError(t, err)
  1009. require.Error(t, peerManager.Accepted(b.NodeID))
  1010. // Also, accepting d should fail, since all upgrade slots are full.
  1011. added, err = peerManager.Add(d)
  1012. require.NoError(t, err)
  1013. require.True(t, added)
  1014. require.Error(t, peerManager.Accepted(d.NodeID))
  1015. }
  1016. func TestPeerManager_Accepted_Upgrade(t *testing.T) {
  1017. ctx, cancel := context.WithCancel(context.Background())
  1018. defer cancel()
  1019. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1020. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1021. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  1022. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1023. PeerScores: map[types.NodeID]p2p.PeerScore{
  1024. b.NodeID: 1,
  1025. c.NodeID: 1,
  1026. },
  1027. MaxConnected: 1,
  1028. MaxConnectedUpgrade: 2,
  1029. })
  1030. require.NoError(t, err)
  1031. // Accept a.
  1032. added, err := peerManager.Add(a)
  1033. require.NoError(t, err)
  1034. require.True(t, added)
  1035. require.NoError(t, peerManager.Accepted(a.NodeID))
  1036. // Accepting b should work, since it upgrades a.
  1037. added, err = peerManager.Add(b)
  1038. require.NoError(t, err)
  1039. require.True(t, added)
  1040. require.NoError(t, peerManager.Accepted(b.NodeID))
  1041. // c cannot get accepted, since a has been upgraded by b.
  1042. added, err = peerManager.Add(c)
  1043. require.NoError(t, err)
  1044. require.True(t, added)
  1045. require.Error(t, peerManager.Accepted(c.NodeID))
  1046. // This should cause a to get evicted.
  1047. evict, err := peerManager.TryEvictNext()
  1048. require.NoError(t, err)
  1049. require.Equal(t, a.NodeID, evict)
  1050. peerManager.Disconnected(ctx, a.NodeID)
  1051. // c still cannot get accepted, since it's not scored above b.
  1052. require.Error(t, peerManager.Accepted(c.NodeID))
  1053. }
  1054. func TestPeerManager_Accepted_UpgradeDialing(t *testing.T) {
  1055. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1056. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1057. c := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("c", 40))}
  1058. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1059. PeerScores: map[types.NodeID]p2p.PeerScore{
  1060. b.NodeID: 1,
  1061. c.NodeID: 1,
  1062. },
  1063. MaxConnected: 1,
  1064. MaxConnectedUpgrade: 2,
  1065. })
  1066. require.NoError(t, err)
  1067. // Accept a.
  1068. added, err := peerManager.Add(a)
  1069. require.NoError(t, err)
  1070. require.True(t, added)
  1071. require.NoError(t, peerManager.Accepted(a.NodeID))
  1072. // Start dial upgrade from a to b.
  1073. added, err = peerManager.Add(b)
  1074. require.NoError(t, err)
  1075. require.True(t, added)
  1076. dial, err := peerManager.TryDialNext()
  1077. require.NoError(t, err)
  1078. require.Equal(t, b, dial)
  1079. // a has already been claimed as an upgrade of a, so accepting
  1080. // c should fail since there's noone else to upgrade.
  1081. added, err = peerManager.Add(c)
  1082. require.NoError(t, err)
  1083. require.True(t, added)
  1084. require.Error(t, peerManager.Accepted(c.NodeID))
  1085. // However, if b connects to us while we're also trying to upgrade to it via
  1086. // dialing, then we accept the incoming connection as an upgrade.
  1087. require.NoError(t, peerManager.Accepted(b.NodeID))
  1088. // This should cause a to get evicted, and the dial upgrade to fail.
  1089. evict, err := peerManager.TryEvictNext()
  1090. require.NoError(t, err)
  1091. require.Equal(t, a.NodeID, evict)
  1092. require.Error(t, peerManager.Dialed(b))
  1093. }
  1094. func TestPeerManager_Ready(t *testing.T) {
  1095. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1096. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1097. ctx, cancel := context.WithCancel(context.Background())
  1098. defer cancel()
  1099. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1100. require.NoError(t, err)
  1101. sub := peerManager.Subscribe(ctx)
  1102. // Connecting to a should still have it as status down.
  1103. added, err := peerManager.Add(a)
  1104. require.NoError(t, err)
  1105. require.True(t, added)
  1106. require.NoError(t, peerManager.Accepted(a.NodeID))
  1107. require.Equal(t, p2p.PeerStatusDown, peerManager.Status(a.NodeID))
  1108. // Marking a as ready should transition it to PeerStatusUp and send an update.
  1109. peerManager.Ready(ctx, a.NodeID)
  1110. require.Equal(t, p2p.PeerStatusUp, peerManager.Status(a.NodeID))
  1111. require.Equal(t, p2p.PeerUpdate{
  1112. NodeID: a.NodeID,
  1113. Status: p2p.PeerStatusUp,
  1114. }, <-sub.Updates())
  1115. // Marking an unconnected peer as ready should do nothing.
  1116. added, err = peerManager.Add(b)
  1117. require.NoError(t, err)
  1118. require.True(t, added)
  1119. require.Equal(t, p2p.PeerStatusDown, peerManager.Status(b.NodeID))
  1120. peerManager.Ready(ctx, b.NodeID)
  1121. require.Equal(t, p2p.PeerStatusDown, peerManager.Status(b.NodeID))
  1122. require.Empty(t, sub.Updates())
  1123. }
  1124. // See TryEvictNext for most tests, this just tests blocking behavior.
  1125. func TestPeerManager_EvictNext(t *testing.T) {
  1126. ctx, cancel := context.WithCancel(context.Background())
  1127. defer cancel()
  1128. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1129. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1130. require.NoError(t, err)
  1131. added, err := peerManager.Add(a)
  1132. require.NoError(t, err)
  1133. require.True(t, added)
  1134. require.NoError(t, peerManager.Accepted(a.NodeID))
  1135. peerManager.Ready(ctx, a.NodeID)
  1136. // Since there are no peers to evict, EvictNext should block until timeout.
  1137. timeoutCtx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
  1138. defer cancel()
  1139. _, err = peerManager.EvictNext(timeoutCtx)
  1140. require.Error(t, err)
  1141. require.Equal(t, context.DeadlineExceeded, err)
  1142. // Erroring the peer will return it from EvictNext().
  1143. peerManager.Errored(a.NodeID, errors.New("foo"))
  1144. evict, err := peerManager.EvictNext(timeoutCtx)
  1145. require.NoError(t, err)
  1146. require.Equal(t, a.NodeID, evict)
  1147. // Since there are no more peers to evict, the next call should block.
  1148. timeoutCtx, cancel = context.WithTimeout(ctx, 100*time.Millisecond)
  1149. defer cancel()
  1150. _, err = peerManager.EvictNext(timeoutCtx)
  1151. require.Error(t, err)
  1152. require.Equal(t, context.DeadlineExceeded, err)
  1153. }
  1154. func TestPeerManager_EvictNext_WakeOnError(t *testing.T) {
  1155. ctx, cancel := context.WithCancel(context.Background())
  1156. defer cancel()
  1157. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1158. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1159. require.NoError(t, err)
  1160. added, err := peerManager.Add(a)
  1161. require.NoError(t, err)
  1162. require.True(t, added)
  1163. require.NoError(t, peerManager.Accepted(a.NodeID))
  1164. peerManager.Ready(ctx, a.NodeID)
  1165. // Spawn a goroutine to error a peer after a delay.
  1166. go func() {
  1167. time.Sleep(200 * time.Millisecond)
  1168. peerManager.Errored(a.NodeID, errors.New("foo"))
  1169. }()
  1170. // This will block until peer errors above.
  1171. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  1172. defer cancel()
  1173. evict, err := peerManager.EvictNext(ctx)
  1174. require.NoError(t, err)
  1175. require.Equal(t, a.NodeID, evict)
  1176. }
  1177. func TestPeerManager_EvictNext_WakeOnUpgradeDialed(t *testing.T) {
  1178. ctx, cancel := context.WithCancel(context.Background())
  1179. defer cancel()
  1180. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1181. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1182. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1183. MaxConnected: 1,
  1184. MaxConnectedUpgrade: 1,
  1185. PeerScores: map[types.NodeID]p2p.PeerScore{b.NodeID: 1},
  1186. })
  1187. require.NoError(t, err)
  1188. // Connect a.
  1189. added, err := peerManager.Add(a)
  1190. require.NoError(t, err)
  1191. require.True(t, added)
  1192. require.NoError(t, peerManager.Accepted(a.NodeID))
  1193. peerManager.Ready(ctx, a.NodeID)
  1194. // Spawn a goroutine to upgrade to b with a delay.
  1195. go func() {
  1196. time.Sleep(200 * time.Millisecond)
  1197. added, err := peerManager.Add(b)
  1198. require.NoError(t, err)
  1199. require.True(t, added)
  1200. dial, err := peerManager.TryDialNext()
  1201. require.NoError(t, err)
  1202. require.Equal(t, b, dial)
  1203. require.NoError(t, peerManager.Dialed(b))
  1204. }()
  1205. // This will block until peer is upgraded above.
  1206. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  1207. defer cancel()
  1208. evict, err := peerManager.EvictNext(ctx)
  1209. require.NoError(t, err)
  1210. require.Equal(t, a.NodeID, evict)
  1211. }
  1212. func TestPeerManager_EvictNext_WakeOnUpgradeAccepted(t *testing.T) {
  1213. ctx, cancel := context.WithCancel(context.Background())
  1214. defer cancel()
  1215. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1216. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1217. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1218. MaxConnected: 1,
  1219. MaxConnectedUpgrade: 1,
  1220. PeerScores: map[types.NodeID]p2p.PeerScore{b.NodeID: 1},
  1221. })
  1222. require.NoError(t, err)
  1223. // Connect a.
  1224. added, err := peerManager.Add(a)
  1225. require.NoError(t, err)
  1226. require.True(t, added)
  1227. require.NoError(t, peerManager.Accepted(a.NodeID))
  1228. peerManager.Ready(ctx, a.NodeID)
  1229. // Spawn a goroutine to upgrade b with a delay.
  1230. go func() {
  1231. time.Sleep(200 * time.Millisecond)
  1232. require.NoError(t, peerManager.Accepted(b.NodeID))
  1233. }()
  1234. // This will block until peer is upgraded above.
  1235. ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
  1236. defer cancel()
  1237. evict, err := peerManager.EvictNext(ctx)
  1238. require.NoError(t, err)
  1239. require.Equal(t, a.NodeID, evict)
  1240. }
  1241. func TestPeerManager_TryEvictNext(t *testing.T) {
  1242. ctx, cancel := context.WithCancel(context.Background())
  1243. defer cancel()
  1244. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1245. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1246. require.NoError(t, err)
  1247. added, err := peerManager.Add(a)
  1248. require.NoError(t, err)
  1249. require.True(t, added)
  1250. // Nothing is evicted with no peers connected.
  1251. evict, err := peerManager.TryEvictNext()
  1252. require.NoError(t, err)
  1253. require.Zero(t, evict)
  1254. // Connecting to a won't evict anything either.
  1255. require.NoError(t, peerManager.Accepted(a.NodeID))
  1256. peerManager.Ready(ctx, a.NodeID)
  1257. // But if a errors it should be evicted.
  1258. peerManager.Errored(a.NodeID, errors.New("foo"))
  1259. evict, err = peerManager.TryEvictNext()
  1260. require.NoError(t, err)
  1261. require.Equal(t, a.NodeID, evict)
  1262. // While a is being evicted (before disconnect), it shouldn't get evicted again.
  1263. evict, err = peerManager.TryEvictNext()
  1264. require.NoError(t, err)
  1265. require.Zero(t, evict)
  1266. peerManager.Errored(a.NodeID, errors.New("foo"))
  1267. evict, err = peerManager.TryEvictNext()
  1268. require.NoError(t, err)
  1269. require.Zero(t, evict)
  1270. }
  1271. func TestPeerManager_Disconnected(t *testing.T) {
  1272. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1273. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1274. require.NoError(t, err)
  1275. ctx, cancel := context.WithCancel(context.Background())
  1276. defer cancel()
  1277. sub := peerManager.Subscribe(ctx)
  1278. // Disconnecting an unknown peer does nothing.
  1279. peerManager.Disconnected(ctx, a.NodeID)
  1280. require.Empty(t, peerManager.Peers())
  1281. require.Empty(t, sub.Updates())
  1282. // Disconnecting an accepted non-ready peer does not send a status update.
  1283. added, err := peerManager.Add(a)
  1284. require.NoError(t, err)
  1285. require.True(t, added)
  1286. require.NoError(t, peerManager.Accepted(a.NodeID))
  1287. peerManager.Disconnected(ctx, a.NodeID)
  1288. require.Empty(t, sub.Updates())
  1289. // Disconnecting a ready peer sends a status update.
  1290. _, err = peerManager.Add(a)
  1291. require.NoError(t, err)
  1292. require.NoError(t, peerManager.Accepted(a.NodeID))
  1293. peerManager.Ready(ctx, a.NodeID)
  1294. require.Equal(t, p2p.PeerStatusUp, peerManager.Status(a.NodeID))
  1295. require.NotEmpty(t, sub.Updates())
  1296. require.Equal(t, p2p.PeerUpdate{
  1297. NodeID: a.NodeID,
  1298. Status: p2p.PeerStatusUp,
  1299. }, <-sub.Updates())
  1300. peerManager.Disconnected(ctx, a.NodeID)
  1301. require.Equal(t, p2p.PeerStatusDown, peerManager.Status(a.NodeID))
  1302. require.NotEmpty(t, sub.Updates())
  1303. require.Equal(t, p2p.PeerUpdate{
  1304. NodeID: a.NodeID,
  1305. Status: p2p.PeerStatusDown,
  1306. }, <-sub.Updates())
  1307. // Disconnecting a dialing peer does not unmark it as dialing, to avoid
  1308. // dialing it multiple times in parallel.
  1309. dial, err := peerManager.TryDialNext()
  1310. require.NoError(t, err)
  1311. require.Equal(t, a, dial)
  1312. peerManager.Disconnected(ctx, a.NodeID)
  1313. dial, err = peerManager.TryDialNext()
  1314. require.NoError(t, err)
  1315. require.Zero(t, dial)
  1316. }
  1317. func TestPeerManager_Errored(t *testing.T) {
  1318. ctx, cancel := context.WithCancel(context.Background())
  1319. defer cancel()
  1320. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1321. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1322. require.NoError(t, err)
  1323. // Erroring an unknown peer does nothing.
  1324. peerManager.Errored(a.NodeID, errors.New("foo"))
  1325. require.Empty(t, peerManager.Peers())
  1326. evict, err := peerManager.TryEvictNext()
  1327. require.NoError(t, err)
  1328. require.Zero(t, evict)
  1329. // Erroring a known peer does nothing, and won't evict it later,
  1330. // even when it connects.
  1331. added, err := peerManager.Add(a)
  1332. require.NoError(t, err)
  1333. require.True(t, added)
  1334. peerManager.Errored(a.NodeID, errors.New("foo"))
  1335. evict, err = peerManager.TryEvictNext()
  1336. require.NoError(t, err)
  1337. require.Zero(t, evict)
  1338. require.NoError(t, peerManager.Accepted(a.NodeID))
  1339. peerManager.Ready(ctx, a.NodeID)
  1340. evict, err = peerManager.TryEvictNext()
  1341. require.NoError(t, err)
  1342. require.Zero(t, evict)
  1343. // However, erroring once connected will evict it.
  1344. peerManager.Errored(a.NodeID, errors.New("foo"))
  1345. evict, err = peerManager.TryEvictNext()
  1346. require.NoError(t, err)
  1347. require.Equal(t, a.NodeID, evict)
  1348. }
  1349. func TestPeerManager_Subscribe(t *testing.T) {
  1350. ctx, cancel := context.WithCancel(context.Background())
  1351. defer cancel()
  1352. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1353. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1354. require.NoError(t, err)
  1355. // This tests all subscription events for full peer lifecycles.
  1356. sub := peerManager.Subscribe(ctx)
  1357. added, err := peerManager.Add(a)
  1358. require.NoError(t, err)
  1359. require.True(t, added)
  1360. require.Empty(t, sub.Updates())
  1361. // Inbound connection.
  1362. require.NoError(t, peerManager.Accepted(a.NodeID))
  1363. require.Empty(t, sub.Updates())
  1364. peerManager.Ready(ctx, a.NodeID)
  1365. require.NotEmpty(t, sub.Updates())
  1366. require.Equal(t, p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusUp}, <-sub.Updates())
  1367. peerManager.Disconnected(ctx, a.NodeID)
  1368. require.NotEmpty(t, sub.Updates())
  1369. require.Equal(t, p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusDown}, <-sub.Updates())
  1370. // Outbound connection with peer error and eviction.
  1371. dial, err := peerManager.TryDialNext()
  1372. require.NoError(t, err)
  1373. require.Equal(t, a, dial)
  1374. require.Empty(t, sub.Updates())
  1375. require.NoError(t, peerManager.Dialed(a))
  1376. require.Empty(t, sub.Updates())
  1377. peerManager.Ready(ctx, a.NodeID)
  1378. require.NotEmpty(t, sub.Updates())
  1379. require.Equal(t, p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusUp}, <-sub.Updates())
  1380. peerManager.Errored(a.NodeID, errors.New("foo"))
  1381. require.Empty(t, sub.Updates())
  1382. evict, err := peerManager.TryEvictNext()
  1383. require.NoError(t, err)
  1384. require.Equal(t, a.NodeID, evict)
  1385. peerManager.Disconnected(ctx, a.NodeID)
  1386. require.NotEmpty(t, sub.Updates())
  1387. require.Equal(t, p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusDown}, <-sub.Updates())
  1388. // Outbound connection with dial failure.
  1389. dial, err = peerManager.TryDialNext()
  1390. require.NoError(t, err)
  1391. require.Equal(t, a, dial)
  1392. require.Empty(t, sub.Updates())
  1393. require.NoError(t, peerManager.DialFailed(ctx, a))
  1394. require.Empty(t, sub.Updates())
  1395. }
  1396. func TestPeerManager_Subscribe_Close(t *testing.T) {
  1397. ctx, cancel := context.WithCancel(context.Background())
  1398. defer cancel()
  1399. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1400. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1401. require.NoError(t, err)
  1402. sub := peerManager.Subscribe(ctx)
  1403. added, err := peerManager.Add(a)
  1404. require.NoError(t, err)
  1405. require.True(t, added)
  1406. require.NoError(t, peerManager.Accepted(a.NodeID))
  1407. require.Empty(t, sub.Updates())
  1408. peerManager.Ready(ctx, a.NodeID)
  1409. require.NotEmpty(t, sub.Updates())
  1410. require.Equal(t, p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusUp}, <-sub.Updates())
  1411. // Closing the subscription should not send us the disconnected update.
  1412. cancel()
  1413. peerManager.Disconnected(ctx, a.NodeID)
  1414. require.Empty(t, sub.Updates())
  1415. }
  1416. func TestPeerManager_Subscribe_Broadcast(t *testing.T) {
  1417. ctx, cancel := context.WithCancel(context.Background())
  1418. defer cancel()
  1419. t.Cleanup(leaktest.Check(t))
  1420. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1421. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
  1422. require.NoError(t, err)
  1423. s2ctx, s2cancel := context.WithCancel(ctx)
  1424. defer s2cancel()
  1425. s1 := peerManager.Subscribe(ctx)
  1426. s2 := peerManager.Subscribe(s2ctx)
  1427. s3 := peerManager.Subscribe(ctx)
  1428. // Connecting to a peer should send updates on all subscriptions.
  1429. added, err := peerManager.Add(a)
  1430. require.NoError(t, err)
  1431. require.True(t, added)
  1432. require.NoError(t, peerManager.Accepted(a.NodeID))
  1433. peerManager.Ready(ctx, a.NodeID)
  1434. expectUp := p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusUp}
  1435. require.NotEmpty(t, s1)
  1436. require.Equal(t, expectUp, <-s1.Updates())
  1437. require.NotEmpty(t, s2)
  1438. require.Equal(t, expectUp, <-s2.Updates())
  1439. require.NotEmpty(t, s3)
  1440. require.Equal(t, expectUp, <-s3.Updates())
  1441. // We now close s2. Disconnecting the peer should only send updates
  1442. // on s1 and s3.
  1443. s2cancel()
  1444. time.Sleep(250 * time.Millisecond) // give the thread a chance to exit
  1445. peerManager.Disconnected(ctx, a.NodeID)
  1446. expectDown := p2p.PeerUpdate{NodeID: a.NodeID, Status: p2p.PeerStatusDown}
  1447. require.NotEmpty(t, s1)
  1448. require.Equal(t, expectDown, <-s1.Updates())
  1449. require.Empty(t, s2.Updates())
  1450. require.NotEmpty(t, s3)
  1451. require.Equal(t, expectDown, <-s3.Updates())
  1452. }
  1453. func TestPeerManager_Close(t *testing.T) {
  1454. // leaktest will check that spawned goroutines are closed.
  1455. t.Cleanup(leaktest.CheckTimeout(t, 1*time.Second))
  1456. ctx, cancel := context.WithCancel(context.Background())
  1457. defer cancel()
  1458. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1459. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1460. MinRetryTime: 10 * time.Second,
  1461. })
  1462. require.NoError(t, err)
  1463. // This subscription isn't closed, but PeerManager.Close()
  1464. // should reap the spawned goroutine.
  1465. _ = peerManager.Subscribe(ctx)
  1466. // This dial failure will start a retry timer for 10 seconds, which
  1467. // should be reaped.
  1468. added, err := peerManager.Add(a)
  1469. require.NoError(t, err)
  1470. require.True(t, added)
  1471. dial, err := peerManager.TryDialNext()
  1472. require.NoError(t, err)
  1473. require.Equal(t, a, dial)
  1474. require.NoError(t, peerManager.DialFailed(ctx, a))
  1475. }
  1476. func TestPeerManager_Advertise(t *testing.T) {
  1477. aID := types.NodeID(strings.Repeat("a", 40))
  1478. aTCP := p2p.NodeAddress{Protocol: "tcp", NodeID: aID, Hostname: "127.0.0.1", Port: 26657, Path: "/path"}
  1479. aMem := p2p.NodeAddress{Protocol: "memory", NodeID: aID}
  1480. bID := types.NodeID(strings.Repeat("b", 40))
  1481. bTCP := p2p.NodeAddress{Protocol: "tcp", NodeID: bID, Hostname: "b10c::1", Port: 26657, Path: "/path"}
  1482. bMem := p2p.NodeAddress{Protocol: "memory", NodeID: bID}
  1483. cID := types.NodeID(strings.Repeat("c", 40))
  1484. cTCP := p2p.NodeAddress{Protocol: "tcp", NodeID: cID, Hostname: "host.domain", Port: 80}
  1485. cMem := p2p.NodeAddress{Protocol: "memory", NodeID: cID}
  1486. dID := types.NodeID(strings.Repeat("d", 40))
  1487. // Create an initial peer manager and add the peers.
  1488. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1489. PeerScores: map[types.NodeID]p2p.PeerScore{aID: 3, bID: 2, cID: 1},
  1490. })
  1491. require.NoError(t, err)
  1492. added, err := peerManager.Add(aTCP)
  1493. require.NoError(t, err)
  1494. require.True(t, added)
  1495. added, err = peerManager.Add(aMem)
  1496. require.NoError(t, err)
  1497. require.True(t, added)
  1498. added, err = peerManager.Add(bTCP)
  1499. require.NoError(t, err)
  1500. require.True(t, added)
  1501. added, err = peerManager.Add(bMem)
  1502. require.NoError(t, err)
  1503. require.True(t, added)
  1504. added, err = peerManager.Add(cTCP)
  1505. require.NoError(t, err)
  1506. require.True(t, added)
  1507. added, err = peerManager.Add(cMem)
  1508. require.NoError(t, err)
  1509. require.True(t, added)
  1510. // d should get all addresses.
  1511. require.ElementsMatch(t, []p2p.NodeAddress{
  1512. aTCP, aMem, bTCP, bMem, cTCP, cMem,
  1513. }, peerManager.Advertise(dID, 100))
  1514. // a should not get its own addresses.
  1515. require.ElementsMatch(t, []p2p.NodeAddress{
  1516. bTCP, bMem, cTCP, cMem,
  1517. }, peerManager.Advertise(aID, 100))
  1518. // Asking for 0 addresses should return, well, 0.
  1519. require.Empty(t, peerManager.Advertise(aID, 0))
  1520. // Asking for 2 addresses should get the highest-rated ones, i.e. a.
  1521. require.ElementsMatch(t, []p2p.NodeAddress{
  1522. aTCP, aMem,
  1523. }, peerManager.Advertise(dID, 2))
  1524. }
  1525. func TestPeerManager_Advertise_Self(t *testing.T) {
  1526. dID := types.NodeID(strings.Repeat("d", 40))
  1527. self := p2p.NodeAddress{Protocol: "tcp", NodeID: selfID, Hostname: "2001:db8::1", Port: 26657}
  1528. // Create a peer manager with SelfAddress defined.
  1529. peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
  1530. SelfAddress: self,
  1531. })
  1532. require.NoError(t, err)
  1533. // peer manager should always advertise its SelfAddress.
  1534. require.ElementsMatch(t, []p2p.NodeAddress{
  1535. self,
  1536. }, peerManager.Advertise(dID, 100))
  1537. }
  1538. func TestPeerManager_SetHeight_GetHeight(t *testing.T) {
  1539. a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
  1540. b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
  1541. db := dbm.NewMemDB()
  1542. peerManager, err := p2p.NewPeerManager(selfID, db, p2p.PeerManagerOptions{})
  1543. require.NoError(t, err)
  1544. // Getting a height should default to 0, for unknown peers and
  1545. // for known peers without height.
  1546. added, err := peerManager.Add(a)
  1547. require.NoError(t, err)
  1548. require.True(t, added)
  1549. require.EqualValues(t, 0, peerManager.GetHeight(a.NodeID))
  1550. require.EqualValues(t, 0, peerManager.GetHeight(b.NodeID))
  1551. // Setting a height should work for a known node.
  1552. require.NoError(t, peerManager.SetHeight(a.NodeID, 3))
  1553. require.EqualValues(t, 3, peerManager.GetHeight(a.NodeID))
  1554. // Setting a height should add an unknown node.
  1555. require.Equal(t, []types.NodeID{a.NodeID}, peerManager.Peers())
  1556. require.NoError(t, peerManager.SetHeight(b.NodeID, 7))
  1557. require.EqualValues(t, 7, peerManager.GetHeight(b.NodeID))
  1558. require.ElementsMatch(t, []types.NodeID{a.NodeID, b.NodeID}, peerManager.Peers())
  1559. // The heights should not be persisted.
  1560. peerManager, err = p2p.NewPeerManager(selfID, db, p2p.PeerManagerOptions{})
  1561. require.NoError(t, err)
  1562. require.ElementsMatch(t, []types.NodeID{a.NodeID, b.NodeID}, peerManager.Peers())
  1563. require.Zero(t, peerManager.GetHeight(a.NodeID))
  1564. require.Zero(t, peerManager.GetHeight(b.NodeID))
  1565. }