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.

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