Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* (baseapp) [#23879](https://github.com/cosmos/cosmos-sdk/pull/23879) Ensure finalize block response is not empty in the defer check of FinalizeBlock to avoid panic by nil pointer.
* (query) [#23884](https://github.com/cosmos/cosmos-sdk/pull/23884) Fix NPE in query pagination.
* (baseapp) [#25552](https://github.com/cosmos/cosmos-sdk/pull/25552) Prevent updating check state before mempool insert

## [v0.50.14](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.14) - 2025-07-08

Expand Down
40 changes: 40 additions & 0 deletions baseapp/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,46 @@ func TestABCI_CheckTx(t *testing.T) {
require.Nil(t, storedBytes)
}

func TestABCI_CheckTx_DoesNotCorruptStateOnMempoolFailure(t *testing.T) {
counterKey := []byte("counter-key")
anteOpt := func(bapp *baseapp.BaseApp) {
bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, counterKey))
}

cfg := mempool.DefaultPriorityNonceMempoolConfig()
cfg.MaxTx = 1
pool := mempool.NewPriorityMempool(cfg)

suite := NewBaseAppSuite(t, anteOpt, baseapp.SetMempool(pool))
baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, counterKey})

_, err := suite.baseApp.InitChain(&abci.RequestInitChain{
ConsensusParams: &cmtproto.ConsensusParams{},
})
require.NoError(t, err)

tx := newTxCounter(t, suite.txConfig, 0, 0)
txBytes, err := suite.txConfig.TxEncoder()(tx)
require.NoError(t, err)

res, err := suite.baseApp.CheckTx(&abci.RequestCheckTx{Tx: txBytes})
require.NoError(t, err)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))

failTx := newTxCounter(t, suite.txConfig, 1, 0)
failTxBytes, err := suite.txConfig.TxEncoder()(failTx)
require.NoError(t, err)

failRes, err := suite.baseApp.CheckTx(&abci.RequestCheckTx{Tx: failTxBytes})
require.NoError(t, err)
require.False(t, failRes.IsOK())
require.Contains(t, failRes.Log, mempool.ErrMempoolTxMaxCapacity.Error())

checkStateStore := getCheckStateCtx(suite.baseApp).KVStore(capKey1)
require.Equal(t, int64(1), getIntFromStore(t, checkStateStore, counterKey))
require.Equal(t, 1, pool.CountTx())
}

func TestABCI_FinalizeBlock_DeliverTx(t *testing.T) {
anteKey := []byte("ante-key")
anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) }
Expand Down
31 changes: 25 additions & 6 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,9 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res
}
}

mempoolCtx := ctx
var commitAnteCache func()

if app.anteHandler != nil {
Comment on lines 887 to 893
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change potentially affects state.

Call sequence:

(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).runTx (baseapp/baseapp.go:825)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).deliverTx (baseapp/baseapp.go:755)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).internalFinalizeBlock (baseapp/baseapp.go:692)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).FinalizeBlock (baseapp/baseapp.go:856)

var (
anteCtx sdk.Context
Expand Down Expand Up @@ -929,16 +932,32 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res
return gInfo, nil, nil, err
}

msCache.Write()
anteEvents = events.ToABCIEvents()
commitAnteCache = func() {
if msCache != nil {
msCache.Write()
}
anteEvents = events.ToABCIEvents()
}

if mode == execModeCheck {
mempoolCtx = ctx.WithMultiStore(msCache)
} else {
commitAnteCache()
commitAnteCache = nil
}
}

if mode == execModeCheck {
err = app.mempool.Insert(ctx, tx)
if err != nil {
switch mode {
case execModeCheck:
if err := app.mempool.Insert(mempoolCtx, tx); err != nil {
return gInfo, nil, anteEvents, err
}
} else if mode == execModeFinalize {

if commitAnteCache != nil {
commitAnteCache()
commitAnteCache = nil
}
case execModeFinalize:
err = app.mempool.Remove(tx)
if err != nil && !errors.Is(err, mempool.ErrTxNotFound) {
return gInfo, nil, anteEvents,
Expand Down