github.com/MagHErmit/tendermint@v0.282.1/mempool/v0/reactor_test.go (about)

     1  package v0
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"net"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/fortytw2/leaktest"
    12  	"github.com/go-kit/log/term"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/MagHErmit/tendermint/abci/example/kvstore"
    17  	abci "github.com/MagHErmit/tendermint/abci/types"
    18  	cfg "github.com/MagHErmit/tendermint/config"
    19  	"github.com/MagHErmit/tendermint/libs/log"
    20  	tmrand "github.com/MagHErmit/tendermint/libs/rand"
    21  	"github.com/MagHErmit/tendermint/mempool"
    22  	"github.com/MagHErmit/tendermint/p2p"
    23  	"github.com/MagHErmit/tendermint/p2p/mock"
    24  	memproto "github.com/MagHErmit/tendermint/proto/tendermint/mempool"
    25  	"github.com/MagHErmit/tendermint/proxy"
    26  	"github.com/MagHErmit/tendermint/types"
    27  )
    28  
    29  const (
    30  	numTxs  = 1000
    31  	timeout = 120 * time.Second // ridiculously high because CircleCI is slow
    32  )
    33  
    34  type peerState struct {
    35  	height int64
    36  }
    37  
    38  func (ps peerState) GetHeight() int64 {
    39  	return ps.height
    40  }
    41  
    42  // Send a bunch of txs to the first reactor's mempool and wait for them all to
    43  // be received in the others.
    44  func TestReactorBroadcastTxsMessage(t *testing.T) {
    45  	config := cfg.TestConfig()
    46  	// if there were more than two reactors, the order of transactions could not be
    47  	// asserted in waitForTxsOnReactors (due to transactions gossiping). If we
    48  	// replace Connect2Switches (full mesh) with a func, which connects first
    49  	// reactor to others and nothing else, this test should also pass with >2 reactors.
    50  	const N = 2
    51  	reactors := makeAndConnectReactors(config, N)
    52  	defer func() {
    53  		for _, r := range reactors {
    54  			if err := r.Stop(); err != nil {
    55  				assert.NoError(t, err)
    56  			}
    57  		}
    58  	}()
    59  	for _, r := range reactors {
    60  		for _, peer := range r.Switch.Peers().List() {
    61  			peer.Set(types.PeerStateKey, peerState{1})
    62  		}
    63  	}
    64  
    65  	txs := checkTxs(t, reactors[0].mempool, numTxs, mempool.UnknownPeerID)
    66  	waitForTxsOnReactors(t, txs, reactors)
    67  }
    68  
    69  // regression test for https://github.com/MagHErmit/tendermint/issues/5408
    70  func TestReactorConcurrency(t *testing.T) {
    71  	config := cfg.TestConfig()
    72  	const N = 2
    73  	reactors := makeAndConnectReactors(config, N)
    74  	defer func() {
    75  		for _, r := range reactors {
    76  			if err := r.Stop(); err != nil {
    77  				assert.NoError(t, err)
    78  			}
    79  		}
    80  	}()
    81  	for _, r := range reactors {
    82  		for _, peer := range r.Switch.Peers().List() {
    83  			peer.Set(types.PeerStateKey, peerState{1})
    84  		}
    85  	}
    86  	var wg sync.WaitGroup
    87  
    88  	const numTxs = 5
    89  
    90  	for i := 0; i < 1000; i++ {
    91  		wg.Add(2)
    92  
    93  		// 1. submit a bunch of txs
    94  		// 2. update the whole mempool
    95  		txs := checkTxs(t, reactors[0].mempool, numTxs, mempool.UnknownPeerID)
    96  		go func() {
    97  			defer wg.Done()
    98  
    99  			reactors[0].mempool.Lock()
   100  			defer reactors[0].mempool.Unlock()
   101  
   102  			deliverTxResponses := make([]*abci.ResponseDeliverTx, len(txs))
   103  			for i := range txs {
   104  				deliverTxResponses[i] = &abci.ResponseDeliverTx{Code: 0}
   105  			}
   106  			err := reactors[0].mempool.Update(1, txs, deliverTxResponses, nil, nil)
   107  			assert.NoError(t, err)
   108  		}()
   109  
   110  		// 1. submit a bunch of txs
   111  		// 2. update none
   112  		_ = checkTxs(t, reactors[1].mempool, numTxs, mempool.UnknownPeerID)
   113  		go func() {
   114  			defer wg.Done()
   115  
   116  			reactors[1].mempool.Lock()
   117  			defer reactors[1].mempool.Unlock()
   118  			err := reactors[1].mempool.Update(1, []types.Tx{}, make([]*abci.ResponseDeliverTx, 0), nil, nil)
   119  			assert.NoError(t, err)
   120  		}()
   121  
   122  		// 1. flush the mempool
   123  		reactors[1].mempool.Flush()
   124  	}
   125  
   126  	wg.Wait()
   127  }
   128  
   129  // Send a bunch of txs to the first reactor's mempool, claiming it came from peer
   130  // ensure peer gets no txs.
   131  func TestReactorNoBroadcastToSender(t *testing.T) {
   132  	config := cfg.TestConfig()
   133  	const N = 2
   134  	reactors := makeAndConnectReactors(config, N)
   135  	defer func() {
   136  		for _, r := range reactors {
   137  			if err := r.Stop(); err != nil {
   138  				assert.NoError(t, err)
   139  			}
   140  		}
   141  	}()
   142  	for _, r := range reactors {
   143  		for _, peer := range r.Switch.Peers().List() {
   144  			peer.Set(types.PeerStateKey, peerState{1})
   145  		}
   146  	}
   147  
   148  	const peerID = 1
   149  	checkTxs(t, reactors[0].mempool, numTxs, peerID)
   150  	ensureNoTxs(t, reactors[peerID], 100*time.Millisecond)
   151  }
   152  
   153  func TestReactor_MaxTxBytes(t *testing.T) {
   154  	config := cfg.TestConfig()
   155  
   156  	const N = 2
   157  	reactors := makeAndConnectReactors(config, N)
   158  	defer func() {
   159  		for _, r := range reactors {
   160  			if err := r.Stop(); err != nil {
   161  				assert.NoError(t, err)
   162  			}
   163  		}
   164  	}()
   165  	for _, r := range reactors {
   166  		for _, peer := range r.Switch.Peers().List() {
   167  			peer.Set(types.PeerStateKey, peerState{1})
   168  		}
   169  	}
   170  
   171  	// Broadcast a tx, which has the max size
   172  	// => ensure it's received by the second reactor.
   173  	tx1 := tmrand.Bytes(config.Mempool.MaxTxBytes)
   174  	err := reactors[0].mempool.CheckTx(tx1, nil, mempool.TxInfo{SenderID: mempool.UnknownPeerID})
   175  	require.NoError(t, err)
   176  	waitForTxsOnReactors(t, []types.Tx{tx1}, reactors)
   177  
   178  	reactors[0].mempool.Flush()
   179  	reactors[1].mempool.Flush()
   180  
   181  	// Broadcast a tx, which is beyond the max size
   182  	// => ensure it's not sent
   183  	tx2 := tmrand.Bytes(config.Mempool.MaxTxBytes + 1)
   184  	err = reactors[0].mempool.CheckTx(tx2, nil, mempool.TxInfo{SenderID: mempool.UnknownPeerID})
   185  	require.Error(t, err)
   186  }
   187  
   188  func TestBroadcastTxForPeerStopsWhenPeerStops(t *testing.T) {
   189  	if testing.Short() {
   190  		t.Skip("skipping test in short mode.")
   191  	}
   192  
   193  	config := cfg.TestConfig()
   194  	const N = 2
   195  	reactors := makeAndConnectReactors(config, N)
   196  	defer func() {
   197  		for _, r := range reactors {
   198  			if err := r.Stop(); err != nil {
   199  				assert.NoError(t, err)
   200  			}
   201  		}
   202  	}()
   203  
   204  	// stop peer
   205  	sw := reactors[1].Switch
   206  	sw.StopPeerForError(sw.Peers().List()[0], errors.New("some reason"))
   207  
   208  	// check that we are not leaking any go-routines
   209  	// i.e. broadcastTxRoutine finishes when peer is stopped
   210  	leaktest.CheckTimeout(t, 10*time.Second)()
   211  }
   212  
   213  func TestBroadcastTxForPeerStopsWhenReactorStops(t *testing.T) {
   214  	if testing.Short() {
   215  		t.Skip("skipping test in short mode.")
   216  	}
   217  
   218  	config := cfg.TestConfig()
   219  	const N = 2
   220  	reactors := makeAndConnectReactors(config, N)
   221  
   222  	// stop reactors
   223  	for _, r := range reactors {
   224  		if err := r.Stop(); err != nil {
   225  			assert.NoError(t, err)
   226  		}
   227  	}
   228  
   229  	// check that we are not leaking any go-routines
   230  	// i.e. broadcastTxRoutine finishes when reactor is stopped
   231  	leaktest.CheckTimeout(t, 10*time.Second)()
   232  }
   233  
   234  func TestMempoolIDsBasic(t *testing.T) {
   235  	ids := newMempoolIDs()
   236  
   237  	peer := mock.NewPeer(net.IP{127, 0, 0, 1})
   238  
   239  	ids.ReserveForPeer(peer)
   240  	assert.EqualValues(t, 1, ids.GetForPeer(peer))
   241  	ids.Reclaim(peer)
   242  
   243  	ids.ReserveForPeer(peer)
   244  	assert.EqualValues(t, 2, ids.GetForPeer(peer))
   245  	ids.Reclaim(peer)
   246  }
   247  
   248  func TestMempoolIDsPanicsIfNodeRequestsOvermaxActiveIDs(t *testing.T) {
   249  	if testing.Short() {
   250  		return
   251  	}
   252  
   253  	// 0 is already reserved for UnknownPeerID
   254  	ids := newMempoolIDs()
   255  
   256  	for i := 0; i < mempool.MaxActiveIDs-1; i++ {
   257  		peer := mock.NewPeer(net.IP{127, 0, 0, 1})
   258  		ids.ReserveForPeer(peer)
   259  	}
   260  
   261  	assert.Panics(t, func() {
   262  		peer := mock.NewPeer(net.IP{127, 0, 0, 1})
   263  		ids.ReserveForPeer(peer)
   264  	})
   265  }
   266  
   267  func TestDontExhaustMaxActiveIDs(t *testing.T) {
   268  	config := cfg.TestConfig()
   269  	const N = 1
   270  	reactors := makeAndConnectReactors(config, N)
   271  	defer func() {
   272  		for _, r := range reactors {
   273  			if err := r.Stop(); err != nil {
   274  				assert.NoError(t, err)
   275  			}
   276  		}
   277  	}()
   278  	reactor := reactors[0]
   279  
   280  	for i := 0; i < mempool.MaxActiveIDs+1; i++ {
   281  		peer := mock.NewPeer(nil)
   282  		reactor.Receive(mempool.MempoolChannel, peer, []byte{0x1, 0x2, 0x3})
   283  		reactor.AddPeer(peer)
   284  	}
   285  }
   286  
   287  // mempoolLogger is a TestingLogger which uses a different
   288  // color for each validator ("validator" key must exist).
   289  func mempoolLogger() log.Logger {
   290  	return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
   291  		for i := 0; i < len(keyvals)-1; i += 2 {
   292  			if keyvals[i] == "validator" {
   293  				return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
   294  			}
   295  		}
   296  		return term.FgBgColor{}
   297  	})
   298  }
   299  
   300  // connect N mempool reactors through N switches
   301  func makeAndConnectReactors(config *cfg.Config, n int) []*Reactor {
   302  	reactors := make([]*Reactor, n)
   303  	logger := mempoolLogger()
   304  	for i := 0; i < n; i++ {
   305  		app := kvstore.NewApplication()
   306  		cc := proxy.NewLocalClientCreator(app)
   307  		mempool, cleanup := newMempoolWithApp(cc)
   308  		defer cleanup()
   309  
   310  		reactors[i] = NewReactor(config.Mempool, mempool) // so we dont start the consensus states
   311  		reactors[i].SetLogger(logger.With("validator", i))
   312  	}
   313  
   314  	p2p.MakeConnectedSwitches(config.P2P, n, func(i int, s *p2p.Switch) *p2p.Switch {
   315  		s.AddReactor("MEMPOOL", reactors[i])
   316  		return s
   317  
   318  	}, p2p.Connect2Switches)
   319  	return reactors
   320  }
   321  
   322  func waitForTxsOnReactors(t *testing.T, txs types.Txs, reactors []*Reactor) {
   323  	// wait for the txs in all mempools
   324  	wg := new(sync.WaitGroup)
   325  	for i, reactor := range reactors {
   326  		wg.Add(1)
   327  		go func(r *Reactor, reactorIndex int) {
   328  			defer wg.Done()
   329  			waitForTxsOnReactor(t, txs, r, reactorIndex)
   330  		}(reactor, i)
   331  	}
   332  
   333  	done := make(chan struct{})
   334  	go func() {
   335  		wg.Wait()
   336  		close(done)
   337  	}()
   338  
   339  	timer := time.After(timeout)
   340  	select {
   341  	case <-timer:
   342  		t.Fatal("Timed out waiting for txs")
   343  	case <-done:
   344  	}
   345  }
   346  
   347  func waitForTxsOnReactor(t *testing.T, txs types.Txs, reactor *Reactor, reactorIndex int) {
   348  	mempool := reactor.mempool
   349  	for mempool.Size() < len(txs) {
   350  		time.Sleep(time.Millisecond * 100)
   351  	}
   352  
   353  	reapedTxs := mempool.ReapMaxTxs(len(txs))
   354  	for i, tx := range txs {
   355  		assert.Equalf(t, tx, reapedTxs[i],
   356  			"txs at index %d on reactor %d don't match: %v vs %v", i, reactorIndex, tx, reapedTxs[i])
   357  	}
   358  }
   359  
   360  // ensure no txs on reactor after some timeout
   361  func ensureNoTxs(t *testing.T, reactor *Reactor, timeout time.Duration) {
   362  	time.Sleep(timeout) // wait for the txs in all mempools
   363  	assert.Zero(t, reactor.mempool.Size())
   364  }
   365  
   366  func TestMempoolVectors(t *testing.T) {
   367  	testCases := []struct {
   368  		testName string
   369  		tx       []byte
   370  		expBytes string
   371  	}{
   372  		{"tx 1", []byte{123}, "0a030a017b"},
   373  		{"tx 2", []byte("proto encoding in mempool"), "0a1b0a1970726f746f20656e636f64696e6720696e206d656d706f6f6c"},
   374  	}
   375  
   376  	for _, tc := range testCases {
   377  		tc := tc
   378  
   379  		msg := memproto.Message{
   380  			Sum: &memproto.Message_Txs{
   381  				Txs: &memproto.Txs{Txs: [][]byte{tc.tx}},
   382  			},
   383  		}
   384  		bz, err := msg.Marshal()
   385  		require.NoError(t, err, tc.testName)
   386  
   387  		require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName)
   388  	}
   389  }