github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/p2p/test_util.go (about)

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