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.

402 lines
10 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
p2p: introduce peerConn to simplify peer creation (#1226) * expose AuthEnc in the P2P config if AuthEnc is true, dialed peers must have a node ID in the address and it must match the persistent pubkey from the secret handshake. Refs #1157 * fixes after my own review * fix docs * fix build failure ``` p2p/pex/pex_reactor_test.go:288:88: cannot use seed.NodeInfo().NetAddress() (type *p2p.NetAddress) as type string in array or slice literal ``` * p2p: introduce peerConn to simplify peer creation * Introduce `peerConn` containing the known fields of `peer` * `peer` only created in `sw.addPeer` once handshake is complete and NodeInfo is checked * Eliminates some mutable variables and makes the code flow better * Simplifies the `newXxxPeer` funcs * Use ID instead of PubKey where possible. * SetPubKeyFilter -> SetIDFilter * nodeInfo.Validate takes ID * remove peer.PubKey() * persistent node ids * fixes from review * test: use ip_plus_id.sh more * fix invalid memory panic during fast_sync test ``` 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: panic: runtime error: invalid memory address or nil pointer dereference 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x98dd3e] 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: goroutine 3432 [running]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.newOutboundPeerConn(0xc423fd1380, 0xc420933e00, 0x1, 0x1239a60, 0 xc420128c40, 0x2, 0x42caf6, 0xc42001f300, 0xc422831d98, 0xc4227951c0, ...) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/peer.go:123 +0x31e 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).addOutboundPeerWithConfig(0xc4200ad040, 0xc423fd1380, 0 xc420933e00, 0xc423f48801, 0x28, 0x2) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:455 +0x12b 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).DialPeerWithAddress(0xc4200ad040, 0xc423fd1380, 0x1, 0x 0, 0x0) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:371 +0xdc 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).reconnectToPeer(0xc4200ad040, 0x123e000, 0xc42007bb00) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:290 +0x25f 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: created by github.com/tendermint/tendermint/p2p.(*Switch).StopPeerForError 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:256 +0x1b7 ```
7 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package pex
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. crypto "github.com/tendermint/go-crypto"
  11. wire "github.com/tendermint/go-wire"
  12. cmn "github.com/tendermint/tmlibs/common"
  13. "github.com/tendermint/tmlibs/log"
  14. cfg "github.com/tendermint/tendermint/config"
  15. "github.com/tendermint/tendermint/p2p"
  16. "github.com/tendermint/tendermint/p2p/conn"
  17. )
  18. var (
  19. config *cfg.P2PConfig
  20. )
  21. func init() {
  22. config = cfg.DefaultP2PConfig()
  23. config.PexReactor = true
  24. }
  25. func TestPEXReactorBasic(t *testing.T) {
  26. assert, require := assert.New(t), require.New(t)
  27. dir, err := ioutil.TempDir("", "pex_reactor")
  28. require.Nil(err)
  29. defer os.RemoveAll(dir) // nolint: errcheck
  30. book := NewAddrBook(dir+"addrbook.json", true)
  31. book.SetLogger(log.TestingLogger())
  32. r := NewPEXReactor(book, &PEXReactorConfig{})
  33. r.SetLogger(log.TestingLogger())
  34. assert.NotNil(r)
  35. assert.NotEmpty(r.GetChannels())
  36. }
  37. func TestPEXReactorAddRemovePeer(t *testing.T) {
  38. assert, require := assert.New(t), require.New(t)
  39. dir, err := ioutil.TempDir("", "pex_reactor")
  40. require.Nil(err)
  41. defer os.RemoveAll(dir) // nolint: errcheck
  42. book := NewAddrBook(dir+"addrbook.json", true)
  43. book.SetLogger(log.TestingLogger())
  44. r := NewPEXReactor(book, &PEXReactorConfig{})
  45. r.SetLogger(log.TestingLogger())
  46. size := book.Size()
  47. peer := p2p.CreateRandomPeer(false)
  48. r.AddPeer(peer)
  49. assert.Equal(size+1, book.Size())
  50. r.RemovePeer(peer, "peer not available")
  51. assert.Equal(size+1, book.Size())
  52. outboundPeer := p2p.CreateRandomPeer(true)
  53. r.AddPeer(outboundPeer)
  54. assert.Equal(size+1, book.Size(), "outbound peers should not be added to the address book")
  55. r.RemovePeer(outboundPeer, "peer not available")
  56. assert.Equal(size+1, book.Size())
  57. }
  58. func TestPEXReactorRunning(t *testing.T) {
  59. N := 3
  60. switches := make([]*p2p.Switch, N)
  61. dir, err := ioutil.TempDir("", "pex_reactor")
  62. require.Nil(t, err)
  63. defer os.RemoveAll(dir) // nolint: errcheck
  64. book := NewAddrBook(dir+"addrbook.json", false)
  65. book.SetLogger(log.TestingLogger())
  66. // create switches
  67. for i := 0; i < N; i++ {
  68. switches[i] = p2p.MakeSwitch(config, i, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
  69. sw.SetLogger(log.TestingLogger().With("switch", i))
  70. r := NewPEXReactor(book, &PEXReactorConfig{})
  71. r.SetLogger(log.TestingLogger())
  72. r.SetEnsurePeersPeriod(250 * time.Millisecond)
  73. sw.AddReactor("pex", r)
  74. return sw
  75. })
  76. }
  77. // fill the address book and add listeners
  78. for _, s := range switches {
  79. addr := s.NodeInfo().NetAddress()
  80. book.AddAddress(addr, addr)
  81. s.AddListener(p2p.NewDefaultListener("tcp", s.NodeInfo().ListenAddr, true, log.TestingLogger()))
  82. }
  83. // start switches
  84. for _, s := range switches {
  85. err := s.Start() // start switch and reactors
  86. require.Nil(t, err)
  87. }
  88. assertPeersWithTimeout(t, switches, 10*time.Millisecond, 10*time.Second, N-1)
  89. // stop them
  90. for _, s := range switches {
  91. s.Stop()
  92. }
  93. }
  94. func TestPEXReactorReceive(t *testing.T) {
  95. assert, require := assert.New(t), require.New(t)
  96. dir, err := ioutil.TempDir("", "pex_reactor")
  97. require.Nil(err)
  98. defer os.RemoveAll(dir) // nolint: errcheck
  99. book := NewAddrBook(dir+"addrbook.json", false)
  100. book.SetLogger(log.TestingLogger())
  101. r := NewPEXReactor(book, &PEXReactorConfig{})
  102. r.SetLogger(log.TestingLogger())
  103. peer := p2p.CreateRandomPeer(false)
  104. // we have to send a request to receive responses
  105. r.RequestAddrs(peer)
  106. size := book.Size()
  107. addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
  108. msg := wire.BinaryBytes(struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}})
  109. r.Receive(PexChannel, peer, msg)
  110. assert.Equal(size+1, book.Size())
  111. msg = wire.BinaryBytes(struct{ PexMessage }{&pexRequestMessage{}})
  112. r.Receive(PexChannel, peer, msg)
  113. }
  114. func TestPEXReactorRequestMessageAbuse(t *testing.T) {
  115. assert, require := assert.New(t), require.New(t)
  116. dir, err := ioutil.TempDir("", "pex_reactor")
  117. require.Nil(err)
  118. defer os.RemoveAll(dir) // nolint: errcheck
  119. book := NewAddrBook(dir+"addrbook.json", true)
  120. book.SetLogger(log.TestingLogger())
  121. r := NewPEXReactor(book, &PEXReactorConfig{})
  122. sw := p2p.MakeSwitch(config, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
  123. sw.SetLogger(log.TestingLogger())
  124. sw.AddReactor("PEX", r)
  125. r.SetSwitch(sw)
  126. r.SetLogger(log.TestingLogger())
  127. peer := newMockPeer()
  128. p2p.AddPeerToSwitch(sw, peer)
  129. assert.True(sw.Peers().Has(peer.ID()))
  130. id := string(peer.ID())
  131. msg := wire.BinaryBytes(struct{ PexMessage }{&pexRequestMessage{}})
  132. // first time creates the entry
  133. r.Receive(PexChannel, peer, msg)
  134. assert.True(r.lastReceivedRequests.Has(id))
  135. assert.True(sw.Peers().Has(peer.ID()))
  136. // next time sets the last time value
  137. r.Receive(PexChannel, peer, msg)
  138. assert.True(r.lastReceivedRequests.Has(id))
  139. assert.True(sw.Peers().Has(peer.ID()))
  140. // third time is too many too soon - peer is removed
  141. r.Receive(PexChannel, peer, msg)
  142. assert.False(r.lastReceivedRequests.Has(id))
  143. assert.False(sw.Peers().Has(peer.ID()))
  144. }
  145. func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
  146. assert, require := assert.New(t), require.New(t)
  147. dir, err := ioutil.TempDir("", "pex_reactor")
  148. require.Nil(err)
  149. defer os.RemoveAll(dir) // nolint: errcheck
  150. book := NewAddrBook(dir+"addrbook.json", true)
  151. book.SetLogger(log.TestingLogger())
  152. r := NewPEXReactor(book, &PEXReactorConfig{})
  153. sw := p2p.MakeSwitch(config, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
  154. sw.SetLogger(log.TestingLogger())
  155. sw.AddReactor("PEX", r)
  156. r.SetSwitch(sw)
  157. r.SetLogger(log.TestingLogger())
  158. peer := newMockPeer()
  159. p2p.AddPeerToSwitch(sw, peer)
  160. assert.True(sw.Peers().Has(peer.ID()))
  161. id := string(peer.ID())
  162. // request addrs from the peer
  163. r.RequestAddrs(peer)
  164. assert.True(r.requestsSent.Has(id))
  165. assert.True(sw.Peers().Has(peer.ID()))
  166. addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
  167. msg := wire.BinaryBytes(struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}})
  168. // receive some addrs. should clear the request
  169. r.Receive(PexChannel, peer, msg)
  170. assert.False(r.requestsSent.Has(id))
  171. assert.True(sw.Peers().Has(peer.ID()))
  172. // receiving more addrs causes a disconnect
  173. r.Receive(PexChannel, peer, msg)
  174. assert.False(sw.Peers().Has(peer.ID()))
  175. }
  176. func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
  177. dir, err := ioutil.TempDir("", "pex_reactor")
  178. require.Nil(t, err)
  179. defer os.RemoveAll(dir) // nolint: errcheck
  180. book := NewAddrBook(dir+"addrbook.json", false)
  181. book.SetLogger(log.TestingLogger())
  182. // 1. create seed
  183. seed := p2p.MakeSwitch(
  184. config,
  185. 0,
  186. "127.0.0.1",
  187. "123.123.123",
  188. func(i int, sw *p2p.Switch) *p2p.Switch {
  189. sw.SetLogger(log.TestingLogger())
  190. r := NewPEXReactor(book, &PEXReactorConfig{})
  191. r.SetLogger(log.TestingLogger())
  192. sw.AddReactor("pex", r)
  193. return sw
  194. },
  195. )
  196. seed.AddListener(
  197. p2p.NewDefaultListener(
  198. "tcp",
  199. seed.NodeInfo().ListenAddr,
  200. true,
  201. log.TestingLogger(),
  202. ),
  203. )
  204. require.Nil(t, seed.Start())
  205. defer seed.Stop()
  206. // 2. create usual peer with only seed configured.
  207. peer := p2p.MakeSwitch(
  208. config,
  209. 1,
  210. "127.0.0.1",
  211. "123.123.123",
  212. func(i int, sw *p2p.Switch) *p2p.Switch {
  213. sw.SetLogger(log.TestingLogger())
  214. r := NewPEXReactor(
  215. book,
  216. &PEXReactorConfig{
  217. Seeds: []string{seed.NodeInfo().NetAddress().String()},
  218. },
  219. )
  220. r.SetLogger(log.TestingLogger())
  221. sw.AddReactor("pex", r)
  222. return sw
  223. },
  224. )
  225. require.Nil(t, peer.Start())
  226. defer peer.Stop()
  227. // 3. check that the peer connects to seed immediately
  228. assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 1*time.Second, 1)
  229. }
  230. func TestPEXReactorCrawlStatus(t *testing.T) {
  231. assert, require := assert.New(t), require.New(t)
  232. dir, err := ioutil.TempDir("", "pex_reactor")
  233. require.Nil(err)
  234. defer os.RemoveAll(dir) // nolint: errcheck
  235. book := NewAddrBook(dir+"addrbook.json", false)
  236. book.SetLogger(log.TestingLogger())
  237. pexR := NewPEXReactor(book, &PEXReactorConfig{SeedMode: true})
  238. // Seed/Crawler mode uses data from the Switch
  239. p2p.MakeSwitch(config, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
  240. pexR.SetLogger(log.TestingLogger())
  241. sw.SetLogger(log.TestingLogger().With("switch", i))
  242. sw.AddReactor("pex", pexR)
  243. return sw
  244. })
  245. // Create a peer, add it to the peer set and the addrbook.
  246. peer := p2p.CreateRandomPeer(false)
  247. p2p.AddPeerToSwitch(pexR.Switch, peer)
  248. addr1 := peer.NodeInfo().NetAddress()
  249. pexR.book.AddAddress(addr1, addr1)
  250. // Add a non-connected address to the book.
  251. _, addr2 := p2p.CreateRoutableAddr()
  252. pexR.book.AddAddress(addr2, addr1)
  253. // Get some peerInfos to crawl
  254. peerInfos := pexR.getPeersToCrawl()
  255. // Make sure it has the proper number of elements
  256. assert.Equal(2, len(peerInfos))
  257. // TODO: test
  258. }
  259. type mockPeer struct {
  260. *cmn.BaseService
  261. pubKey crypto.PubKey
  262. addr *p2p.NetAddress
  263. outbound, persistent bool
  264. }
  265. func newMockPeer() mockPeer {
  266. _, netAddr := p2p.CreateRoutableAddr()
  267. mp := mockPeer{
  268. addr: netAddr,
  269. pubKey: crypto.GenPrivKeyEd25519().Wrap().PubKey(),
  270. }
  271. mp.BaseService = cmn.NewBaseService(nil, "MockPeer", mp)
  272. mp.Start()
  273. return mp
  274. }
  275. func (mp mockPeer) ID() p2p.ID { return p2p.PubKeyToID(mp.pubKey) }
  276. func (mp mockPeer) IsOutbound() bool { return mp.outbound }
  277. func (mp mockPeer) IsPersistent() bool { return mp.persistent }
  278. func (mp mockPeer) NodeInfo() p2p.NodeInfo {
  279. return p2p.NodeInfo{
  280. PubKey: mp.pubKey,
  281. ListenAddr: mp.addr.DialString(),
  282. }
  283. }
  284. func (mp mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
  285. func (mp mockPeer) Send(byte, interface{}) bool { return false }
  286. func (mp mockPeer) TrySend(byte, interface{}) bool { return false }
  287. func (mp mockPeer) Set(string, interface{}) {}
  288. func (mp mockPeer) Get(string) interface{} { return nil }
  289. func assertPeersWithTimeout(
  290. t *testing.T,
  291. switches []*p2p.Switch,
  292. checkPeriod, timeout time.Duration,
  293. nPeers int,
  294. ) {
  295. var (
  296. ticker = time.NewTicker(checkPeriod)
  297. remaining = timeout
  298. )
  299. for {
  300. select {
  301. case <-ticker.C:
  302. // check peers are connected
  303. allGood := true
  304. for _, s := range switches {
  305. outbound, inbound, _ := s.NumPeers()
  306. if outbound+inbound < nPeers {
  307. allGood = false
  308. }
  309. }
  310. remaining -= checkPeriod
  311. if remaining < 0 {
  312. remaining = 0
  313. }
  314. if allGood {
  315. return
  316. }
  317. case <-time.After(remaining):
  318. numPeersStr := ""
  319. for i, s := range switches {
  320. outbound, inbound, _ := s.NumPeers()
  321. numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
  322. }
  323. t.Errorf(
  324. "expected all switches to be connected to at least one peer (switches: %s)",
  325. numPeersStr,
  326. )
  327. return
  328. }
  329. }
  330. }