From 543929a7155222e0a7df098695cddb035e7085a8 Mon Sep 17 00:00:00 2001 From: William Banfield Date: Fri, 15 Oct 2021 14:07:56 -0400 Subject: [PATCH] add test for v0 mempool --- internal/mempool/v0/clist_mempool.go | 2 +- internal/mempool/v0/clist_mempool_test.go | 52 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/internal/mempool/v0/clist_mempool.go b/internal/mempool/v0/clist_mempool.go index 2cb69551f..0a12c7000 100644 --- a/internal/mempool/v0/clist_mempool.go +++ b/internal/mempool/v0/clist_mempool.go @@ -462,7 +462,7 @@ func (mem *CListMempool) resCbRecheck(req *abci.Request, res *abci.Response) { mem.logger.Error( "re-CheckTx transaction mismatch", - "got", tx, + "got", types.Tx(tx), "expected", memTx.tx, ) diff --git a/internal/mempool/v0/clist_mempool_test.go b/internal/mempool/v0/clist_mempool_test.go index b61a8333e..0381d576a 100644 --- a/internal/mempool/v0/clist_mempool_test.go +++ b/internal/mempool/v0/clist_mempool_test.go @@ -13,9 +13,11 @@ import ( "github.com/gogo/protobuf/proto" gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" abciclient "github.com/tendermint/tendermint/abci/client" + abciclimocks "github.com/tendermint/tendermint/abci/client/mocks" "github.com/tendermint/tendermint/abci/example/kvstore" abciserver "github.com/tendermint/tendermint/abci/server" abci "github.com/tendermint/tendermint/abci/types" @@ -214,6 +216,56 @@ func TestMempoolUpdate(t *testing.T) { } } +func TestMempoolUpdateDoesNotPanicWhenApplicationMissedTx(t *testing.T) { + var callback abciclient.Callback + mockClient := new(abciclimocks.Client) + mockClient.On("Start").Return(nil) + mockClient.On("SetLogger", mock.Anything) + + mockClient.On("Error").Return(nil).Times(4) + mockClient.On("FlushAsync", mock.Anything).Return(abciclient.NewReqRes(abci.ToRequestFlush()), nil) + mockClient.On("SetResponseCallback", mock.MatchedBy(func(cb abciclient.Callback) bool { callback = cb; return true })) + + cc := func() (abciclient.Client, error) { + return mockClient, nil + } + + mp, cleanup := newMempoolWithApp(cc) + defer cleanup() + + // Add 4 transactions to the mempool by calling the mempool's `CheckTx` on each of them. + txs := []types.Tx{[]byte{0x01}, []byte{0x02}, []byte{0x03}, []byte{0x04}} + for _, tx := range txs { + reqRes := abciclient.NewReqRes(abci.ToRequestCheckTx(abci.RequestCheckTx{Tx: tx})) + reqRes.Response = abci.ToResponseCheckTx(abci.ResponseCheckTx{Code: abci.CodeTypeOK}) + // SetDone allows the ReqRes to process its callback synchronously. + // This simulates the Response being ready for the client immediately. + reqRes.SetDone() + + mockClient.On("CheckTxAsync", mock.Anything, mock.Anything).Return(reqRes, nil) + err := mp.CheckTx(context.Background(), tx, nil, mempool.TxInfo{}) + require.NoError(t, err) + } + + // Calling update to remove the first transaction from the mempool. + // This call also triggers the mempool to recheck its remaining transactions. + err := mp.Update(0, []types.Tx{txs[0]}, abciResponses(1, abci.CodeTypeOK), nil, nil) + require.Nil(t, err) + + // The mempool has now sent its callbacks off to the client to be rechecked. + // We now call the mempool-supplied callback on the first and third transaction. + // This simulates the client dropping the second request. + // Previous versions of this code panicked when the ABCI application missed + // a recheck-tx request. + resp := abci.ResponseCheckTx{Code: abci.CodeTypeOK} + req := abci.RequestCheckTx{Tx: txs[1]} + callback(abci.ToRequestCheckTx(req), abci.ToResponseCheckTx(resp)) + + req = abci.RequestCheckTx{Tx: txs[3]} + callback(abci.ToRequestCheckTx(req), abci.ToResponseCheckTx(resp)) + mockClient.AssertExpectations(t) +} + func TestMempool_KeepInvalidTxsInCache(t *testing.T) { app := kvstore.NewApplication() cc := abciclient.NewLocalCreator(app)