github.com/evdatsion/aphelion-dpos-bft@v0.32.1/p2p/test_util.go (about)

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