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.

456 lines
12 KiB

  1. package pex
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net"
  6. "os"
  7. "path/filepath"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. crypto "github.com/tendermint/tendermint/crypto"
  13. cmn "github.com/tendermint/tendermint/libs/common"
  14. "github.com/tendermint/tendermint/libs/log"
  15. "github.com/tendermint/tendermint/config"
  16. "github.com/tendermint/tendermint/p2p"
  17. "github.com/tendermint/tendermint/p2p/conn"
  18. )
  19. var (
  20. cfg *config.P2PConfig
  21. )
  22. func init() {
  23. cfg = config.DefaultP2PConfig()
  24. cfg.PexReactor = true
  25. cfg.AllowDuplicateIP = true
  26. }
  27. func TestPEXReactorBasic(t *testing.T) {
  28. r, book := createReactor(&PEXReactorConfig{})
  29. defer teardownReactor(book)
  30. assert.NotNil(t, r)
  31. assert.NotEmpty(t, r.GetChannels())
  32. }
  33. func TestPEXReactorAddRemovePeer(t *testing.T) {
  34. r, book := createReactor(&PEXReactorConfig{})
  35. defer teardownReactor(book)
  36. size := book.Size()
  37. peer := p2p.CreateRandomPeer(false)
  38. r.AddPeer(peer)
  39. assert.Equal(t, size+1, book.Size())
  40. r.RemovePeer(peer, "peer not available")
  41. outboundPeer := p2p.CreateRandomPeer(true)
  42. r.AddPeer(outboundPeer)
  43. assert.Equal(t, size+1, book.Size(), "outbound peers should not be added to the address book")
  44. r.RemovePeer(outboundPeer, "peer not available")
  45. }
  46. // --- FAIL: TestPEXReactorRunning (11.10s)
  47. // pex_reactor_test.go:411: expected all switches to be connected to at
  48. // least one peer (switches: 0 => {outbound: 1, inbound: 0}, 1 =>
  49. // {outbound: 0, inbound: 1}, 2 => {outbound: 0, inbound: 0}, )
  50. //
  51. // EXPLANATION: peers are getting rejected because in switch#addPeer we check
  52. // if any peer (who we already connected to) has the same IP. Even though local
  53. // peers have different IP addresses, they all have the same underlying remote
  54. // IP: 127.0.0.1.
  55. //
  56. func TestPEXReactorRunning(t *testing.T) {
  57. N := 3
  58. switches := make([]*p2p.Switch, N)
  59. // directory to store address books
  60. dir, err := ioutil.TempDir("", "pex_reactor")
  61. require.Nil(t, err)
  62. defer os.RemoveAll(dir) // nolint: errcheck
  63. books := make([]*addrBook, N)
  64. logger := log.TestingLogger()
  65. // create switches
  66. for i := 0; i < N; i++ {
  67. switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
  68. books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
  69. books[i].SetLogger(logger.With("pex", i))
  70. sw.SetAddrBook(books[i])
  71. sw.SetLogger(logger.With("pex", i))
  72. r := NewPEXReactor(books[i], &PEXReactorConfig{})
  73. r.SetLogger(logger.With("pex", i))
  74. r.SetEnsurePeersPeriod(250 * time.Millisecond)
  75. sw.AddReactor("pex", r)
  76. return sw
  77. })
  78. }
  79. addOtherNodeAddrToAddrBook := func(switchIndex, otherSwitchIndex int) {
  80. addr := switches[otherSwitchIndex].NodeInfo().NetAddress()
  81. books[switchIndex].AddAddress(addr, addr)
  82. }
  83. addOtherNodeAddrToAddrBook(0, 1)
  84. addOtherNodeAddrToAddrBook(1, 0)
  85. addOtherNodeAddrToAddrBook(2, 1)
  86. for i, sw := range switches {
  87. sw.AddListener(p2p.NewDefaultListener("tcp://"+sw.NodeInfo().ListenAddr, "", false, logger.With("pex", i)))
  88. err := sw.Start() // start switch and reactors
  89. require.Nil(t, err)
  90. }
  91. assertPeersWithTimeout(t, switches, 10*time.Millisecond, 10*time.Second, N-1)
  92. // stop them
  93. for _, s := range switches {
  94. s.Stop()
  95. }
  96. }
  97. func TestPEXReactorReceive(t *testing.T) {
  98. r, book := createReactor(&PEXReactorConfig{})
  99. defer teardownReactor(book)
  100. peer := p2p.CreateRandomPeer(false)
  101. // we have to send a request to receive responses
  102. r.RequestAddrs(peer)
  103. size := book.Size()
  104. addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
  105. msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
  106. r.Receive(PexChannel, peer, msg)
  107. assert.Equal(t, size+1, book.Size())
  108. msg = cdc.MustMarshalBinaryBare(&pexRequestMessage{})
  109. r.Receive(PexChannel, peer, msg) // should not panic.
  110. }
  111. func TestPEXReactorRequestMessageAbuse(t *testing.T) {
  112. r, book := createReactor(&PEXReactorConfig{})
  113. defer teardownReactor(book)
  114. sw := createSwitchAndAddReactors(r)
  115. sw.SetAddrBook(book)
  116. peer := newMockPeer()
  117. p2p.AddPeerToSwitch(sw, peer)
  118. assert.True(t, sw.Peers().Has(peer.ID()))
  119. id := string(peer.ID())
  120. msg := cdc.MustMarshalBinaryBare(&pexRequestMessage{})
  121. // first time creates the entry
  122. r.Receive(PexChannel, peer, msg)
  123. assert.True(t, r.lastReceivedRequests.Has(id))
  124. assert.True(t, sw.Peers().Has(peer.ID()))
  125. // next time sets the last time value
  126. r.Receive(PexChannel, peer, msg)
  127. assert.True(t, r.lastReceivedRequests.Has(id))
  128. assert.True(t, sw.Peers().Has(peer.ID()))
  129. // third time is too many too soon - peer is removed
  130. r.Receive(PexChannel, peer, msg)
  131. assert.False(t, r.lastReceivedRequests.Has(id))
  132. assert.False(t, sw.Peers().Has(peer.ID()))
  133. }
  134. func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
  135. r, book := createReactor(&PEXReactorConfig{})
  136. defer teardownReactor(book)
  137. sw := createSwitchAndAddReactors(r)
  138. sw.SetAddrBook(book)
  139. peer := newMockPeer()
  140. p2p.AddPeerToSwitch(sw, peer)
  141. assert.True(t, sw.Peers().Has(peer.ID()))
  142. id := string(peer.ID())
  143. // request addrs from the peer
  144. r.RequestAddrs(peer)
  145. assert.True(t, r.requestsSent.Has(id))
  146. assert.True(t, sw.Peers().Has(peer.ID()))
  147. addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
  148. msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
  149. // receive some addrs. should clear the request
  150. r.Receive(PexChannel, peer, msg)
  151. assert.False(t, r.requestsSent.Has(id))
  152. assert.True(t, sw.Peers().Has(peer.ID()))
  153. // receiving more addrs causes a disconnect
  154. r.Receive(PexChannel, peer, msg)
  155. assert.False(t, sw.Peers().Has(peer.ID()))
  156. }
  157. func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
  158. // directory to store address books
  159. dir, err := ioutil.TempDir("", "pex_reactor")
  160. require.Nil(t, err)
  161. defer os.RemoveAll(dir) // nolint: errcheck
  162. // 1. create seed
  163. seed := p2p.MakeSwitch(
  164. cfg,
  165. 0,
  166. "127.0.0.1",
  167. "123.123.123",
  168. func(i int, sw *p2p.Switch) *p2p.Switch {
  169. book := NewAddrBook(filepath.Join(dir, "addrbook0.json"), false)
  170. book.SetLogger(log.TestingLogger())
  171. sw.SetAddrBook(book)
  172. sw.SetLogger(log.TestingLogger())
  173. r := NewPEXReactor(book, &PEXReactorConfig{})
  174. r.SetLogger(log.TestingLogger())
  175. sw.AddReactor("pex", r)
  176. return sw
  177. },
  178. )
  179. seed.AddListener(
  180. p2p.NewDefaultListener("tcp://"+seed.NodeInfo().ListenAddr, "", false, log.TestingLogger()),
  181. )
  182. require.Nil(t, seed.Start())
  183. defer seed.Stop()
  184. // 2. create usual peer with only seed configured.
  185. peer := p2p.MakeSwitch(
  186. cfg,
  187. 1,
  188. "127.0.0.1",
  189. "123.123.123",
  190. func(i int, sw *p2p.Switch) *p2p.Switch {
  191. book := NewAddrBook(filepath.Join(dir, "addrbook1.json"), false)
  192. book.SetLogger(log.TestingLogger())
  193. sw.SetAddrBook(book)
  194. sw.SetLogger(log.TestingLogger())
  195. r := NewPEXReactor(
  196. book,
  197. &PEXReactorConfig{
  198. Seeds: []string{seed.NodeInfo().NetAddress().String()},
  199. },
  200. )
  201. r.SetLogger(log.TestingLogger())
  202. sw.AddReactor("pex", r)
  203. return sw
  204. },
  205. )
  206. require.Nil(t, peer.Start())
  207. defer peer.Stop()
  208. // 3. check that the peer connects to seed immediately
  209. assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 3*time.Second, 1)
  210. }
  211. func TestPEXReactorCrawlStatus(t *testing.T) {
  212. pexR, book := createReactor(&PEXReactorConfig{SeedMode: true})
  213. defer teardownReactor(book)
  214. // Seed/Crawler mode uses data from the Switch
  215. sw := createSwitchAndAddReactors(pexR)
  216. sw.SetAddrBook(book)
  217. // Create a peer, add it to the peer set and the addrbook.
  218. peer := p2p.CreateRandomPeer(false)
  219. p2p.AddPeerToSwitch(pexR.Switch, peer)
  220. addr1 := peer.NodeInfo().NetAddress()
  221. pexR.book.AddAddress(addr1, addr1)
  222. // Add a non-connected address to the book.
  223. _, addr2 := p2p.CreateRoutableAddr()
  224. pexR.book.AddAddress(addr2, addr1)
  225. // Get some peerInfos to crawl
  226. peerInfos := pexR.getPeersToCrawl()
  227. // Make sure it has the proper number of elements
  228. assert.Equal(t, 2, len(peerInfos))
  229. // TODO: test
  230. }
  231. func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
  232. peer := p2p.CreateRandomPeer(false)
  233. pexR, book := createReactor(&PEXReactorConfig{})
  234. book.AddPrivateIDs([]string{string(peer.NodeInfo().ID)})
  235. defer teardownReactor(book)
  236. // we have to send a request to receive responses
  237. pexR.RequestAddrs(peer)
  238. size := book.Size()
  239. addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
  240. msg := cdc.MustMarshalBinaryBare(&pexAddrsMessage{Addrs: addrs})
  241. pexR.Receive(PexChannel, peer, msg)
  242. assert.Equal(t, size, book.Size())
  243. pexR.AddPeer(peer)
  244. assert.Equal(t, size, book.Size())
  245. }
  246. func TestPEXReactorDialPeer(t *testing.T) {
  247. pexR, book := createReactor(&PEXReactorConfig{})
  248. defer teardownReactor(book)
  249. sw := createSwitchAndAddReactors(pexR)
  250. sw.SetAddrBook(book)
  251. peer := newMockPeer()
  252. addr := peer.NodeInfo().NetAddress()
  253. assert.Equal(t, 0, pexR.AttemptsToDial(addr))
  254. // 1st unsuccessful attempt
  255. pexR.dialPeer(addr)
  256. assert.Equal(t, 1, pexR.AttemptsToDial(addr))
  257. // 2nd unsuccessful attempt
  258. pexR.dialPeer(addr)
  259. // must be skipped because it is too early
  260. assert.Equal(t, 1, pexR.AttemptsToDial(addr))
  261. if !testing.Short() {
  262. time.Sleep(3 * time.Second)
  263. // 3rd attempt
  264. pexR.dialPeer(addr)
  265. assert.Equal(t, 2, pexR.AttemptsToDial(addr))
  266. }
  267. }
  268. type mockPeer struct {
  269. *cmn.BaseService
  270. pubKey crypto.PubKey
  271. addr *p2p.NetAddress
  272. outbound, persistent bool
  273. }
  274. func newMockPeer() mockPeer {
  275. _, netAddr := p2p.CreateRoutableAddr()
  276. mp := mockPeer{
  277. addr: netAddr,
  278. pubKey: crypto.GenPrivKeyEd25519().PubKey(),
  279. }
  280. mp.BaseService = cmn.NewBaseService(nil, "MockPeer", mp)
  281. mp.Start()
  282. return mp
  283. }
  284. func (mp mockPeer) ID() p2p.ID { return mp.addr.ID }
  285. func (mp mockPeer) IsOutbound() bool { return mp.outbound }
  286. func (mp mockPeer) IsPersistent() bool { return mp.persistent }
  287. func (mp mockPeer) NodeInfo() p2p.NodeInfo {
  288. return p2p.NodeInfo{
  289. ID: mp.addr.ID,
  290. ListenAddr: mp.addr.DialString(),
  291. }
  292. }
  293. func (mockPeer) RemoteIP() net.IP { return net.ParseIP("127.0.0.1") }
  294. func (mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
  295. func (mockPeer) Send(byte, []byte) bool { return false }
  296. func (mockPeer) TrySend(byte, []byte) bool { return false }
  297. func (mockPeer) Set(string, interface{}) {}
  298. func (mockPeer) Get(string) interface{} { return nil }
  299. func (mockPeer) OriginalAddr() *p2p.NetAddress { return nil }
  300. func assertPeersWithTimeout(
  301. t *testing.T,
  302. switches []*p2p.Switch,
  303. checkPeriod, timeout time.Duration,
  304. nPeers int,
  305. ) {
  306. var (
  307. ticker = time.NewTicker(checkPeriod)
  308. remaining = timeout
  309. )
  310. for {
  311. select {
  312. case <-ticker.C:
  313. // check peers are connected
  314. allGood := true
  315. for _, s := range switches {
  316. outbound, inbound, _ := s.NumPeers()
  317. if outbound+inbound < nPeers {
  318. allGood = false
  319. }
  320. }
  321. remaining -= checkPeriod
  322. if remaining < 0 {
  323. remaining = 0
  324. }
  325. if allGood {
  326. return
  327. }
  328. case <-time.After(remaining):
  329. numPeersStr := ""
  330. for i, s := range switches {
  331. outbound, inbound, _ := s.NumPeers()
  332. numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
  333. }
  334. t.Errorf(
  335. "expected all switches to be connected to at least one peer (switches: %s)",
  336. numPeersStr,
  337. )
  338. return
  339. }
  340. }
  341. }
  342. func createReactor(conf *PEXReactorConfig) (r *PEXReactor, book *addrBook) {
  343. // directory to store address book
  344. dir, err := ioutil.TempDir("", "pex_reactor")
  345. if err != nil {
  346. panic(err)
  347. }
  348. book = NewAddrBook(filepath.Join(dir, "addrbook.json"), true)
  349. book.SetLogger(log.TestingLogger())
  350. r = NewPEXReactor(book, conf)
  351. r.SetLogger(log.TestingLogger())
  352. return
  353. }
  354. func teardownReactor(book *addrBook) {
  355. err := os.RemoveAll(filepath.Dir(book.FilePath()))
  356. if err != nil {
  357. panic(err)
  358. }
  359. }
  360. func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch {
  361. sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
  362. sw.SetLogger(log.TestingLogger())
  363. for _, r := range reactors {
  364. sw.AddReactor(r.String(), r)
  365. r.SetSwitch(sw)
  366. }
  367. return sw
  368. }