mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 04:55:18 +00:00
mempool: introduce KeepInvalidTxsInCache config option (#5813)
When set to true, an invalid transaction will be kept in the cache (this may help some applications to protect against spam). NOTE: this is a temporary config option. The more correct solution would be to add a TTL to each transaction (i.e. CheckTx may return a TTL in ResponseCheckTx). Closes: #5751
This commit is contained in:
@@ -439,8 +439,10 @@ func (mem *CListMempool) resCbFirstTime(
|
||||
mem.logger.Info("Rejected bad transaction",
|
||||
"tx", txID(tx), "peerID", peerP2PID, "res", r, "err", postCheckErr)
|
||||
mem.metrics.FailedTxs.Add(1)
|
||||
// remove from cache (it might be good later)
|
||||
mem.cache.Remove(tx)
|
||||
if !mem.config.KeepInvalidTxsInCache {
|
||||
// remove from cache (it might be good later)
|
||||
mem.cache.Remove(tx)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// ignore other messages
|
||||
@@ -472,7 +474,7 @@ func (mem *CListMempool) resCbRecheck(req *abci.Request, res *abci.Response) {
|
||||
// Tx became invalidated due to newly committed block.
|
||||
mem.logger.Info("Tx is no longer valid", "tx", txID(tx), "res", r, "err", postCheckErr)
|
||||
// NOTE: we remove tx from the cache because it might be good later
|
||||
mem.removeTx(tx, mem.recheckCursor, true)
|
||||
mem.removeTx(tx, mem.recheckCursor, !mem.config.KeepInvalidTxsInCache)
|
||||
}
|
||||
if mem.recheckCursor == mem.recheckEnd {
|
||||
mem.recheckCursor = nil
|
||||
@@ -586,7 +588,7 @@ func (mem *CListMempool) Update(
|
||||
if deliverTxResponses[i].Code == abci.CodeTypeOK {
|
||||
// Add valid committed tx to the cache (if missing).
|
||||
_ = mem.cache.Push(tx)
|
||||
} else {
|
||||
} else if !mem.config.KeepInvalidTxsInCache {
|
||||
// Allow invalid transactions to be resubmitted.
|
||||
mem.cache.Remove(tx)
|
||||
}
|
||||
|
||||
@@ -216,6 +216,63 @@ func TestMempoolUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMempool_KeepInvalidTxsInCache(t *testing.T) {
|
||||
app := counter.NewApplication(true)
|
||||
cc := proxy.NewLocalClientCreator(app)
|
||||
wcfg := cfg.DefaultConfig()
|
||||
wcfg.Mempool.KeepInvalidTxsInCache = true
|
||||
mempool, cleanup := newMempoolWithAppAndConfig(cc, wcfg)
|
||||
defer cleanup()
|
||||
|
||||
// 1. An invalid transaction must remain in the cache after Update
|
||||
{
|
||||
a := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(a, 0)
|
||||
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, 1)
|
||||
|
||||
err := mempool.CheckTx(b, nil, TxInfo{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// simulate new block
|
||||
_ = app.DeliverTx(abci.RequestDeliverTx{Tx: a})
|
||||
_ = app.DeliverTx(abci.RequestDeliverTx{Tx: b})
|
||||
err = mempool.Update(1, []types.Tx{a, b},
|
||||
[]*abci.ResponseDeliverTx{{Code: abci.CodeTypeOK}, {Code: 2}}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// a must be added to the cache
|
||||
err = mempool.CheckTx(a, nil, TxInfo{})
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, ErrTxInCache, err)
|
||||
}
|
||||
|
||||
// b must remain in the cache
|
||||
err = mempool.CheckTx(b, nil, TxInfo{})
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, ErrTxInCache, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. An invalid transaction must remain in the cache
|
||||
{
|
||||
a := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(a, 0)
|
||||
|
||||
// remove a from the cache to test (2)
|
||||
mempool.cache.Remove(a)
|
||||
|
||||
err := mempool.CheckTx(a, nil, TxInfo{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mempool.CheckTx(a, nil, TxInfo{})
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, ErrTxInCache, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxsAvailable(t *testing.T) {
|
||||
app := kvstore.NewApplication()
|
||||
cc := proxy.NewLocalClientCreator(app)
|
||||
|
||||
Reference in New Issue
Block a user