diff --git a/baseapp/abci.go b/baseapp/abci.go index ad420d0c2..a0bc3aa9a 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -370,6 +370,12 @@ func (app *BaseApp) Commit(ctx context.Context) (res *abci.ResponseCommit, err e header := app.stateToCommit.ctx.BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) + if app.preCommitHandler != nil { + if err := app.preCommitHandler(app.deliverState.ctx); err != nil { + panic(fmt.Errorf("error when executing commit handler: %s", err)) + } + } + app.WriteState() app.GetWorkingHash() app.cms.Commit(true) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 2ca96853e..57eeb072a 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -91,6 +91,8 @@ type BaseApp struct { //nolint: maligned finalizeBlocker sdk.FinalizeBlocker anteHandler sdk.AnteHandler // ante handler for fee and auth loadVersionHandler sdk.LoadVersionHandler + preCommitHandler sdk.PreCommitHandler + closeHandler sdk.CloseHandler appStore baseappVersions @@ -1171,7 +1173,13 @@ func (app *BaseApp) Close() error { if err := app.cms.Close(); err != nil { return err } - return app.snapshotManager.Close() + if err := app.snapshotManager.Close(); err != nil { + return err + } + if app.closeHandler == nil { + return nil + } + return app.closeHandler() } func (app *BaseApp) ReloadDB() error { diff --git a/baseapp/deliver_tx_test.go b/baseapp/deliver_tx_test.go index dc377c35a..aebf05644 100644 --- a/baseapp/deliver_tx_test.go +++ b/baseapp/deliver_tx_test.go @@ -5,6 +5,7 @@ import ( "context" "crypto/sha256" "encoding/binary" + "errors" "fmt" "math/rand" "os" @@ -906,9 +907,16 @@ func TestBaseAppAnteHandler(t *testing.T) { r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) bapp.Router().AddRoute(r) } + var preCommitCalled bool + preCommitHandlerOpt := func(bapp *BaseApp) { + bapp.SetPreCommitHandler(func(ctx sdk.Context) error { + preCommitCalled = true + return nil + }) + } cdc := codec.NewLegacyAmino() - app := setupBaseApp(t, anteOpt, routerOpt) + app := setupBaseApp(t, anteOpt, routerOpt, preCommitHandlerOpt) app.InitChain(context.Background(), &abci.RequestInitChain{}) registerTestCodec(cdc) @@ -976,6 +984,98 @@ func TestBaseAppAnteHandler(t *testing.T) { app.SetDeliverStateToCommit() app.Commit(context.Background()) + + require.True(t, preCommitCalled) +} + +func TestPrecommitHandlerPanic(t *testing.T) { + anteKey := []byte("ante-key") + anteOpt := func(bapp *BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } + + deliverKey := []byte("deliver-key") + routerOpt := func(bapp *BaseApp) { + r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) + bapp.Router().AddRoute(r) + } + preCommitHandlerOpt := func(bapp *BaseApp) { + bapp.SetPreCommitHandler(func(ctx sdk.Context) error { + return errors.New("test error") + }) + } + + cdc := codec.NewLegacyAmino() + app := setupBaseApp(t, anteOpt, routerOpt, preCommitHandlerOpt) + + app.InitChain(context.Background(), &abci.RequestInitChain{}) + registerTestCodec(cdc) + + header := tmproto.Header{Height: app.LastBlockHeight() + 1} + app.setDeliverState(header) + app.BeginBlock(app.deliverState.ctx, abci.RequestBeginBlock{Header: header}) + + // execute a tx that will fail ante handler execution + // + // NOTE: State should not be mutated here. This will be implicitly checked by + // the next txs ante handler execution (anteHandlerTxTest). + tx := newTxCounter(0, 0) + tx.setFailOnAnte(true) + txBytes, err := cdc.Marshal(tx) + require.NoError(t, err) + decoded, _ := app.txDecoder(txBytes) + res := app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes)) + require.Empty(t, res.Events) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx := app.getState(runTxModeDeliver).ctx + store := ctx.KVStore(capKey1) + require.Equal(t, int64(0), getIntFromStore(store, anteKey)) + + // execute at tx that will pass the ante handler (the checkTx state should + // mutate) but will fail the message handler + tx = newTxCounter(0, 0) + tx.setFailOnHandler(true) + + txBytes, err = cdc.Marshal(tx) + require.NoError(t, err) + + decoded, _ = app.txDecoder(txBytes) + res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes)) + // should emit ante event + require.NotEmpty(t, res.Events) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx = app.getState(runTxModeDeliver).ctx + store = ctx.KVStore(capKey1) + require.Equal(t, int64(1), getIntFromStore(store, anteKey)) + require.Equal(t, int64(0), getIntFromStore(store, deliverKey)) + + // execute a successful ante handler and message execution where state is + // implicitly checked by previous tx executions + tx = newTxCounter(1, 0) + + txBytes, err = cdc.Marshal(tx) + require.NoError(t, err) + + decoded, _ = app.txDecoder(txBytes) + res = app.DeliverTx(app.deliverState.ctx, abci.RequestDeliverTx{Tx: txBytes}, decoded, sha256.Sum256(txBytes)) + require.NotEmpty(t, res.Events) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx = app.getState(runTxModeDeliver).ctx + store = ctx.KVStore(capKey1) + require.Equal(t, int64(2), getIntFromStore(store, anteKey)) + require.Equal(t, int64(1), getIntFromStore(store, deliverKey)) + + // commit + app.EndBlock(app.deliverState.ctx, abci.RequestEndBlock{}) + require.Empty(t, app.deliverState.ctx.MultiStore().GetEvents()) + + app.SetDeliverStateToCommit() + + // should panic because pre-commit handler returned an error + require.Panics(t, func() { app.Commit(context.Background()) }) } func TestGasConsumptionBadTx(t *testing.T) { @@ -1426,7 +1526,13 @@ func TestCheckTx(t *testing.T) { })) } - app := setupBaseApp(t, anteOpt, routerOpt) + pchOpt := func(bapp *BaseApp) { + bapp.SetPreCommitHandler(func(ctx sdk.Context) error { + return nil + }) + } + + app := setupBaseApp(t, anteOpt, routerOpt, pchOpt) nTxs := int64(5) app.InitChain(context.Background(), &abci.RequestInitChain{}) @@ -1591,7 +1697,6 @@ func TestInfo(t *testing.T) { func TestBaseAppOptionSeal(t *testing.T) { app := setupBaseApp(t) - require.Panics(t, func() { app.SetName("") }) @@ -1628,6 +1733,9 @@ func TestBaseAppOptionSeal(t *testing.T) { require.Panics(t, func() { app.SetRouter(NewRouter()) }) + require.Panics(t, func() { + app.SetPreCommitHandler(nil) + }) } func TestVersionSetterGetter(t *testing.T) { diff --git a/baseapp/options.go b/baseapp/options.go index 1ef2622b3..316cbbee0 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -191,6 +191,22 @@ func (app *BaseApp) SetPrepareProposalHandler(prepareProposalHandler sdk.Prepare app.prepareProposalHandler = prepareProposalHandler } +func (app *BaseApp) SetPreCommitHandler(preCommitHandler sdk.PreCommitHandler) { + if app.sealed { + panic("SetPreCommitHandler() on sealed BaseApp") + } + + app.preCommitHandler = preCommitHandler +} + +func (app *BaseApp) SetCloseHandler(closeHandler sdk.CloseHandler) { + if app.sealed { + panic("SetCloseHandler() on sealed BaseApp") + } + + app.closeHandler = closeHandler +} + func (app *BaseApp) SetProcessProposalHandler(processProposalHandler sdk.ProcessProposalHandler) { if app.sealed { panic("SetProcessProposalHandler() on sealed BaseApp") diff --git a/go.mod b/go.mod index 6c91bb8bf..c0ad48078 100644 --- a/go.mod +++ b/go.mod @@ -195,7 +195,7 @@ replace ( // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.38 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.39 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.2 diff --git a/go.sum b/go.sum index 6c3b90b63..8384cb4be 100644 --- a/go.sum +++ b/go.sum @@ -967,8 +967,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/sei-protocol/go-ethereum v1.13.5-sei-21 h1:uzBquo71kOMs2bZjmYsiDQb7t5VpksYzOHnpGGQNaIU= github.com/sei-protocol/go-ethereum v1.13.5-sei-21/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= -github.com/sei-protocol/sei-db v0.0.38 h1:GiQl3qBd6XgGsHkJd4I8GnOmGjGoWQg3SJAS82TTNao= -github.com/sei-protocol/sei-db v0.0.38/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-db v0.0.39 h1:/XwwlObPhWnX8zH8GDbDvyn+a/K2911HZlmlBZzN+gQ= +github.com/sei-protocol/sei-db v0.0.39/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-tendermint v0.3.2 h1:Fiwr0y09GT5Gv/iGXVi6itRdwdUdh//O/oQTHq3x33c= diff --git a/storev2/rootmulti/store.go b/storev2/rootmulti/store.go index 8a16f095b..cbb4ef89c 100644 --- a/storev2/rootmulti/store.go +++ b/storev2/rootmulti/store.go @@ -74,7 +74,7 @@ func NewStore( pendingChanges: make(chan VersionedChangesets, 1000), } if ssConfig.Enable { - ssStore, err := ss.NewStateStore(homeDir, ssConfig) + ssStore, err := ss.NewStateStore(logger, homeDir, ssConfig) if err != nil { panic(err) } @@ -84,14 +84,11 @@ func NewStore( if ssVersion <= 0 && scVersion > 0 { panic("Enabling SS store without state sync could cause data corruption") } - if err = ss.RecoverStateStore(homeDir, logger, ssStore); err != nil { + if err = ss.RecoverStateStore(logger, homeDir, ssStore); err != nil { panic(err) } store.ssStore = ssStore go store.StateStoreCommit() - store.pruningManager = pruning.NewPruningManager( - logger, ssStore, int64(ssConfig.KeepRecent), int64(ssConfig.PruneIntervalSeconds)) - store.pruningManager.Start() } return store diff --git a/types/abci.go b/types/abci.go index 0d92626ce..bf08eefcd 100644 --- a/types/abci.go +++ b/types/abci.go @@ -32,3 +32,6 @@ type ProcessProposalHandler func(ctx Context, req *abci.RequestProcessProposal) type FinalizeBlocker func(ctx Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) type LoadVersionHandler func() error + +type PreCommitHandler func(ctx Context) error +type CloseHandler func() error