github.com/DFWallet/tendermint-cosmos@v0.0.2/mempool/clist_mempool_test.go (about)

     1  package mempool
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/sha256"
     6  	"encoding/binary"
     7  	"fmt"
     8  	"io/ioutil"
     9  	mrand "math/rand"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/gogo/protobuf/proto"
    16  	gogotypes "github.com/gogo/protobuf/types"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  
    20  	"github.com/DFWallet/tendermint-cosmos/abci/example/counter"
    21  	"github.com/DFWallet/tendermint-cosmos/abci/example/kvstore"
    22  	abciserver "github.com/DFWallet/tendermint-cosmos/abci/server"
    23  	abci "github.com/DFWallet/tendermint-cosmos/abci/types"
    24  	cfg "github.com/DFWallet/tendermint-cosmos/config"
    25  	"github.com/DFWallet/tendermint-cosmos/libs/log"
    26  	tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand"
    27  	"github.com/DFWallet/tendermint-cosmos/libs/service"
    28  	"github.com/DFWallet/tendermint-cosmos/proxy"
    29  	"github.com/DFWallet/tendermint-cosmos/types"
    30  )
    31  
    32  // A cleanupFunc cleans up any config / test files created for a particular
    33  // test.
    34  type cleanupFunc func()
    35  
    36  func newMempoolWithApp(cc proxy.ClientCreator) (*CListMempool, cleanupFunc) {
    37  	return newMempoolWithAppAndConfig(cc, cfg.ResetTestRoot("mempool_test"))
    38  }
    39  
    40  func newMempoolWithAppAndConfig(cc proxy.ClientCreator, config *cfg.Config) (*CListMempool, cleanupFunc) {
    41  	appConnMem, _ := cc.NewABCIClient()
    42  	appConnMem.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "mempool"))
    43  	err := appConnMem.Start()
    44  	if err != nil {
    45  		panic(err)
    46  	}
    47  	mempool := NewCListMempool(config.Mempool, appConnMem, 0)
    48  	mempool.SetLogger(log.TestingLogger())
    49  	return mempool, func() { os.RemoveAll(config.RootDir) }
    50  }
    51  
    52  func ensureNoFire(t *testing.T, ch <-chan struct{}, timeoutMS int) {
    53  	timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond)
    54  	select {
    55  	case <-ch:
    56  		t.Fatal("Expected not to fire")
    57  	case <-timer.C:
    58  	}
    59  }
    60  
    61  func ensureFire(t *testing.T, ch <-chan struct{}, timeoutMS int) {
    62  	timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond)
    63  	select {
    64  	case <-ch:
    65  	case <-timer.C:
    66  		t.Fatal("Expected to fire")
    67  	}
    68  }
    69  
    70  func checkTxs(t *testing.T, mempool Mempool, count int, peerID uint16) types.Txs {
    71  	txs := make(types.Txs, count)
    72  	txInfo := TxInfo{SenderID: peerID}
    73  	for i := 0; i < count; i++ {
    74  		txBytes := make([]byte, 20)
    75  		txs[i] = txBytes
    76  		_, err := rand.Read(txBytes)
    77  		if err != nil {
    78  			t.Error(err)
    79  		}
    80  		if err := mempool.CheckTx(txBytes, nil, txInfo); err != nil {
    81  			// Skip invalid txs.
    82  			// TestMempoolFilters will fail otherwise. It asserts a number of txs
    83  			// returned.
    84  			if IsPreCheckError(err) {
    85  				continue
    86  			}
    87  			t.Fatalf("CheckTx failed: %v while checking #%d tx", err, i)
    88  		}
    89  	}
    90  	return txs
    91  }
    92  
    93  func TestReapMaxBytesMaxGas(t *testing.T) {
    94  	app := kvstore.NewApplication()
    95  	cc := proxy.NewLocalClientCreator(app)
    96  	mempool, cleanup := newMempoolWithApp(cc)
    97  	defer cleanup()
    98  
    99  	// Ensure gas calculation behaves as expected
   100  	checkTxs(t, mempool, 1, UnknownPeerID)
   101  	tx0 := mempool.TxsFront().Value.(*mempoolTx)
   102  	// assert that kv store has gas wanted = 1.
   103  	require.Equal(t, app.CheckTx(abci.RequestCheckTx{Tx: tx0.tx}).GasWanted, int64(1), "KVStore had a gas value neq to 1")
   104  	require.Equal(t, tx0.gasWanted, int64(1), "transactions gas was set incorrectly")
   105  	// ensure each tx is 20 bytes long
   106  	require.Equal(t, len(tx0.tx), 20, "Tx is longer than 20 bytes")
   107  	mempool.Flush()
   108  
   109  	// each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs.
   110  	// each tx has 20 bytes
   111  	tests := []struct {
   112  		numTxsToCreate int
   113  		maxBytes       int64
   114  		maxGas         int64
   115  		expectedNumTxs int
   116  	}{
   117  		{20, -1, -1, 20},
   118  		{20, -1, 0, 0},
   119  		{20, -1, 10, 10},
   120  		{20, -1, 30, 20},
   121  		{20, 0, -1, 0},
   122  		{20, 0, 10, 0},
   123  		{20, 10, 10, 0},
   124  		{20, 24, 10, 1},
   125  		{20, 240, 5, 5},
   126  		{20, 240, -1, 10},
   127  		{20, 240, 10, 10},
   128  		{20, 240, 15, 10},
   129  		{20, 20000, -1, 20},
   130  		{20, 20000, 5, 5},
   131  		{20, 20000, 30, 20},
   132  	}
   133  	for tcIndex, tt := range tests {
   134  		checkTxs(t, mempool, tt.numTxsToCreate, UnknownPeerID)
   135  		got := mempool.ReapMaxBytesMaxGas(tt.maxBytes, tt.maxGas)
   136  		assert.Equal(t, tt.expectedNumTxs, len(got), "Got %d txs, expected %d, tc #%d",
   137  			len(got), tt.expectedNumTxs, tcIndex)
   138  		mempool.Flush()
   139  	}
   140  }
   141  
   142  func TestMempoolFilters(t *testing.T) {
   143  	app := kvstore.NewApplication()
   144  	cc := proxy.NewLocalClientCreator(app)
   145  	mempool, cleanup := newMempoolWithApp(cc)
   146  	defer cleanup()
   147  	emptyTxArr := []types.Tx{[]byte{}}
   148  
   149  	nopPreFilter := func(tx types.Tx) error { return nil }
   150  	nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) error { return nil }
   151  
   152  	// each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs.
   153  	// each tx has 20 bytes
   154  	tests := []struct {
   155  		numTxsToCreate int
   156  		preFilter      PreCheckFunc
   157  		postFilter     PostCheckFunc
   158  		expectedNumTxs int
   159  	}{
   160  		{10, nopPreFilter, nopPostFilter, 10},
   161  		{10, PreCheckMaxBytes(10), nopPostFilter, 0},
   162  		{10, PreCheckMaxBytes(22), nopPostFilter, 10},
   163  		{10, nopPreFilter, PostCheckMaxGas(-1), 10},
   164  		{10, nopPreFilter, PostCheckMaxGas(0), 0},
   165  		{10, nopPreFilter, PostCheckMaxGas(1), 10},
   166  		{10, nopPreFilter, PostCheckMaxGas(3000), 10},
   167  		{10, PreCheckMaxBytes(10), PostCheckMaxGas(20), 0},
   168  		{10, PreCheckMaxBytes(30), PostCheckMaxGas(20), 10},
   169  		{10, PreCheckMaxBytes(22), PostCheckMaxGas(1), 10},
   170  		{10, PreCheckMaxBytes(22), PostCheckMaxGas(0), 0},
   171  	}
   172  	for tcIndex, tt := range tests {
   173  		err := mempool.Update(1, emptyTxArr, abciResponses(len(emptyTxArr), abci.CodeTypeOK), tt.preFilter, tt.postFilter)
   174  		require.NoError(t, err)
   175  		checkTxs(t, mempool, tt.numTxsToCreate, UnknownPeerID)
   176  		require.Equal(t, tt.expectedNumTxs, mempool.Size(), "mempool had the incorrect size, on test case %d", tcIndex)
   177  		mempool.Flush()
   178  	}
   179  }
   180  
   181  func TestMempoolUpdate(t *testing.T) {
   182  	app := kvstore.NewApplication()
   183  	cc := proxy.NewLocalClientCreator(app)
   184  	mempool, cleanup := newMempoolWithApp(cc)
   185  	defer cleanup()
   186  
   187  	// 1. Adds valid txs to the cache
   188  	{
   189  		err := mempool.Update(1, []types.Tx{[]byte{0x01}}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   190  		require.NoError(t, err)
   191  		err = mempool.CheckTx([]byte{0x01}, nil, TxInfo{})
   192  		if assert.Error(t, err) {
   193  			assert.Equal(t, ErrTxInCache, err)
   194  		}
   195  	}
   196  
   197  	// 2. Removes valid txs from the mempool
   198  	{
   199  		err := mempool.CheckTx([]byte{0x02}, nil, TxInfo{})
   200  		require.NoError(t, err)
   201  		err = mempool.Update(1, []types.Tx{[]byte{0x02}}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   202  		require.NoError(t, err)
   203  		assert.Zero(t, mempool.Size())
   204  	}
   205  
   206  	// 3. Removes invalid transactions from the cache and the mempool (if present)
   207  	{
   208  		err := mempool.CheckTx([]byte{0x03}, nil, TxInfo{})
   209  		require.NoError(t, err)
   210  		err = mempool.Update(1, []types.Tx{[]byte{0x03}}, abciResponses(1, 1), nil, nil)
   211  		require.NoError(t, err)
   212  		assert.Zero(t, mempool.Size())
   213  
   214  		err = mempool.CheckTx([]byte{0x03}, nil, TxInfo{})
   215  		require.NoError(t, err)
   216  	}
   217  }
   218  
   219  func TestMempool_KeepInvalidTxsInCache(t *testing.T) {
   220  	app := counter.NewApplication(true)
   221  	cc := proxy.NewLocalClientCreator(app)
   222  	wcfg := cfg.DefaultConfig()
   223  	wcfg.Mempool.KeepInvalidTxsInCache = true
   224  	mempool, cleanup := newMempoolWithAppAndConfig(cc, wcfg)
   225  	defer cleanup()
   226  
   227  	// 1. An invalid transaction must remain in the cache after Update
   228  	{
   229  		a := make([]byte, 8)
   230  		binary.BigEndian.PutUint64(a, 0)
   231  
   232  		b := make([]byte, 8)
   233  		binary.BigEndian.PutUint64(b, 1)
   234  
   235  		err := mempool.CheckTx(b, nil, TxInfo{})
   236  		require.NoError(t, err)
   237  
   238  		// simulate new block
   239  		_ = app.DeliverTx(abci.RequestDeliverTx{Tx: a})
   240  		_ = app.DeliverTx(abci.RequestDeliverTx{Tx: b})
   241  		err = mempool.Update(1, []types.Tx{a, b},
   242  			[]*abci.ResponseDeliverTx{{Code: abci.CodeTypeOK}, {Code: 2}}, nil, nil)
   243  		require.NoError(t, err)
   244  
   245  		// a must be added to the cache
   246  		err = mempool.CheckTx(a, nil, TxInfo{})
   247  		if assert.Error(t, err) {
   248  			assert.Equal(t, ErrTxInCache, err)
   249  		}
   250  
   251  		// b must remain in the cache
   252  		err = mempool.CheckTx(b, nil, TxInfo{})
   253  		if assert.Error(t, err) {
   254  			assert.Equal(t, ErrTxInCache, err)
   255  		}
   256  	}
   257  
   258  	// 2. An invalid transaction must remain in the cache
   259  	{
   260  		a := make([]byte, 8)
   261  		binary.BigEndian.PutUint64(a, 0)
   262  
   263  		// remove a from the cache to test (2)
   264  		mempool.cache.Remove(a)
   265  
   266  		err := mempool.CheckTx(a, nil, TxInfo{})
   267  		require.NoError(t, err)
   268  
   269  		err = mempool.CheckTx(a, nil, TxInfo{})
   270  		if assert.Error(t, err) {
   271  			assert.Equal(t, ErrTxInCache, err)
   272  		}
   273  	}
   274  }
   275  
   276  func TestTxsAvailable(t *testing.T) {
   277  	app := kvstore.NewApplication()
   278  	cc := proxy.NewLocalClientCreator(app)
   279  	mempool, cleanup := newMempoolWithApp(cc)
   280  	defer cleanup()
   281  	mempool.EnableTxsAvailable()
   282  
   283  	timeoutMS := 500
   284  
   285  	// with no txs, it shouldnt fire
   286  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   287  
   288  	// send a bunch of txs, it should only fire once
   289  	txs := checkTxs(t, mempool, 100, UnknownPeerID)
   290  	ensureFire(t, mempool.TxsAvailable(), timeoutMS)
   291  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   292  
   293  	// call update with half the txs.
   294  	// it should fire once now for the new height
   295  	// since there are still txs left
   296  	committedTxs, txs := txs[:50], txs[50:]
   297  	if err := mempool.Update(1, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil {
   298  		t.Error(err)
   299  	}
   300  	ensureFire(t, mempool.TxsAvailable(), timeoutMS)
   301  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   302  
   303  	// send a bunch more txs. we already fired for this height so it shouldnt fire again
   304  	moreTxs := checkTxs(t, mempool, 50, UnknownPeerID)
   305  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   306  
   307  	// now call update with all the txs. it should not fire as there are no txs left
   308  	committedTxs = append(txs, moreTxs...) //nolint: gocritic
   309  	if err := mempool.Update(2, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil {
   310  		t.Error(err)
   311  	}
   312  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   313  
   314  	// send a bunch more txs, it should only fire once
   315  	checkTxs(t, mempool, 100, UnknownPeerID)
   316  	ensureFire(t, mempool.TxsAvailable(), timeoutMS)
   317  	ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
   318  }
   319  
   320  func TestSerialReap(t *testing.T) {
   321  	app := counter.NewApplication(true)
   322  	app.SetOption(abci.RequestSetOption{Key: "serial", Value: "on"})
   323  	cc := proxy.NewLocalClientCreator(app)
   324  
   325  	mempool, cleanup := newMempoolWithApp(cc)
   326  	defer cleanup()
   327  
   328  	appConnCon, _ := cc.NewABCIClient()
   329  	appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus"))
   330  	err := appConnCon.Start()
   331  	require.Nil(t, err)
   332  
   333  	cacheMap := make(map[string]struct{})
   334  	deliverTxsRange := func(start, end int) {
   335  		// Deliver some txs.
   336  		for i := start; i < end; i++ {
   337  
   338  			// This will succeed
   339  			txBytes := make([]byte, 8)
   340  			binary.BigEndian.PutUint64(txBytes, uint64(i))
   341  			err := mempool.CheckTx(txBytes, nil, TxInfo{})
   342  			_, cached := cacheMap[string(txBytes)]
   343  			if cached {
   344  				require.NotNil(t, err, "expected error for cached tx")
   345  			} else {
   346  				require.Nil(t, err, "expected no err for uncached tx")
   347  			}
   348  			cacheMap[string(txBytes)] = struct{}{}
   349  
   350  			// Duplicates are cached and should return error
   351  			err = mempool.CheckTx(txBytes, nil, TxInfo{})
   352  			require.NotNil(t, err, "Expected error after CheckTx on duplicated tx")
   353  		}
   354  	}
   355  
   356  	reapCheck := func(exp int) {
   357  		txs := mempool.ReapMaxBytesMaxGas(-1, -1)
   358  		require.Equal(t, len(txs), exp, fmt.Sprintf("Expected to reap %v txs but got %v", exp, len(txs)))
   359  	}
   360  
   361  	updateRange := func(start, end int) {
   362  		txs := make([]types.Tx, 0)
   363  		for i := start; i < end; i++ {
   364  			txBytes := make([]byte, 8)
   365  			binary.BigEndian.PutUint64(txBytes, uint64(i))
   366  			txs = append(txs, txBytes)
   367  		}
   368  		if err := mempool.Update(0, txs, abciResponses(len(txs), abci.CodeTypeOK), nil, nil); err != nil {
   369  			t.Error(err)
   370  		}
   371  	}
   372  
   373  	commitRange := func(start, end int) {
   374  		// Deliver some txs.
   375  		for i := start; i < end; i++ {
   376  			txBytes := make([]byte, 8)
   377  			binary.BigEndian.PutUint64(txBytes, uint64(i))
   378  			res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: txBytes})
   379  			if err != nil {
   380  				t.Errorf("client error committing tx: %v", err)
   381  			}
   382  			if res.IsErr() {
   383  				t.Errorf("error committing tx. Code:%v result:%X log:%v",
   384  					res.Code, res.Data, res.Log)
   385  			}
   386  		}
   387  		res, err := appConnCon.CommitSync()
   388  		if err != nil {
   389  			t.Errorf("client error committing: %v", err)
   390  		}
   391  		if len(res.Data) != 8 {
   392  			t.Errorf("error committing. Hash:%X", res.Data)
   393  		}
   394  	}
   395  
   396  	//----------------------------------------
   397  
   398  	// Deliver some txs.
   399  	deliverTxsRange(0, 100)
   400  
   401  	// Reap the txs.
   402  	reapCheck(100)
   403  
   404  	// Reap again.  We should get the same amount
   405  	reapCheck(100)
   406  
   407  	// Deliver 0 to 999, we should reap 900 new txs
   408  	// because 100 were already counted.
   409  	deliverTxsRange(0, 1000)
   410  
   411  	// Reap the txs.
   412  	reapCheck(1000)
   413  
   414  	// Reap again.  We should get the same amount
   415  	reapCheck(1000)
   416  
   417  	// Commit from the conensus AppConn
   418  	commitRange(0, 500)
   419  	updateRange(0, 500)
   420  
   421  	// We should have 500 left.
   422  	reapCheck(500)
   423  
   424  	// Deliver 100 invalid txs and 100 valid txs
   425  	deliverTxsRange(900, 1100)
   426  
   427  	// We should have 600 now.
   428  	reapCheck(600)
   429  }
   430  
   431  func TestMempoolCloseWAL(t *testing.T) {
   432  	// 1. Create the temporary directory for mempool and WAL testing.
   433  	rootDir, err := ioutil.TempDir("", "mempool-test")
   434  	require.Nil(t, err, "expecting successful tmpdir creation")
   435  
   436  	// 2. Ensure that it doesn't contain any elements -- Sanity check
   437  	m1, err := filepath.Glob(filepath.Join(rootDir, "*"))
   438  	require.Nil(t, err, "successful globbing expected")
   439  	require.Equal(t, 0, len(m1), "no matches yet")
   440  
   441  	// 3. Create the mempool
   442  	wcfg := cfg.DefaultConfig()
   443  	wcfg.Mempool.RootDir = rootDir
   444  	app := kvstore.NewApplication()
   445  	cc := proxy.NewLocalClientCreator(app)
   446  	mempool, cleanup := newMempoolWithAppAndConfig(cc, wcfg)
   447  	defer cleanup()
   448  	mempool.height = 10
   449  	err = mempool.InitWAL()
   450  	require.NoError(t, err)
   451  
   452  	// 4. Ensure that the directory contains the WAL file
   453  	m2, err := filepath.Glob(filepath.Join(rootDir, "*"))
   454  	require.Nil(t, err, "successful globbing expected")
   455  	require.Equal(t, 1, len(m2), "expecting the wal match in")
   456  
   457  	// 5. Write some contents to the WAL
   458  	err = mempool.CheckTx(types.Tx([]byte("foo")), nil, TxInfo{})
   459  	require.NoError(t, err)
   460  	walFilepath := mempool.wal.Path
   461  	sum1 := checksumFile(walFilepath, t)
   462  
   463  	// 6. Sanity check to ensure that the written TX matches the expectation.
   464  	require.Equal(t, sum1, checksumIt([]byte("foo\n")), "foo with a newline should be written")
   465  
   466  	// 7. Invoke CloseWAL() and ensure it discards the
   467  	// WAL thus any other write won't go through.
   468  	mempool.CloseWAL()
   469  	err = mempool.CheckTx(types.Tx([]byte("bar")), nil, TxInfo{})
   470  	require.NoError(t, err)
   471  	sum2 := checksumFile(walFilepath, t)
   472  	require.Equal(t, sum1, sum2, "expected no change to the WAL after invoking CloseWAL() since it was discarded")
   473  
   474  	// 8. Sanity check to ensure that the WAL file still exists
   475  	m3, err := filepath.Glob(filepath.Join(rootDir, "*"))
   476  	require.Nil(t, err, "successful globbing expected")
   477  	require.Equal(t, 1, len(m3), "expecting the wal match in")
   478  }
   479  
   480  func TestMempool_CheckTxChecksTxSize(t *testing.T) {
   481  	app := kvstore.NewApplication()
   482  	cc := proxy.NewLocalClientCreator(app)
   483  	mempl, cleanup := newMempoolWithApp(cc)
   484  	defer cleanup()
   485  
   486  	maxTxSize := mempl.config.MaxTxBytes
   487  
   488  	testCases := []struct {
   489  		len int
   490  		err bool
   491  	}{
   492  		// check small txs. no error
   493  		0: {10, false},
   494  		1: {1000, false},
   495  		2: {1000000, false},
   496  
   497  		// check around maxTxSize
   498  		3: {maxTxSize - 1, false},
   499  		4: {maxTxSize, false},
   500  		5: {maxTxSize + 1, true},
   501  	}
   502  
   503  	for i, testCase := range testCases {
   504  		caseString := fmt.Sprintf("case %d, len %d", i, testCase.len)
   505  
   506  		tx := tmrand.Bytes(testCase.len)
   507  
   508  		err := mempl.CheckTx(tx, nil, TxInfo{})
   509  		bv := gogotypes.BytesValue{Value: tx}
   510  		bz, err2 := bv.Marshal()
   511  		require.NoError(t, err2)
   512  		require.Equal(t, len(bz), proto.Size(&bv), caseString)
   513  
   514  		if !testCase.err {
   515  			require.NoError(t, err, caseString)
   516  		} else {
   517  			require.Equal(t, err, ErrTxTooLarge{maxTxSize, testCase.len}, caseString)
   518  		}
   519  	}
   520  }
   521  
   522  func TestMempoolTxsBytes(t *testing.T) {
   523  	app := kvstore.NewApplication()
   524  	cc := proxy.NewLocalClientCreator(app)
   525  	config := cfg.ResetTestRoot("mempool_test")
   526  	config.Mempool.MaxTxsBytes = 10
   527  	mempool, cleanup := newMempoolWithAppAndConfig(cc, config)
   528  	defer cleanup()
   529  
   530  	// 1. zero by default
   531  	assert.EqualValues(t, 0, mempool.TxsBytes())
   532  
   533  	// 2. len(tx) after CheckTx
   534  	err := mempool.CheckTx([]byte{0x01}, nil, TxInfo{})
   535  	require.NoError(t, err)
   536  	assert.EqualValues(t, 1, mempool.TxsBytes())
   537  
   538  	// 3. zero again after tx is removed by Update
   539  	err = mempool.Update(1, []types.Tx{[]byte{0x01}}, abciResponses(1, abci.CodeTypeOK), nil, nil)
   540  	require.NoError(t, err)
   541  	assert.EqualValues(t, 0, mempool.TxsBytes())
   542  
   543  	// 4. zero after Flush
   544  	err = mempool.CheckTx([]byte{0x02, 0x03}, nil, TxInfo{})
   545  	require.NoError(t, err)
   546  	assert.EqualValues(t, 2, mempool.TxsBytes())
   547  
   548  	mempool.Flush()
   549  	assert.EqualValues(t, 0, mempool.TxsBytes())
   550  
   551  	// 5. ErrMempoolIsFull is returned when/if MaxTxsBytes limit is reached.
   552  	err = mempool.CheckTx([]byte{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, nil, TxInfo{})
   553  	require.NoError(t, err)
   554  	err = mempool.CheckTx([]byte{0x05}, nil, TxInfo{})
   555  	if assert.Error(t, err) {
   556  		assert.IsType(t, ErrMempoolIsFull{}, err)
   557  	}
   558  
   559  	// 6. zero after tx is rechecked and removed due to not being valid anymore
   560  	app2 := counter.NewApplication(true)
   561  	cc = proxy.NewLocalClientCreator(app2)
   562  	mempool, cleanup = newMempoolWithApp(cc)
   563  	defer cleanup()
   564  
   565  	txBytes := make([]byte, 8)
   566  	binary.BigEndian.PutUint64(txBytes, uint64(0))
   567  
   568  	err = mempool.CheckTx(txBytes, nil, TxInfo{})
   569  	require.NoError(t, err)
   570  	assert.EqualValues(t, 8, mempool.TxsBytes())
   571  
   572  	appConnCon, _ := cc.NewABCIClient()
   573  	appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus"))
   574  	err = appConnCon.Start()
   575  	require.Nil(t, err)
   576  	t.Cleanup(func() {
   577  		if err := appConnCon.Stop(); err != nil {
   578  			t.Error(err)
   579  		}
   580  	})
   581  	res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: txBytes})
   582  	require.NoError(t, err)
   583  	require.EqualValues(t, 0, res.Code)
   584  	res2, err := appConnCon.CommitSync()
   585  	require.NoError(t, err)
   586  	require.NotEmpty(t, res2.Data)
   587  
   588  	// Pretend like we committed nothing so txBytes gets rechecked and removed.
   589  	err = mempool.Update(1, []types.Tx{}, abciResponses(0, abci.CodeTypeOK), nil, nil)
   590  	require.NoError(t, err)
   591  	assert.EqualValues(t, 0, mempool.TxsBytes())
   592  
   593  	// 7. Test RemoveTxByKey function
   594  	err = mempool.CheckTx([]byte{0x06}, nil, TxInfo{})
   595  	require.NoError(t, err)
   596  	assert.EqualValues(t, 1, mempool.TxsBytes())
   597  	mempool.RemoveTxByKey(TxKey([]byte{0x07}), true)
   598  	assert.EqualValues(t, 1, mempool.TxsBytes())
   599  	mempool.RemoveTxByKey(TxKey([]byte{0x06}), true)
   600  	assert.EqualValues(t, 0, mempool.TxsBytes())
   601  
   602  }
   603  
   604  // This will non-deterministically catch some concurrency failures like
   605  // https://github.com/DFWallet/tendermint-cosmos/issues/3509
   606  // TODO: all of the tests should probably also run using the remote proxy app
   607  // since otherwise we're not actually testing the concurrency of the mempool here!
   608  func TestMempoolRemoteAppConcurrency(t *testing.T) {
   609  	sockPath := fmt.Sprintf("unix:///tmp/echo_%v.sock", tmrand.Str(6))
   610  	app := kvstore.NewApplication()
   611  	cc, server := newRemoteApp(t, sockPath, app)
   612  	t.Cleanup(func() {
   613  		if err := server.Stop(); err != nil {
   614  			t.Error(err)
   615  		}
   616  	})
   617  	config := cfg.ResetTestRoot("mempool_test")
   618  	mempool, cleanup := newMempoolWithAppAndConfig(cc, config)
   619  	defer cleanup()
   620  
   621  	// generate small number of txs
   622  	nTxs := 10
   623  	txLen := 200
   624  	txs := make([]types.Tx, nTxs)
   625  	for i := 0; i < nTxs; i++ {
   626  		txs[i] = tmrand.Bytes(txLen)
   627  	}
   628  
   629  	// simulate a group of peers sending them over and over
   630  	N := config.Mempool.Size
   631  	maxPeers := 5
   632  	for i := 0; i < N; i++ {
   633  		peerID := mrand.Intn(maxPeers)
   634  		txNum := mrand.Intn(nTxs)
   635  		tx := txs[txNum]
   636  
   637  		// this will err with ErrTxInCache many times ...
   638  		mempool.CheckTx(tx, nil, TxInfo{SenderID: uint16(peerID)}) //nolint: errcheck // will error
   639  	}
   640  	err := mempool.FlushAppConn()
   641  	require.NoError(t, err)
   642  }
   643  
   644  // caller must close server
   645  func newRemoteApp(
   646  	t *testing.T,
   647  	addr string,
   648  	app abci.Application,
   649  ) (
   650  	clientCreator proxy.ClientCreator,
   651  	server service.Service,
   652  ) {
   653  	clientCreator = proxy.NewRemoteClientCreator(addr, "socket", true)
   654  
   655  	// Start server
   656  	server = abciserver.NewSocketServer(addr, app)
   657  	server.SetLogger(log.TestingLogger().With("module", "abci-server"))
   658  	if err := server.Start(); err != nil {
   659  		t.Fatalf("Error starting socket server: %v", err.Error())
   660  	}
   661  	return clientCreator, server
   662  }
   663  func checksumIt(data []byte) string {
   664  	h := sha256.New()
   665  	h.Write(data)
   666  	return fmt.Sprintf("%x", h.Sum(nil))
   667  }
   668  
   669  func checksumFile(p string, t *testing.T) string {
   670  	data, err := ioutil.ReadFile(p)
   671  	require.Nil(t, err, "expecting successful read of %q", p)
   672  	return checksumIt(data)
   673  }
   674  
   675  func abciResponses(n int, code uint32) []*abci.ResponseDeliverTx {
   676  	responses := make([]*abci.ResponseDeliverTx, 0, n)
   677  	for i := 0; i < n; i++ {
   678  		responses = append(responses, &abci.ResponseDeliverTx{Code: code})
   679  	}
   680  	return responses
   681  }