github.com/aakash4dev/cometbft@v0.38.2/mempool/clist_mempool_test.go (about)

     1  package mempool
     2  
     3  import (
     4  	"context"
     5  	"encoding/binary"
     6  	mrand "math/rand"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"fmt"
    12  
    13  	"github.com/cosmos/gogoproto/proto"
    14  	gogotypes "github.com/cosmos/gogoproto/types"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	abciclient "github.com/aakash4dev/cometbft/abci/client"
    20  	abciclimocks "github.com/aakash4dev/cometbft/abci/client/mocks"
    21  	"github.com/aakash4dev/cometbft/abci/example/kvstore"
    22  	abciserver "github.com/aakash4dev/cometbft/abci/server"
    23  	abci "github.com/aakash4dev/cometbft/abci/types"
    24  	"github.com/aakash4dev/cometbft/config"
    25  	"github.com/aakash4dev/cometbft/internal/test"
    26  	"github.com/aakash4dev/cometbft/libs/log"
    27  	cmtrand "github.com/aakash4dev/cometbft/libs/rand"
    28  	"github.com/aakash4dev/cometbft/libs/service"
    29  	"github.com/aakash4dev/cometbft/proxy"
    30  	"github.com/aakash4dev/cometbft/types"
    31  )
    32  
    33  // A cleanupFunc cleans up any config / test files created for a particular
    34  // test.
    35  type cleanupFunc func()
    36  
    37  func newMempoolWithAppMock(client abciclient.Client) (*CListMempool, cleanupFunc, error) {
    38  	conf := test.ResetTestRoot("mempool_test")
    39  
    40  	mp, cu := newMempoolWithAppAndConfigMock(conf, client)
    41  	return mp, cu, nil
    42  }
    43  
    44  func newMempoolWithAppAndConfigMock(
    45  	cfg *config.Config,
    46  	client abciclient.Client,
    47  ) (*CListMempool, cleanupFunc) {
    48  	appConnMem := client
    49  	appConnMem.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "mempool"))
    50  	err := appConnMem.Start()
    51  	if err != nil {
    52  		panic(err)
    53  	}
    54  
    55  	mp := NewCListMempool(cfg.Mempool, appConnMem, 0)
    56  	mp.SetLogger(log.TestingLogger())
    57  
    58  	return mp, func() { os.RemoveAll(cfg.RootDir) }
    59  }
    60  
    61  func newMempoolWithApp(cc proxy.ClientCreator) (*CListMempool, cleanupFunc) {
    62  	conf := test.ResetTestRoot("mempool_test")
    63  
    64  	mp, cu := newMempoolWithAppAndConfig(cc, conf)
    65  	return mp, cu
    66  }
    67  
    68  func newMempoolWithAppAndConfig(cc proxy.ClientCreator, cfg *config.Config) (*CListMempool, cleanupFunc) {
    69  	appConnMem, _ := cc.NewABCIClient()
    70  	appConnMem.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "mempool"))
    71  	err := appConnMem.Start()
    72  	if err != nil {
    73  		panic(err)
    74  	}
    75  
    76  	mp := NewCListMempool(cfg.Mempool, appConnMem, 0)
    77  	mp.SetLogger(log.TestingLogger())
    78  
    79  	return mp, func() { os.RemoveAll(cfg.RootDir) }
    80  }
    81  
    82  func ensureNoFire(t *testing.T, ch <-chan struct{}, timeoutMS int) {
    83  	timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond)
    84  	select {
    85  	case <-ch:
    86  		t.Fatal("Expected not to fire")
    87  	case <-timer.C:
    88  	}
    89  }
    90  
    91  func ensureFire(t *testing.T, ch <-chan struct{}, timeoutMS int) {
    92  	timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond)
    93  	select {
    94  	case <-ch:
    95  	case <-timer.C:
    96  		t.Fatal("Expected to fire")
    97  	}
    98  }
    99  
   100  // Call CheckTx on a given mempool on each transaction in the list.
   101  func callCheckTx(t *testing.T, mp Mempool, txs types.Txs) {
   102  	for i, tx := range txs {
   103  		if _, err := mp.CheckTx(tx); err != nil {
   104  			// Skip invalid txs.
   105  			// TestMempoolFilters will fail otherwise. It asserts a number of txs
   106  			// returned.
   107  			if IsPreCheckError(err) {
   108  				continue
   109  			}
   110  			t.Fatalf("CheckTx failed: %v while checking #%d tx", err, i)
   111  		}
   112  	}
   113  }
   114  
   115  // Generate a list of random transactions
   116  func NewRandomTxs(numTxs int, txLen int) types.Txs {
   117  	txs := make(types.Txs, numTxs)
   118  	for i := 0; i < numTxs; i++ {
   119  		txBytes := kvstore.NewRandomTx(txLen)
   120  		txs[i] = txBytes
   121  	}
   122  	return txs
   123  }
   124  
   125  // Generate a list of random transactions of a given size and call CheckTx on
   126  // each of them.
   127  func checkTxs(t *testing.T, mp Mempool, count int) types.Txs {
   128  	txs := NewRandomTxs(count, 20)
   129  	callCheckTx(t, mp, txs)
   130  	return txs
   131  }
   132  
   133  func TestReapMaxBytesMaxGas(t *testing.T) {
   134  	app := kvstore.NewInMemoryApplication()
   135  	cc := proxy.NewLocalClientCreator(app)
   136  	mp, cleanup := newMempoolWithApp(cc)
   137  	defer cleanup()
   138  
   139  	// Ensure gas calculation behaves as expected
   140  	checkTxs(t, mp, 1)
   141  	tx0 := mp.TxsFront().Value.(*mempoolTx)
   142  	require.Equal(t, tx0.gasWanted, int64(1), "transactions gas was set incorrectly")
   143  	// ensure each tx is 20 bytes long
   144  	require.Equal(t, len(tx0.tx), 20, "Tx is longer than 20 bytes")
   145  	mp.Flush()
   146  
   147  	// each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs.
   148  	// each tx has 20 bytes
   149  	tests := []struct {
   150  		numTxsToCreate int
   151  		maxBytes       int64
   152  		maxGas         int64
   153  		expectedNumTxs int
   154  	}{
   155  		{20, -1, -1, 20},
   156  		{20, -1, 0, 0},
   157  		{20, -1, 10, 10},
   158  		{20, -1, 30, 20},
   159  		{20, 0, -1, 0},
   160  		{20, 0, 10, 0},
   161  		{20, 10, 10, 0},
   162  		{20, 24, 10, 1},
   163  		{20, 240, 5, 5},
   164  		{20, 240, -1, 10},
   165  		{20, 240, 10, 10},
   166  		{20, 240, 15, 10},
   167  		{20, 20000, -1, 20},
   168  		{20, 20000, 5, 5},
   169  		{20, 20000, 30, 20},
   170  	}
   171  	for tcIndex, tt := range tests {
   172  		checkTxs(t, mp, tt.numTxsToCreate)
   173  		got := mp.ReapMaxBytesMaxGas(tt.maxBytes, tt.maxGas)
   174  		assert.Equal(t, tt.expectedNumTxs, len(got), "Got %d txs, expected %d, tc #%d",
   175  			len(got), tt.expectedNumTxs, tcIndex)
   176  		mp.Flush()
   177  	}
   178  }
   179  
   180  func TestMempoolFilters(t *testing.T) {
   181  	app := kvstore.NewInMemoryApplication()
   182  	cc := proxy.NewLocalClientCreator(app)
   183  	mp, cleanup := newMempoolWithApp(cc)
   184  	defer cleanup()
   185  	emptyTxArr := []types.Tx{[]byte{}}
   186  
   187  	nopPreFilter := func(tx types.Tx) error { return nil }
   188  	nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) error { return nil }
   189  
   190  	// each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs.
   191  	// each tx has 20 bytes
   192  	tests := []struct {
   193  		numTxsToCreate int
   194  		preFilter      PreCheckFunc
   195  		postFilter     PostCheckFunc
   196  		expectedNumTxs int
   197  	}{
   198  		{10, nopPreFilter, nopPostFilter, 10},
   199  		{10, PreCheckMaxBytes(10), nopPostFilter, 0},
   200  		{10, PreCheckMaxBytes(22), nopPostFilter, 10},
   201  		{10, nopPreFilter, PostCheckMaxGas(-1), 10},
   202  		{10, nopPreFilter, PostCheckMaxGas(0), 0},
   203  		{10, nopPreFilter, PostCheckMaxGas(1), 10},
   204  		{10, nopPreFilter, PostCheckMaxGas(3000), 10},
   205  		{10, PreCheckMaxBytes(10), PostCheckMaxGas(20), 0},
   206  		{10, PreCheckMaxBytes(30), PostCheckMaxGas(20), 10},
   207  		{10, PreCheckMaxBytes(22), PostCheckMaxGas(1), 10},
   208  		{10, PreCheckMaxBytes(22), PostCheckMaxGas(0), 0},
   209  	}
   210  	for tcIndex, tt := range tests {
   211  		err := mp.Update(1, emptyTxArr, abciResponses(len(emptyTxArr), abci.CodeTypeOK), tt.preFilter, tt.postFilter)
   212  		require.NoError(t, err)
   213  		checkTxs(t, mp, tt.numTxsToCreate)
   214  		require.Equal(t, tt.expectedNumTxs, mp.Size(), "mempool had the incorrect size, on test case %d", tcIndex)
   215  		mp.Flush()
   216  	}
   217  }
   218  
   219  func TestMempoolUpdate(t *testing.T) {
   220  	app := kvstore.NewInMemoryApplication()
   221  	cc := proxy.NewLocalClientCreator(app)
   222  	mp, cleanup := newMempoolWithApp(cc)
   223  	defer cleanup()
   224  
   225  	// 1. Adds valid txs to the cache
   226  	{
   227  		tx1 := kvstore.NewTxFromID(1)
   228  		err := mp.Update(1, []types.Tx{tx1}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   229  		require.NoError(t, err)
   230  		_, err = mp.CheckTx(tx1)
   231  		if assert.Error(t, err) {
   232  			assert.Equal(t, ErrTxInCache, err)
   233  		}
   234  	}
   235  
   236  	// 2. Removes valid txs from the mempool
   237  	{
   238  		tx2 := kvstore.NewTxFromID(2)
   239  		_, err := mp.CheckTx(tx2)
   240  		require.NoError(t, err)
   241  		err = mp.Update(1, []types.Tx{tx2}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   242  		require.NoError(t, err)
   243  		assert.Zero(t, mp.Size())
   244  	}
   245  
   246  	// 3. Removes invalid transactions from the cache and the mempool (if present)
   247  	{
   248  		tx3 := kvstore.NewTxFromID(3)
   249  		_, err := mp.CheckTx(tx3)
   250  		require.NoError(t, err)
   251  		err = mp.Update(1, []types.Tx{tx3}, abciResponses(1, 1), nil, nil)
   252  		require.NoError(t, err)
   253  		assert.Zero(t, mp.Size())
   254  
   255  		_, err = mp.CheckTx(tx3)
   256  		require.NoError(t, err)
   257  	}
   258  }
   259  
   260  func TestMempoolUpdateDoesNotPanicWhenApplicationMissedTx(t *testing.T) {
   261  	var callback abciclient.Callback
   262  	mockClient := new(abciclimocks.Client)
   263  	mockClient.On("Start").Return(nil)
   264  	mockClient.On("SetLogger", mock.Anything)
   265  
   266  	mockClient.On("Error").Return(nil).Times(4)
   267  	mockClient.On("SetResponseCallback", mock.MatchedBy(func(cb abciclient.Callback) bool { callback = cb; return true }))
   268  
   269  	mp, cleanup, err := newMempoolWithAppMock(mockClient)
   270  	require.NoError(t, err)
   271  	defer cleanup()
   272  
   273  	// Add 4 transactions to the mempool by calling the mempool's `CheckTx` on each of them.
   274  	txs := []types.Tx{[]byte{0x01}, []byte{0x02}, []byte{0x03}, []byte{0x04}}
   275  	for _, tx := range txs {
   276  		reqRes := abciclient.NewReqRes(abci.ToRequestCheckTx(&abci.RequestCheckTx{Tx: tx}))
   277  		reqRes.Response = abci.ToResponseCheckTx(&abci.ResponseCheckTx{Code: abci.CodeTypeOK})
   278  
   279  		mockClient.On("CheckTxAsync", mock.Anything, mock.Anything).Return(reqRes, nil)
   280  		_, err := mp.CheckTx(tx)
   281  		require.NoError(t, err)
   282  
   283  		// ensure that the callback that the mempool sets on the ReqRes is run.
   284  		reqRes.InvokeCallback()
   285  	}
   286  
   287  	// Calling update to remove the first transaction from the mempool.
   288  	// This call also triggers the mempool to recheck its remaining transactions.
   289  	err = mp.Update(0, []types.Tx{txs[0]}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   290  	require.Nil(t, err)
   291  
   292  	// The mempool has now sent its requests off to the client to be rechecked
   293  	// and is waiting for the corresponding callbacks to be called.
   294  	// We now call the mempool-supplied callback on the first and third transaction.
   295  	// This simulates the client dropping the second request.
   296  	// Previous versions of this code panicked when the ABCI application missed
   297  	// a recheck-tx request.
   298  	resp := &abci.ResponseCheckTx{Code: abci.CodeTypeOK}
   299  	req := &abci.RequestCheckTx{Tx: txs[1]}
   300  	callback(abci.ToRequestCheckTx(req), abci.ToResponseCheckTx(resp))
   301  
   302  	req = &abci.RequestCheckTx{Tx: txs[3]}
   303  	callback(abci.ToRequestCheckTx(req), abci.ToResponseCheckTx(resp))
   304  	mockClient.AssertExpectations(t)
   305  }
   306  
   307  func TestMempool_KeepInvalidTxsInCache(t *testing.T) {
   308  	app := kvstore.NewInMemoryApplication()
   309  	cc := proxy.NewLocalClientCreator(app)
   310  	wcfg := config.DefaultConfig()
   311  	wcfg.Mempool.KeepInvalidTxsInCache = true
   312  	mp, cleanup := newMempoolWithAppAndConfig(cc, wcfg)
   313  	defer cleanup()
   314  
   315  	// 1. An invalid transaction must remain in the cache after Update
   316  	{
   317  		a := make([]byte, 8)
   318  		binary.BigEndian.PutUint64(a, 0)
   319  
   320  		b := make([]byte, 8)
   321  		binary.BigEndian.PutUint64(b, 1)
   322  
   323  		_, err := mp.CheckTx(b)
   324  		require.NoError(t, err)
   325  
   326  		// simulate new block
   327  		_, err = app.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{
   328  			Txs: [][]byte{a, b},
   329  		})
   330  		require.NoError(t, err)
   331  		err = mp.Update(1, []types.Tx{a, b},
   332  			[]*abci.ExecTxResult{{Code: abci.CodeTypeOK}, {Code: 2}}, nil, nil)
   333  		require.NoError(t, err)
   334  
   335  		// a must be added to the cache
   336  		_, err = mp.CheckTx(a)
   337  		if assert.Error(t, err) {
   338  			assert.Equal(t, ErrTxInCache, err)
   339  		}
   340  
   341  		// b must remain in the cache
   342  		_, err = mp.CheckTx(b)
   343  		if assert.Error(t, err) {
   344  			assert.Equal(t, ErrTxInCache, err)
   345  		}
   346  	}
   347  
   348  	// 2. An invalid transaction must remain in the cache
   349  	{
   350  		a := make([]byte, 8)
   351  		binary.BigEndian.PutUint64(a, 0)
   352  
   353  		// remove a from the cache to test (2)
   354  		mp.cache.Remove(a)
   355  
   356  		_, err := mp.CheckTx(a)
   357  		require.NoError(t, err)
   358  	}
   359  }
   360  
   361  func TestTxsAvailable(t *testing.T) {
   362  	app := kvstore.NewInMemoryApplication()
   363  	cc := proxy.NewLocalClientCreator(app)
   364  	mp, cleanup := newMempoolWithApp(cc)
   365  	defer cleanup()
   366  	mp.EnableTxsAvailable()
   367  
   368  	timeoutMS := 500
   369  
   370  	// with no txs, it shouldnt fire
   371  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   372  
   373  	// send a bunch of txs, it should only fire once
   374  	txs := checkTxs(t, mp, 100)
   375  	ensureFire(t, mp.TxsAvailable(), timeoutMS)
   376  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   377  
   378  	// call update with half the txs.
   379  	// it should fire once now for the new height
   380  	// since there are still txs left
   381  	committedTxs, remainingTxs := txs[:50], txs[50:]
   382  	if err := mp.Update(1, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil {
   383  		t.Error(err)
   384  	}
   385  	ensureFire(t, mp.TxsAvailable(), timeoutMS)
   386  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   387  
   388  	// send a bunch more txs. we already fired for this height so it shouldnt fire again
   389  	moreTxs := checkTxs(t, mp, 50)
   390  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   391  
   392  	// now call update with all the txs. it should not fire as there are no txs left
   393  	committedTxs = append(remainingTxs, moreTxs...)
   394  	if err := mp.Update(2, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil {
   395  		t.Error(err)
   396  	}
   397  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   398  
   399  	// send a bunch more txs, it should only fire once
   400  	checkTxs(t, mp, 100)
   401  	ensureFire(t, mp.TxsAvailable(), timeoutMS)
   402  	ensureNoFire(t, mp.TxsAvailable(), timeoutMS)
   403  }
   404  
   405  func TestSerialReap(t *testing.T) {
   406  	app := kvstore.NewInMemoryApplication()
   407  	cc := proxy.NewLocalClientCreator(app)
   408  
   409  	mp, cleanup := newMempoolWithApp(cc)
   410  	defer cleanup()
   411  
   412  	appConnCon, _ := cc.NewABCIClient()
   413  	appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus"))
   414  	err := appConnCon.Start()
   415  	require.Nil(t, err)
   416  
   417  	cacheMap := make(map[string]struct{})
   418  	deliverTxsRange := func(start, end int) {
   419  		// Deliver some txs.
   420  		for i := start; i < end; i++ {
   421  			txBytes := kvstore.NewTx(fmt.Sprintf("%d", i), "true")
   422  			_, err := mp.CheckTx(txBytes)
   423  			_, cached := cacheMap[string(txBytes)]
   424  			if cached {
   425  				require.NotNil(t, err, "expected error for cached tx")
   426  			} else {
   427  				require.Nil(t, err, "expected no err for uncached tx")
   428  			}
   429  			cacheMap[string(txBytes)] = struct{}{}
   430  
   431  			// Duplicates are cached and should return error
   432  			_, err = mp.CheckTx(txBytes)
   433  			require.NotNil(t, err, "Expected error after CheckTx on duplicated tx")
   434  		}
   435  	}
   436  
   437  	reapCheck := func(exp int) {
   438  		txs := mp.ReapMaxBytesMaxGas(-1, -1)
   439  		require.Equal(t, len(txs), exp, fmt.Sprintf("Expected to reap %v txs but got %v", exp, len(txs)))
   440  	}
   441  
   442  	updateRange := func(start, end int) {
   443  		txs := make(types.Txs, end-start)
   444  		for i := start; i < end; i++ {
   445  			txs[i-start] = kvstore.NewTx(fmt.Sprintf("%d", i), "true")
   446  		}
   447  		if err := mp.Update(0, txs, abciResponses(len(txs), abci.CodeTypeOK), nil, nil); err != nil {
   448  			t.Error(err)
   449  		}
   450  	}
   451  
   452  	commitRange := func(start, end int) {
   453  		// Deliver some txs in a block
   454  		txs := make([][]byte, end-start)
   455  		for i := start; i < end; i++ {
   456  			txs[i-start] = kvstore.NewTx(fmt.Sprintf("%d", i), "true")
   457  		}
   458  
   459  		res, err := appConnCon.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{Txs: txs})
   460  		if err != nil {
   461  			t.Errorf("client error committing tx: %v", err)
   462  		}
   463  		for _, txResult := range res.TxResults {
   464  			if txResult.IsErr() {
   465  				t.Errorf("error committing tx. Code:%v result:%X log:%v",
   466  					txResult.Code, txResult.Data, txResult.Log)
   467  			}
   468  		}
   469  		if len(res.AppHash) != 8 {
   470  			t.Errorf("error committing. Hash:%X", res.AppHash)
   471  		}
   472  
   473  		_, err = appConnCon.Commit(context.Background(), &abci.RequestCommit{})
   474  		if err != nil {
   475  			t.Errorf("client error committing: %v", err)
   476  		}
   477  	}
   478  
   479  	//----------------------------------------
   480  
   481  	// Deliver some txs.
   482  	deliverTxsRange(0, 100)
   483  
   484  	// Reap the txs.
   485  	reapCheck(100)
   486  
   487  	// Reap again.  We should get the same amount
   488  	reapCheck(100)
   489  
   490  	// Deliver 0 to 999, we should reap 900 new txs
   491  	// because 100 were already counted.
   492  	deliverTxsRange(0, 1000)
   493  
   494  	// Reap the txs.
   495  	reapCheck(1000)
   496  
   497  	// Reap again.  We should get the same amount
   498  	reapCheck(1000)
   499  
   500  	// Commit from the conensus AppConn
   501  	commitRange(0, 500)
   502  	updateRange(0, 500)
   503  
   504  	// We should have 500 left.
   505  	reapCheck(500)
   506  
   507  	// Deliver 100 invalid txs and 100 valid txs
   508  	deliverTxsRange(900, 1100)
   509  
   510  	// We should have 600 now.
   511  	reapCheck(600)
   512  }
   513  
   514  func TestMempool_CheckTxChecksTxSize(t *testing.T) {
   515  	app := kvstore.NewInMemoryApplication()
   516  	cc := proxy.NewLocalClientCreator(app)
   517  
   518  	mempl, cleanup := newMempoolWithApp(cc)
   519  	defer cleanup()
   520  
   521  	maxTxSize := mempl.config.MaxTxBytes
   522  
   523  	testCases := []struct {
   524  		len int
   525  		err bool
   526  	}{
   527  		// check small txs. no error
   528  		0: {10, false},
   529  		1: {1000, false},
   530  		2: {1000000, false},
   531  
   532  		// check around maxTxSize
   533  		3: {maxTxSize - 1, false},
   534  		4: {maxTxSize, false},
   535  		5: {maxTxSize + 1, true},
   536  	}
   537  
   538  	for i, testCase := range testCases {
   539  		caseString := fmt.Sprintf("case %d, len %d", i, testCase.len)
   540  
   541  		tx := cmtrand.Bytes(testCase.len)
   542  
   543  		_, err := mempl.CheckTx(tx)
   544  		bv := gogotypes.BytesValue{Value: tx}
   545  		bz, err2 := bv.Marshal()
   546  		require.NoError(t, err2)
   547  		require.Equal(t, len(bz), proto.Size(&bv), caseString)
   548  
   549  		if !testCase.err {
   550  			require.NoError(t, err, caseString)
   551  		} else {
   552  			require.Equal(t, err, ErrTxTooLarge{
   553  				Max:    maxTxSize,
   554  				Actual: testCase.len,
   555  			}, caseString)
   556  		}
   557  	}
   558  }
   559  
   560  func TestMempoolTxsBytes(t *testing.T) {
   561  	app := kvstore.NewInMemoryApplication()
   562  	cc := proxy.NewLocalClientCreator(app)
   563  
   564  	cfg := test.ResetTestRoot("mempool_test")
   565  
   566  	cfg.Mempool.MaxTxsBytes = 100
   567  	mp, cleanup := newMempoolWithAppAndConfig(cc, cfg)
   568  	defer cleanup()
   569  
   570  	// 1. zero by default
   571  	assert.EqualValues(t, 0, mp.SizeBytes())
   572  
   573  	// 2. len(tx) after CheckTx
   574  	tx1 := kvstore.NewRandomTx(10)
   575  	_, err := mp.CheckTx(tx1)
   576  	require.NoError(t, err)
   577  	assert.EqualValues(t, 10, mp.SizeBytes())
   578  
   579  	// 3. zero again after tx is removed by Update
   580  	err = mp.Update(1, []types.Tx{tx1}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   581  	require.NoError(t, err)
   582  	assert.EqualValues(t, 0, mp.SizeBytes())
   583  
   584  	// 4. zero after Flush
   585  	tx2 := kvstore.NewRandomTx(20)
   586  	_, err = mp.CheckTx(tx2)
   587  	require.NoError(t, err)
   588  	assert.EqualValues(t, 20, mp.SizeBytes())
   589  
   590  	mp.Flush()
   591  	assert.EqualValues(t, 0, mp.SizeBytes())
   592  
   593  	// 5. ErrMempoolIsFull is returned when/if MaxTxsBytes limit is reached.
   594  	tx3 := kvstore.NewRandomTx(100)
   595  	_, err = mp.CheckTx(tx3)
   596  	require.NoError(t, err)
   597  
   598  	tx4 := kvstore.NewRandomTx(10)
   599  	_, err = mp.CheckTx(tx4)
   600  	if assert.Error(t, err) {
   601  		assert.IsType(t, ErrMempoolIsFull{}, err)
   602  	}
   603  
   604  	// 6. zero after tx is rechecked and removed due to not being valid anymore
   605  	app2 := kvstore.NewInMemoryApplication()
   606  	cc = proxy.NewLocalClientCreator(app2)
   607  
   608  	mp, cleanup = newMempoolWithApp(cc)
   609  	defer cleanup()
   610  
   611  	txBytes := kvstore.NewRandomTx(10)
   612  
   613  	_, err = mp.CheckTx(txBytes)
   614  	require.NoError(t, err)
   615  	assert.EqualValues(t, 10, mp.SizeBytes())
   616  
   617  	appConnCon, _ := cc.NewABCIClient()
   618  	appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus"))
   619  	err = appConnCon.Start()
   620  	require.Nil(t, err)
   621  	t.Cleanup(func() {
   622  		if err := appConnCon.Stop(); err != nil {
   623  			t.Error(err)
   624  		}
   625  	})
   626  
   627  	res, err := appConnCon.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{Txs: [][]byte{txBytes}})
   628  	require.NoError(t, err)
   629  	require.EqualValues(t, 0, res.TxResults[0].Code)
   630  	require.NotEmpty(t, res.AppHash)
   631  
   632  	_, err = appConnCon.Commit(context.Background(), &abci.RequestCommit{})
   633  	require.NoError(t, err)
   634  
   635  	// Pretend like we committed nothing so txBytes gets rechecked and removed.
   636  	err = mp.Update(1, []types.Tx{}, abciResponses(0, abci.CodeTypeOK), nil, nil)
   637  	require.NoError(t, err)
   638  	assert.EqualValues(t, 10, mp.SizeBytes())
   639  
   640  	// 7. Test RemoveTxByKey function
   641  	_, err = mp.CheckTx(tx1)
   642  	require.NoError(t, err)
   643  	assert.EqualValues(t, 20, mp.SizeBytes())
   644  	assert.Error(t, mp.RemoveTxByKey(types.Tx([]byte{0x07}).Key()))
   645  	assert.EqualValues(t, 20, mp.SizeBytes())
   646  	assert.NoError(t, mp.RemoveTxByKey(types.Tx(tx1).Key()))
   647  	assert.EqualValues(t, 10, mp.SizeBytes())
   648  }
   649  
   650  func TestMempoolNoCacheOverflow(t *testing.T) {
   651  	sockPath := fmt.Sprintf("unix:///tmp/echo_%v.sock", cmtrand.Str(6))
   652  	app := kvstore.NewInMemoryApplication()
   653  	_, server := newRemoteApp(t, sockPath, app)
   654  	t.Cleanup(func() {
   655  		if err := server.Stop(); err != nil {
   656  			t.Error(err)
   657  		}
   658  	})
   659  	cfg := test.ResetTestRoot("mempool_test")
   660  	mp, cleanup := newMempoolWithAppAndConfig(proxy.NewRemoteClientCreator(sockPath, "socket", true), cfg)
   661  	defer cleanup()
   662  
   663  	// add tx0
   664  	var tx0 = kvstore.NewTxFromID(0)
   665  	_, err := mp.CheckTx(tx0)
   666  	require.NoError(t, err)
   667  	err = mp.FlushAppConn()
   668  	require.NoError(t, err)
   669  
   670  	// saturate the cache to remove tx0
   671  	for i := 1; i <= mp.config.CacheSize; i++ {
   672  		_, err = mp.CheckTx(kvstore.NewTxFromID(i))
   673  		require.NoError(t, err)
   674  	}
   675  	err = mp.FlushAppConn()
   676  	require.NoError(t, err)
   677  	assert.False(t, mp.cache.Has(kvstore.NewTxFromID(0)))
   678  
   679  	// add again tx0
   680  	_, err = mp.CheckTx(tx0)
   681  	require.NoError(t, err)
   682  	err = mp.FlushAppConn()
   683  	require.NoError(t, err)
   684  
   685  	// tx0 should appear only once in mp.txs
   686  	found := 0
   687  	for e := mp.txs.Front(); e != nil; e = e.Next() {
   688  		if types.Tx.Key(e.Value.(*mempoolTx).tx) == types.Tx.Key(tx0) {
   689  			found++
   690  		}
   691  	}
   692  	assert.True(t, found == 1)
   693  }
   694  
   695  // This will non-deterministically catch some concurrency failures like
   696  // https://github.com/tendermint/tendermint/issues/3509
   697  // TODO: all of the tests should probably also run using the remote proxy app
   698  // since otherwise we're not actually testing the concurrency of the mempool here!
   699  func TestMempoolRemoteAppConcurrency(t *testing.T) {
   700  	sockPath := fmt.Sprintf("unix:///tmp/echo_%v.sock", cmtrand.Str(6))
   701  	app := kvstore.NewInMemoryApplication()
   702  	_, server := newRemoteApp(t, sockPath, app)
   703  	t.Cleanup(func() {
   704  		if err := server.Stop(); err != nil {
   705  			t.Error(err)
   706  		}
   707  	})
   708  
   709  	cfg := test.ResetTestRoot("mempool_test")
   710  
   711  	mp, cleanup := newMempoolWithAppAndConfig(proxy.NewRemoteClientCreator(sockPath, "socket", true), cfg)
   712  	defer cleanup()
   713  
   714  	// generate small number of txs
   715  	nTxs := 10
   716  	txLen := 200
   717  	txs := NewRandomTxs(nTxs, txLen)
   718  
   719  	// simulate a group of peers sending them over and over
   720  	N := cfg.Mempool.Size
   721  	for i := 0; i < N; i++ {
   722  		txNum := mrand.Intn(nTxs)
   723  		tx := txs[txNum]
   724  
   725  		// this will err with ErrTxInCache many times ...
   726  		mp.CheckTx(tx) //nolint: errcheck // will error
   727  	}
   728  
   729  	require.NoError(t, mp.FlushAppConn())
   730  }
   731  
   732  // caller must close server
   733  func newRemoteApp(t *testing.T, addr string, app abci.Application) (abciclient.Client, service.Service) {
   734  	clientCreator, err := abciclient.NewClient(addr, "socket", true)
   735  	require.NoError(t, err)
   736  
   737  	// Start server
   738  	server := abciserver.NewSocketServer(addr, app)
   739  	server.SetLogger(log.TestingLogger().With("module", "abci-server"))
   740  	if err := server.Start(); err != nil {
   741  		t.Fatalf("Error starting socket server: %v", err.Error())
   742  	}
   743  
   744  	return clientCreator, server
   745  }
   746  
   747  func abciResponses(n int, code uint32) []*abci.ExecTxResult {
   748  	responses := make([]*abci.ExecTxResult, 0, n)
   749  	for i := 0; i < n; i++ {
   750  		responses = append(responses, &abci.ExecTxResult{Code: code})
   751  	}
   752  	return responses
   753  }
   754  
   755  func doCommit(t require.TestingT, mp Mempool, app abci.Application, txs types.Txs, height int64) {
   756  	rfb := &abci.RequestFinalizeBlock{Txs: make([][]byte, len(txs))}
   757  	for i, tx := range txs {
   758  		rfb.Txs[i] = tx
   759  	}
   760  	_, e := app.FinalizeBlock(context.Background(), rfb)
   761  	require.True(t, e == nil)
   762  	mp.Lock()
   763  	e = mp.FlushAppConn()
   764  	require.True(t, e == nil)
   765  	_, e = app.Commit(context.Background(), &abci.RequestCommit{})
   766  	require.True(t, e == nil)
   767  	e = mp.Update(height, txs, abciResponses(txs.Len(), abci.CodeTypeOK), nil, nil)
   768  	require.True(t, e == nil)
   769  	mp.Unlock()
   770  }