github.com/PikeEcosystem/tendermint@v0.0.4/mempool/clist_mempool_test.go (about)

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