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.

1905 lines
62 KiB

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