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.

262 lines
6.2 KiB

  1. package p2p
  2. import (
  3. "fmt"
  4. "net"
  5. "time"
  6. crypto "github.com/tendermint/tendermint/crypto"
  7. "github.com/tendermint/tendermint/crypto/ed25519"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/config"
  11. "github.com/tendermint/tendermint/p2p/conn"
  12. )
  13. const testCh = 0x01
  14. //------------------------------------------------
  15. type mockNodeInfo struct {
  16. addr *NetAddress
  17. }
  18. func (ni mockNodeInfo) ID() ID { return ni.addr.ID }
  19. func (ni mockNodeInfo) NetAddress() *NetAddress { return ni.addr }
  20. func (ni mockNodeInfo) ValidateBasic() error { return nil }
  21. func (ni mockNodeInfo) CompatibleWith(other NodeInfo) error { return nil }
  22. func AddPeerToSwitch(sw *Switch, peer Peer) {
  23. sw.peers.Add(peer)
  24. }
  25. func CreateRandomPeer(outbound bool) *peer {
  26. addr, netAddr := CreateRoutableAddr()
  27. p := &peer{
  28. peerConn: peerConn{
  29. outbound: outbound,
  30. },
  31. nodeInfo: mockNodeInfo{netAddr},
  32. mconn: &conn.MConnection{},
  33. metrics: NopMetrics(),
  34. }
  35. p.SetLogger(log.TestingLogger().With("peer", addr))
  36. return p
  37. }
  38. func CreateRoutableAddr() (addr string, netAddr *NetAddress) {
  39. for {
  40. var err error
  41. addr = fmt.Sprintf("%X@%v.%v.%v.%v:26656", cmn.RandBytes(20), cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256)
  42. netAddr, err = NewNetAddressString(addr)
  43. if err != nil {
  44. panic(err)
  45. }
  46. if netAddr.Routable() {
  47. break
  48. }
  49. }
  50. return
  51. }
  52. //------------------------------------------------------------------
  53. // Connects switches via arbitrary net.Conn. Used for testing.
  54. const TEST_HOST = "localhost"
  55. // MakeConnectedSwitches returns n switches, connected according to the connect func.
  56. // If connect==Connect2Switches, the switches will be fully connected.
  57. // initSwitch defines how the i'th switch should be initialized (ie. with what reactors).
  58. // NOTE: panics if any switch fails to start.
  59. func MakeConnectedSwitches(cfg *config.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch {
  60. switches := make([]*Switch, n)
  61. for i := 0; i < n; i++ {
  62. switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch)
  63. }
  64. if err := StartSwitches(switches); err != nil {
  65. panic(err)
  66. }
  67. for i := 0; i < n; i++ {
  68. for j := i + 1; j < n; j++ {
  69. connect(switches, i, j)
  70. }
  71. }
  72. return switches
  73. }
  74. // Connect2Switches will connect switches i and j via net.Pipe().
  75. // Blocks until a connection is established.
  76. // NOTE: caller ensures i and j are within bounds.
  77. func Connect2Switches(switches []*Switch, i, j int) {
  78. switchI := switches[i]
  79. switchJ := switches[j]
  80. c1, c2 := conn.NetPipe()
  81. doneCh := make(chan struct{})
  82. go func() {
  83. err := switchI.addPeerWithConnection(c1)
  84. if err != nil {
  85. panic(err)
  86. }
  87. doneCh <- struct{}{}
  88. }()
  89. go func() {
  90. err := switchJ.addPeerWithConnection(c2)
  91. if err != nil {
  92. panic(err)
  93. }
  94. doneCh <- struct{}{}
  95. }()
  96. <-doneCh
  97. <-doneCh
  98. }
  99. func (sw *Switch) addPeerWithConnection(conn net.Conn) error {
  100. pc, err := testInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey)
  101. if err != nil {
  102. if err := conn.Close(); err != nil {
  103. sw.Logger.Error("Error closing connection", "err", err)
  104. }
  105. return err
  106. }
  107. ni, err := handshake(conn, 50*time.Millisecond, sw.nodeInfo)
  108. if err != nil {
  109. if err := conn.Close(); err != nil {
  110. sw.Logger.Error("Error closing connection", "err", err)
  111. }
  112. return err
  113. }
  114. p := newPeer(
  115. pc,
  116. sw.mConfig,
  117. ni,
  118. sw.reactorsByCh,
  119. sw.chDescs,
  120. sw.StopPeerForError,
  121. )
  122. if err = sw.addPeer(p); err != nil {
  123. pc.CloseConn()
  124. return err
  125. }
  126. return nil
  127. }
  128. // StartSwitches calls sw.Start() for each given switch.
  129. // It returns the first encountered error.
  130. func StartSwitches(switches []*Switch) error {
  131. for _, s := range switches {
  132. err := s.Start() // start switch and reactors
  133. if err != nil {
  134. return err
  135. }
  136. }
  137. return nil
  138. }
  139. func MakeSwitch(
  140. cfg *config.P2PConfig,
  141. i int,
  142. network, version string,
  143. initSwitch func(int, *Switch) *Switch,
  144. opts ...SwitchOption,
  145. ) *Switch {
  146. nodeKey := NodeKey{
  147. PrivKey: ed25519.GenPrivKey(),
  148. }
  149. nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i))
  150. t := NewMultiplexTransport(nodeInfo, nodeKey)
  151. addr := nodeInfo.NetAddress()
  152. if err := t.Listen(*addr); err != nil {
  153. panic(err)
  154. }
  155. // TODO: let the config be passed in?
  156. sw := initSwitch(i, NewSwitch(cfg, t, opts...))
  157. sw.SetLogger(log.TestingLogger())
  158. sw.SetNodeKey(&nodeKey)
  159. ni := nodeInfo.(DefaultNodeInfo)
  160. for ch := range sw.reactorsByCh {
  161. ni.Channels = append(ni.Channels, ch)
  162. }
  163. nodeInfo = ni
  164. // TODO: We need to setup reactors ahead of time so the NodeInfo is properly
  165. // populated and we don't have to do those awkward overrides and setters.
  166. t.nodeInfo = nodeInfo
  167. sw.SetNodeInfo(nodeInfo)
  168. return sw
  169. }
  170. func testInboundPeerConn(
  171. conn net.Conn,
  172. config *config.P2PConfig,
  173. ourNodePrivKey crypto.PrivKey,
  174. ) (peerConn, error) {
  175. return testPeerConn(conn, config, false, false, ourNodePrivKey)
  176. }
  177. func testPeerConn(
  178. rawConn net.Conn,
  179. cfg *config.P2PConfig,
  180. outbound, persistent bool,
  181. ourNodePrivKey crypto.PrivKey,
  182. ) (pc peerConn, err error) {
  183. conn := rawConn
  184. // Fuzz connection
  185. if cfg.TestFuzz {
  186. // so we have time to do peer handshakes and get set up
  187. conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig)
  188. }
  189. // Encrypt connection
  190. conn, err = upgradeSecretConn(conn, cfg.HandshakeTimeout, ourNodePrivKey)
  191. if err != nil {
  192. return pc, cmn.ErrorWrap(err, "Error creating peer")
  193. }
  194. // Only the information we already have
  195. return peerConn{
  196. config: cfg,
  197. outbound: outbound,
  198. persistent: persistent,
  199. conn: conn,
  200. }, nil
  201. }
  202. //----------------------------------------------------------------
  203. // rand node info
  204. func testNodeInfo(id ID, name string) NodeInfo {
  205. return testNodeInfoWithNetwork(id, name, "testing")
  206. }
  207. func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
  208. return DefaultNodeInfo{
  209. ProtocolVersion: InitProtocolVersion,
  210. ID_: id,
  211. ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
  212. Network: network,
  213. Version: "1.2.3-rc0-deadbeef",
  214. Channels: []byte{testCh},
  215. Moniker: name,
  216. Other: DefaultNodeInfoOther{
  217. TxIndex: "on",
  218. RPCAddress: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
  219. },
  220. }
  221. }