github.com/Finschia/ostracon@v1.1.5/p2p/test_util.go (about)

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