diff --git a/CHANGELOG.md b/CHANGELOG.md index 08c804e0f8d..49383a39f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/27-interchain-accounts, apps/tranfer, apps/29-fee) [\#6253](https://github.com/cosmos/ibc-go/pull/6253) Allow channel handshake to succeed if fee middleware is wired up on one side, but not the other. * (apps/27-interchain-accounts) [\#6251](https://github.com/cosmos/ibc-go/pull/6251) Use `UNORDERED` as the default ordering for new ICA channels. * (apps/transfer) [\#6268](https://github.com/cosmos/ibc-go/pull/6268) Use memo strings instead of JSON keys in `AllowedPacketData` of transfer authorization. +* (core/ante) [\#6278](https://github.com/cosmos/ibc-go/pull/6278) Performance: Exclude pruning from tendermint client updates in ante handler executions. ### Features diff --git a/modules/light-clients/07-tendermint/update.go b/modules/light-clients/07-tendermint/update.go index 59c050cc903..5c5fbca840c 100644 --- a/modules/light-clients/07-tendermint/update.go +++ b/modules/light-clients/07-tendermint/update.go @@ -138,7 +138,11 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client return []exported.Height{} } - cs.pruneOldestConsensusState(ctx, cdc, clientStore) + // performance: do not prune in checkTx + // simulation must prune for accurate gas estimation + if (!ctx.IsCheckTx() && !ctx.IsReCheckTx()) || ctx.ExecMode() == sdk.ExecModeSimulate { + cs.pruneOldestConsensusState(ctx, cdc, clientStore) + } // check for duplicate update if _, found := GetConsensusState(clientStore, cdc, header.GetHeight()); found { diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go index 1fe8c75e541..1176a053b9d 100644 --- a/modules/light-clients/07-tendermint/update_test.go +++ b/modules/light-clients/07-tendermint/update_test.go @@ -5,6 +5,8 @@ import ( storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/cometbft/cometbft/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -523,6 +525,75 @@ func (suite *TendermintTestSuite) TestUpdateState() { } } +func (suite *TendermintTestSuite) TestUpdateStateCheckTx() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + createClientMessage := func() exported.ClientMessage { + header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, path.EndpointA.ClientID) + suite.Require().NoError(err) + return header + } + + // get the first height as it will be pruned first. + var pruneHeight exported.Height + getFirstHeightCb := func(height exported.Height) bool { + pruneHeight = height + return true + } + ctx := path.EndpointA.Chain.GetContext() + clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + ibctm.IterateConsensusStateAscending(clientStore, getFirstHeightCb) + + // Increment the time by a week + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + + cs := path.EndpointA.GetClientState() + ctx = path.EndpointA.Chain.GetContext().WithIsCheckTx(true) + + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + // Increment the time by another week, then update the client. + // This will cause the first two consensus states to become expired. + suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) + ctx = path.EndpointA.Chain.GetContext().WithIsCheckTx(true) + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + assertPrune := func(pruned bool) { + // check consensus states and associated metadata + consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) + suite.Require().Equal(!pruned, ok) + + processTime, ok := ibctm.GetProcessedTime(clientStore, pruneHeight) + suite.Require().Equal(!pruned, ok) + + processHeight, ok := ibctm.GetProcessedHeight(clientStore, pruneHeight) + suite.Require().Equal(!pruned, ok) + + consKey := ibctm.GetIterationKey(clientStore, pruneHeight) + + if pruned { + suite.Require().Nil(consState, "expired consensus state not pruned") + suite.Require().Empty(processTime, "processed time metadata not pruned") + suite.Require().Nil(processHeight, "processed height metadata not pruned") + suite.Require().Nil(consKey, "iteration key not pruned") + } else { + suite.Require().NotNil(consState, "expired consensus state pruned") + suite.Require().NotEqual(uint64(0), processTime, "processed time metadata pruned") + suite.Require().NotNil(processHeight, "processed height metadata pruned") + suite.Require().NotNil(consKey, "iteration key pruned") + } + } + + assertPrune(false) + + // simulation mode must prune to calculate gas correctly + ctx = ctx.WithExecMode(sdk.ExecModeSimulate) + cs.UpdateState(ctx, suite.chainA.GetSimApp().AppCodec(), clientStore, createClientMessage()) + + assertPrune(true) +} + func (suite *TendermintTestSuite) TestPruneConsensusState() { // create path and setup clients path := ibctesting.NewPath(suite.chainA, suite.chainB)