github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/p2p/switch_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"sync"
    10  	"sync/atomic"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/gnolang/gno/tm2/pkg/crypto/ed25519"
    18  	"github.com/gnolang/gno/tm2/pkg/log"
    19  	"github.com/gnolang/gno/tm2/pkg/p2p/config"
    20  	"github.com/gnolang/gno/tm2/pkg/p2p/conn"
    21  	"github.com/gnolang/gno/tm2/pkg/testutils"
    22  )
    23  
    24  var cfg *config.P2PConfig
    25  
    26  func init() {
    27  	cfg = config.DefaultP2PConfig()
    28  	cfg.PexReactor = true
    29  	cfg.AllowDuplicateIP = true
    30  }
    31  
    32  type PeerMessage struct {
    33  	PeerID  ID
    34  	Bytes   []byte
    35  	Counter int
    36  }
    37  
    38  type TestReactor struct {
    39  	BaseReactor
    40  
    41  	mtx          sync.Mutex
    42  	channels     []*conn.ChannelDescriptor
    43  	logMessages  bool
    44  	msgsCounter  int
    45  	msgsReceived map[byte][]PeerMessage
    46  }
    47  
    48  func NewTestReactor(channels []*conn.ChannelDescriptor, logMessages bool) *TestReactor {
    49  	tr := &TestReactor{
    50  		channels:     channels,
    51  		logMessages:  logMessages,
    52  		msgsReceived: make(map[byte][]PeerMessage),
    53  	}
    54  	tr.BaseReactor = *NewBaseReactor("TestReactor", tr)
    55  	tr.SetLogger(log.NewNoopLogger())
    56  	return tr
    57  }
    58  
    59  func (tr *TestReactor) GetChannels() []*conn.ChannelDescriptor {
    60  	return tr.channels
    61  }
    62  
    63  func (tr *TestReactor) AddPeer(peer Peer) {}
    64  
    65  func (tr *TestReactor) RemovePeer(peer Peer, reason interface{}) {}
    66  
    67  func (tr *TestReactor) Receive(chID byte, peer Peer, msgBytes []byte) {
    68  	if tr.logMessages {
    69  		tr.mtx.Lock()
    70  		defer tr.mtx.Unlock()
    71  		// fmt.Printf("Received: %X, %X\n", chID, msgBytes)
    72  		tr.msgsReceived[chID] = append(tr.msgsReceived[chID], PeerMessage{peer.ID(), msgBytes, tr.msgsCounter})
    73  		tr.msgsCounter++
    74  	}
    75  }
    76  
    77  func (tr *TestReactor) getMsgs(chID byte) []PeerMessage {
    78  	tr.mtx.Lock()
    79  	defer tr.mtx.Unlock()
    80  	return tr.msgsReceived[chID]
    81  }
    82  
    83  // -----------------------------------------------------------------------------
    84  
    85  // convenience method for creating two switches connected to each other.
    86  // XXX: note this uses net.Pipe and not a proper TCP conn
    87  func MakeSwitchPair(_ testing.TB, initSwitch func(int, *Switch) *Switch) (*Switch, *Switch) {
    88  	// Create two switches that will be interconnected.
    89  	switches := MakeConnectedSwitches(cfg, 2, initSwitch, Connect2Switches)
    90  	return switches[0], switches[1]
    91  }
    92  
    93  func initSwitchFunc(i int, sw *Switch) *Switch {
    94  	// Make two reactors of two channels each
    95  	sw.AddReactor("foo", NewTestReactor([]*conn.ChannelDescriptor{
    96  		{ID: byte(0x00), Priority: 10},
    97  		{ID: byte(0x01), Priority: 10},
    98  	}, true))
    99  	sw.AddReactor("bar", NewTestReactor([]*conn.ChannelDescriptor{
   100  		{ID: byte(0x02), Priority: 10},
   101  		{ID: byte(0x03), Priority: 10},
   102  	}, true))
   103  
   104  	return sw
   105  }
   106  
   107  func TestSwitches(t *testing.T) {
   108  	t.Parallel()
   109  
   110  	s1, s2 := MakeSwitchPair(t, initSwitchFunc)
   111  	defer s1.Stop()
   112  	defer s2.Stop()
   113  
   114  	if s1.Peers().Size() != 1 {
   115  		t.Errorf("Expected exactly 1 peer in s1, got %v", s1.Peers().Size())
   116  	}
   117  	if s2.Peers().Size() != 1 {
   118  		t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size())
   119  	}
   120  
   121  	// Lets send some messages
   122  	ch0Msg := []byte("channel zero")
   123  	ch1Msg := []byte("channel foo")
   124  	ch2Msg := []byte("channel bar")
   125  
   126  	s1.Broadcast(byte(0x00), ch0Msg)
   127  	s1.Broadcast(byte(0x01), ch1Msg)
   128  	s1.Broadcast(byte(0x02), ch2Msg)
   129  
   130  	assertMsgReceivedWithTimeout(t, ch0Msg, byte(0x00), s2.Reactor("foo").(*TestReactor), 10*time.Millisecond, 5*time.Second)
   131  	assertMsgReceivedWithTimeout(t, ch1Msg, byte(0x01), s2.Reactor("foo").(*TestReactor), 10*time.Millisecond, 5*time.Second)
   132  	assertMsgReceivedWithTimeout(t, ch2Msg, byte(0x02), s2.Reactor("bar").(*TestReactor), 10*time.Millisecond, 5*time.Second)
   133  }
   134  
   135  func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, reactor *TestReactor, checkPeriod, timeout time.Duration) {
   136  	t.Helper()
   137  
   138  	ticker := time.NewTicker(checkPeriod)
   139  	for {
   140  		select {
   141  		case <-ticker.C:
   142  			msgs := reactor.getMsgs(channel)
   143  			if len(msgs) > 0 {
   144  				if !bytes.Equal(msgs[0].Bytes, msgBytes) {
   145  					t.Fatalf("Unexpected message bytes. Wanted: %X, Got: %X", msgBytes, msgs[0].Bytes)
   146  				}
   147  				return
   148  			}
   149  
   150  		case <-time.After(timeout):
   151  			t.Fatalf("Expected to have received 1 message in channel #%v, got zero", channel)
   152  		}
   153  	}
   154  }
   155  
   156  func TestSwitchFiltersOutItself(t *testing.T) {
   157  	t.Parallel()
   158  
   159  	s1 := MakeSwitch(cfg, 1, "127.0.0.1", "123.123.123", initSwitchFunc)
   160  
   161  	// simulate s1 having a public IP by creating a remote peer with the same ID
   162  	rp := &remotePeer{PrivKey: s1.nodeKey.PrivKey, Config: cfg}
   163  	rp.Start()
   164  
   165  	// addr should be rejected in addPeer based on the same ID
   166  	err := s1.DialPeerWithAddress(rp.Addr())
   167  	if assert.Error(t, err) {
   168  		if err, ok := err.(RejectedError); ok {
   169  			if !err.IsSelf() {
   170  				t.Errorf("expected self to be rejected")
   171  			}
   172  		} else {
   173  			t.Errorf("expected RejectedError")
   174  		}
   175  	}
   176  
   177  	rp.Stop()
   178  
   179  	assertNoPeersAfterTimeout(t, s1, 100*time.Millisecond)
   180  }
   181  
   182  func TestSwitchPeerFilter(t *testing.T) {
   183  	t.Parallel()
   184  
   185  	var (
   186  		filters = []PeerFilterFunc{
   187  			func(_ IPeerSet, _ Peer) error { return nil },
   188  			func(_ IPeerSet, _ Peer) error { return fmt.Errorf("denied!") },
   189  			func(_ IPeerSet, _ Peer) error { return nil },
   190  		}
   191  		sw = MakeSwitch(
   192  			cfg,
   193  			1,
   194  			"testing",
   195  			"123.123.123",
   196  			initSwitchFunc,
   197  			SwitchPeerFilters(filters...),
   198  		)
   199  	)
   200  	defer sw.Stop()
   201  
   202  	// simulate remote peer
   203  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   204  	rp.Start()
   205  	defer rp.Stop()
   206  
   207  	p, err := sw.transport.Dial(*rp.Addr(), peerConfig{
   208  		chDescs:      sw.chDescs,
   209  		onPeerError:  sw.StopPeerForError,
   210  		isPersistent: sw.isPeerPersistentFn(),
   211  		reactorsByCh: sw.reactorsByCh,
   212  	})
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	err = sw.addPeer(p)
   218  	if err, ok := err.(RejectedError); ok {
   219  		if !err.IsFiltered() {
   220  			t.Errorf("expected peer to be filtered")
   221  		}
   222  	} else {
   223  		t.Errorf("expected RejectedError")
   224  	}
   225  }
   226  
   227  func TestSwitchPeerFilterTimeout(t *testing.T) {
   228  	t.Parallel()
   229  
   230  	var (
   231  		filters = []PeerFilterFunc{
   232  			func(_ IPeerSet, _ Peer) error {
   233  				time.Sleep(10 * time.Millisecond)
   234  				return nil
   235  			},
   236  		}
   237  		sw = MakeSwitch(
   238  			cfg,
   239  			1,
   240  			"testing",
   241  			"123.123.123",
   242  			initSwitchFunc,
   243  			SwitchFilterTimeout(5*time.Millisecond),
   244  			SwitchPeerFilters(filters...),
   245  		)
   246  	)
   247  	defer sw.Stop()
   248  
   249  	// simulate remote peer
   250  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   251  	rp.Start()
   252  	defer rp.Stop()
   253  
   254  	p, err := sw.transport.Dial(*rp.Addr(), peerConfig{
   255  		chDescs:      sw.chDescs,
   256  		onPeerError:  sw.StopPeerForError,
   257  		isPersistent: sw.isPeerPersistentFn(),
   258  		reactorsByCh: sw.reactorsByCh,
   259  	})
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	err = sw.addPeer(p)
   265  	if _, ok := err.(FilterTimeoutError); !ok {
   266  		t.Errorf("expected FilterTimeoutError")
   267  	}
   268  }
   269  
   270  func TestSwitchPeerFilterDuplicate(t *testing.T) {
   271  	t.Parallel()
   272  
   273  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   274  	sw.Start()
   275  	defer sw.Stop()
   276  
   277  	// simulate remote peer
   278  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   279  	rp.Start()
   280  	defer rp.Stop()
   281  
   282  	p, err := sw.transport.Dial(*rp.Addr(), peerConfig{
   283  		chDescs:      sw.chDescs,
   284  		onPeerError:  sw.StopPeerForError,
   285  		isPersistent: sw.isPeerPersistentFn(),
   286  		reactorsByCh: sw.reactorsByCh,
   287  	})
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  
   292  	if err := sw.addPeer(p); err != nil {
   293  		t.Fatal(err)
   294  	}
   295  
   296  	err = sw.addPeer(p)
   297  	if errRej, ok := err.(RejectedError); ok {
   298  		if !errRej.IsDuplicate() {
   299  			t.Errorf("expected peer to be duplicate. got %v", errRej)
   300  		}
   301  	} else {
   302  		t.Errorf("expected RejectedError, got %v", err)
   303  	}
   304  }
   305  
   306  func assertNoPeersAfterTimeout(t *testing.T, sw *Switch, timeout time.Duration) {
   307  	t.Helper()
   308  
   309  	time.Sleep(timeout)
   310  	if sw.Peers().Size() != 0 {
   311  		t.Fatalf("Expected %v to not connect to some peers, got %d", sw, sw.Peers().Size())
   312  	}
   313  }
   314  
   315  func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
   316  	t.Parallel()
   317  
   318  	assert, require := assert.New(t), require.New(t)
   319  
   320  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   321  	err := sw.Start()
   322  	if err != nil {
   323  		t.Error(err)
   324  	}
   325  	defer sw.Stop()
   326  
   327  	// simulate remote peer
   328  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   329  	rp.Start()
   330  	defer rp.Stop()
   331  
   332  	p, err := sw.transport.Dial(*rp.Addr(), peerConfig{
   333  		chDescs:      sw.chDescs,
   334  		onPeerError:  sw.StopPeerForError,
   335  		isPersistent: sw.isPeerPersistentFn(),
   336  		reactorsByCh: sw.reactorsByCh,
   337  	})
   338  	require.Nil(err)
   339  
   340  	err = sw.addPeer(p)
   341  	require.Nil(err)
   342  
   343  	require.NotNil(sw.Peers().Get(rp.ID()))
   344  
   345  	// simulate failure by closing connection
   346  	p.(*peer).CloseConn()
   347  
   348  	assertNoPeersAfterTimeout(t, sw, 100*time.Millisecond)
   349  	assert.False(p.IsRunning())
   350  }
   351  
   352  func TestSwitchStopPeerForError(t *testing.T) {
   353  	t.Parallel()
   354  
   355  	// make two connected switches
   356  	sw1, sw2 := MakeSwitchPair(t, func(i int, sw *Switch) *Switch {
   357  		return initSwitchFunc(i, sw)
   358  	})
   359  
   360  	assert.Equal(t, len(sw1.Peers().List()), 1)
   361  
   362  	// send messages to the peer from sw1
   363  	p := sw1.Peers().List()[0]
   364  	p.Send(0x1, []byte("here's a message to send"))
   365  
   366  	// stop sw2. this should cause the p to fail,
   367  	// which results in calling StopPeerForError internally
   368  	sw2.Stop()
   369  
   370  	// now call StopPeerForError explicitly, eg. from a reactor
   371  	sw1.StopPeerForError(p, fmt.Errorf("some err"))
   372  
   373  	assert.Equal(t, len(sw1.Peers().List()), 0)
   374  }
   375  
   376  func TestSwitchReconnectsToOutboundPersistentPeer(t *testing.T) {
   377  	t.Parallel()
   378  
   379  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   380  	err := sw.Start()
   381  	require.NoError(t, err)
   382  	defer sw.Stop()
   383  
   384  	// 1. simulate failure by closing connection
   385  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   386  	rp.Start()
   387  	defer rp.Stop()
   388  
   389  	err = sw.AddPersistentPeers([]string{rp.Addr().String()})
   390  	require.NoError(t, err)
   391  
   392  	err = sw.DialPeerWithAddress(rp.Addr())
   393  	require.Nil(t, err)
   394  	require.NotNil(t, sw.Peers().Get(rp.ID()))
   395  
   396  	p := sw.Peers().List()[0]
   397  	p.(*peer).CloseConn()
   398  
   399  	waitUntilSwitchHasAtLeastNPeers(sw, 1)
   400  	assert.False(t, p.IsRunning())        // old peer instance
   401  	assert.Equal(t, 1, sw.Peers().Size()) // new peer instance
   402  
   403  	// 2. simulate first time dial failure
   404  	rp = &remotePeer{
   405  		PrivKey: ed25519.GenPrivKey(),
   406  		Config:  cfg,
   407  		// Use different interface to prevent duplicate IP filter, this will break
   408  		// beyond two peers.
   409  		listenAddr: "127.0.0.1:0",
   410  	}
   411  	rp.Start()
   412  	defer rp.Stop()
   413  
   414  	conf := config.DefaultP2PConfig()
   415  	conf.TestDialFail = true // will trigger a reconnect
   416  	err = sw.addOutboundPeerWithConfig(rp.Addr(), conf)
   417  	require.NotNil(t, err)
   418  	// DialPeerWithAddres - sw.peerConfig resets the dialer
   419  	waitUntilSwitchHasAtLeastNPeers(sw, 2)
   420  	assert.Equal(t, 2, sw.Peers().Size())
   421  }
   422  
   423  func TestSwitchReconnectsToInboundPersistentPeer(t *testing.T) {
   424  	t.Parallel()
   425  
   426  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   427  	err := sw.Start()
   428  	require.NoError(t, err)
   429  	defer sw.Stop()
   430  
   431  	// 1. simulate failure by closing the connection
   432  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   433  	rp.Start()
   434  	defer rp.Stop()
   435  
   436  	err = sw.AddPersistentPeers([]string{rp.Addr().String()})
   437  	require.NoError(t, err)
   438  
   439  	conn, err := rp.Dial(sw.NetAddress())
   440  	require.NoError(t, err)
   441  	time.Sleep(100 * time.Millisecond)
   442  	require.NotNil(t, sw.Peers().Get(rp.ID()))
   443  
   444  	conn.Close()
   445  
   446  	waitUntilSwitchHasAtLeastNPeers(sw, 1)
   447  	assert.Equal(t, 1, sw.Peers().Size())
   448  }
   449  
   450  func TestSwitchDialPeersAsync(t *testing.T) {
   451  	t.Parallel()
   452  
   453  	if testing.Short() {
   454  		return
   455  	}
   456  
   457  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   458  	err := sw.Start()
   459  	require.NoError(t, err)
   460  	defer sw.Stop()
   461  
   462  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   463  	rp.Start()
   464  	defer rp.Stop()
   465  
   466  	err = sw.DialPeersAsync([]string{rp.Addr().String()})
   467  	require.NoError(t, err)
   468  	time.Sleep(dialRandomizerIntervalMilliseconds * time.Millisecond)
   469  	require.NotNil(t, sw.Peers().Get(rp.ID()))
   470  }
   471  
   472  func waitUntilSwitchHasAtLeastNPeers(sw *Switch, n int) {
   473  	for i := 0; i < 20; i++ {
   474  		time.Sleep(250 * time.Millisecond)
   475  		has := sw.Peers().Size()
   476  		if has >= n {
   477  			break
   478  		}
   479  	}
   480  }
   481  
   482  func TestSwitchFullConnectivity(t *testing.T) {
   483  	t.Parallel()
   484  
   485  	switches := MakeConnectedSwitches(cfg, 3, initSwitchFunc, Connect2Switches)
   486  	defer func() {
   487  		for _, sw := range switches {
   488  			sw.Stop()
   489  		}
   490  	}()
   491  
   492  	for i, sw := range switches {
   493  		if sw.Peers().Size() != 2 {
   494  			t.Fatalf("Expected each switch to be connected to 2 other, but %d switch only connected to %d", sw.Peers().Size(), i)
   495  		}
   496  	}
   497  }
   498  
   499  func TestSwitchAcceptRoutine(t *testing.T) {
   500  	t.Parallel()
   501  
   502  	cfg.MaxNumInboundPeers = 5
   503  
   504  	// make switch
   505  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc)
   506  	err := sw.Start()
   507  	require.NoError(t, err)
   508  	defer sw.Stop()
   509  
   510  	remotePeers := make([]*remotePeer, 0)
   511  	assert.Equal(t, 0, sw.Peers().Size())
   512  
   513  	// 1. check we connect up to MaxNumInboundPeers
   514  	for i := 0; i < cfg.MaxNumInboundPeers; i++ {
   515  		rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   516  		remotePeers = append(remotePeers, rp)
   517  		rp.Start()
   518  		c, err := rp.Dial(sw.NetAddress())
   519  		require.NoError(t, err)
   520  		// spawn a reading routine to prevent connection from closing
   521  		go func(c net.Conn) {
   522  			for {
   523  				one := make([]byte, 1)
   524  				_, err := c.Read(one)
   525  				if err != nil {
   526  					return
   527  				}
   528  			}
   529  		}(c)
   530  	}
   531  	time.Sleep(100 * time.Millisecond)
   532  	assert.Equal(t, cfg.MaxNumInboundPeers, sw.Peers().Size())
   533  
   534  	// 2. check we close new connections if we already have MaxNumInboundPeers peers
   535  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   536  	rp.Start()
   537  	conn, err := rp.Dial(sw.NetAddress())
   538  	require.NoError(t, err)
   539  	// check conn is closed
   540  	one := make([]byte, 1)
   541  	conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
   542  	_, err = conn.Read(one)
   543  	assert.Equal(t, io.EOF, err)
   544  	assert.Equal(t, cfg.MaxNumInboundPeers, sw.Peers().Size())
   545  	rp.Stop()
   546  
   547  	// stop remote peers
   548  	for _, rp := range remotePeers {
   549  		rp.Stop()
   550  	}
   551  }
   552  
   553  type errorTransport struct {
   554  	acceptErr error
   555  }
   556  
   557  func (et errorTransport) NetAddress() NetAddress {
   558  	panic("not implemented")
   559  }
   560  
   561  func (et errorTransport) Accept(c peerConfig) (Peer, error) {
   562  	return nil, et.acceptErr
   563  }
   564  
   565  func (errorTransport) Dial(NetAddress, peerConfig) (Peer, error) {
   566  	panic("not implemented")
   567  }
   568  
   569  func (errorTransport) Cleanup(Peer) {
   570  	panic("not implemented")
   571  }
   572  
   573  func TestSwitchAcceptRoutineErrorCases(t *testing.T) {
   574  	t.Parallel()
   575  
   576  	sw := NewSwitch(cfg, errorTransport{FilterTimeoutError{}})
   577  	assert.NotPanics(t, func() {
   578  		err := sw.Start()
   579  		assert.NoError(t, err)
   580  		sw.Stop()
   581  	})
   582  
   583  	sw = NewSwitch(cfg, errorTransport{RejectedError{conn: nil, err: errors.New("filtered"), isFiltered: true}})
   584  	assert.NotPanics(t, func() {
   585  		err := sw.Start()
   586  		assert.NoError(t, err)
   587  		sw.Stop()
   588  	})
   589  
   590  	sw = NewSwitch(cfg, errorTransport{TransportClosedError{}})
   591  	assert.NotPanics(t, func() {
   592  		err := sw.Start()
   593  		assert.NoError(t, err)
   594  		sw.Stop()
   595  	})
   596  }
   597  
   598  // mockReactor checks that InitPeer never called before RemovePeer. If that's
   599  // not true, InitCalledBeforeRemoveFinished will return true.
   600  type mockReactor struct {
   601  	*BaseReactor
   602  
   603  	// atomic
   604  	removePeerInProgress           uint32
   605  	initCalledBeforeRemoveFinished uint32
   606  }
   607  
   608  func (r *mockReactor) RemovePeer(peer Peer, reason interface{}) {
   609  	atomic.StoreUint32(&r.removePeerInProgress, 1)
   610  	defer atomic.StoreUint32(&r.removePeerInProgress, 0)
   611  	time.Sleep(100 * time.Millisecond)
   612  }
   613  
   614  func (r *mockReactor) InitPeer(peer Peer) Peer {
   615  	if atomic.LoadUint32(&r.removePeerInProgress) == 1 {
   616  		atomic.StoreUint32(&r.initCalledBeforeRemoveFinished, 1)
   617  	}
   618  
   619  	return peer
   620  }
   621  
   622  func (r *mockReactor) InitCalledBeforeRemoveFinished() bool {
   623  	return atomic.LoadUint32(&r.initCalledBeforeRemoveFinished) == 1
   624  }
   625  
   626  // see stopAndRemovePeer
   627  func TestFlappySwitchInitPeerIsNotCalledBeforeRemovePeer(t *testing.T) {
   628  	t.Parallel()
   629  
   630  	testutils.FilterStability(t, testutils.Flappy)
   631  
   632  	// make reactor
   633  	reactor := &mockReactor{}
   634  	reactor.BaseReactor = NewBaseReactor("mockReactor", reactor)
   635  
   636  	// make switch
   637  	sw := MakeSwitch(cfg, 1, "testing", "123.123.123", func(i int, sw *Switch) *Switch {
   638  		sw.AddReactor("mock", reactor)
   639  		return sw
   640  	})
   641  	err := sw.Start()
   642  	require.NoError(t, err)
   643  	defer sw.Stop()
   644  
   645  	// add peer
   646  	rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg}
   647  	rp.Start()
   648  	defer rp.Stop()
   649  	_, err = rp.Dial(sw.NetAddress())
   650  	require.NoError(t, err)
   651  	// wait till the switch adds rp to the peer set
   652  	time.Sleep(100 * time.Millisecond)
   653  
   654  	// stop peer asynchronously
   655  	go sw.StopPeerForError(sw.Peers().Get(rp.ID()), "test")
   656  
   657  	// simulate peer reconnecting to us
   658  	_, err = rp.Dial(sw.NetAddress())
   659  	require.NoError(t, err)
   660  	// wait till the switch adds rp to the peer set
   661  	time.Sleep(100 * time.Millisecond)
   662  
   663  	// make sure reactor.RemovePeer is finished before InitPeer is called
   664  	assert.False(t, reactor.InitCalledBeforeRemoveFinished())
   665  }
   666  
   667  func BenchmarkSwitchBroadcast(b *testing.B) {
   668  	s1, s2 := MakeSwitchPair(b, func(i int, sw *Switch) *Switch {
   669  		// Make bar reactors of bar channels each
   670  		sw.AddReactor("foo", NewTestReactor([]*conn.ChannelDescriptor{
   671  			{ID: byte(0x00), Priority: 10},
   672  			{ID: byte(0x01), Priority: 10},
   673  		}, false))
   674  		sw.AddReactor("bar", NewTestReactor([]*conn.ChannelDescriptor{
   675  			{ID: byte(0x02), Priority: 10},
   676  			{ID: byte(0x03), Priority: 10},
   677  		}, false))
   678  		return sw
   679  	})
   680  	defer s1.Stop()
   681  	defer s2.Stop()
   682  
   683  	// Allow time for goroutines to boot up
   684  	time.Sleep(1 * time.Second)
   685  
   686  	b.ResetTimer()
   687  
   688  	numSuccess, numFailure := 0, 0
   689  
   690  	// Send random message from foo channel to another
   691  	for i := 0; i < b.N; i++ {
   692  		chID := byte(i % 4)
   693  		successChan := s1.Broadcast(chID, []byte("test data"))
   694  		for s := range successChan {
   695  			if s {
   696  				numSuccess++
   697  			} else {
   698  				numFailure++
   699  			}
   700  		}
   701  	}
   702  
   703  	b.Logf("success: %v, failure: %v", numSuccess, numFailure)
   704  }