diff --git a/app/app.go b/app/app.go index cdd662ab8..f508e75fb 100644 --- a/app/app.go +++ b/app/app.go @@ -216,6 +216,7 @@ func NewTerraApp( TXCounterStoreKey: app.GetKey(wasm.StoreKey), DyncommKeeper: app.DyncommKeeper, StakingKeeper: app.StakingKeeper, + Cdc: app.appCodec, }, ) if err != nil { diff --git a/custom/auth/ante/ante.go b/custom/auth/ante/ante.go index 1441d28a6..a6f548209 100644 --- a/custom/auth/ante/ante.go +++ b/custom/auth/ante/ante.go @@ -3,6 +3,7 @@ package ante import ( dyncommante "github.com/classic-terra/core/v2/x/dyncomm/ante" dyncommkeeper "github.com/classic-terra/core/v2/x/dyncomm/keeper" + "github.com/cosmos/cosmos-sdk/codec" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ibcante "github.com/cosmos/ibc-go/v6/modules/core/ante" ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper" @@ -36,6 +37,7 @@ type HandlerOptions struct { TXCounterStoreKey storetypes.StoreKey DyncommKeeper dyncommkeeper.Keeper StakingKeeper stakingkeeper.Keeper + Cdc codec.BinaryCodec } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -84,7 +86,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { NewMinInitialDepositDecorator(options.GovKeeper, options.TreasuryKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), NewFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TreasuryKeeper), - dyncommante.NewDyncommDecorator(options.DyncommKeeper, options.StakingKeeper), + dyncommante.NewDyncommDecorator(options.Cdc, options.DyncommKeeper, options.StakingKeeper), // Do not add any other decorators below this point unless explicitly explain. ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators diff --git a/x/dyncomm/ante/ante.go b/x/dyncomm/ante/ante.go index 300c81607..fba980012 100644 --- a/x/dyncomm/ante/ante.go +++ b/x/dyncomm/ante/ante.go @@ -4,10 +4,14 @@ import ( "fmt" dyncommkeeper "github.com/classic-terra/core/v2/x/dyncomm/keeper" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authz "github.com/cosmos/cosmos-sdk/x/authz" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icatypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" ) // DyncommDecorator checks for EditValidator and rejects @@ -15,12 +19,14 @@ import ( type DyncommDecorator struct { dyncommKeeper dyncommkeeper.Keeper stakingKeeper stakingkeeper.Keeper + cdc codec.BinaryCodec } -func NewDyncommDecorator(dk dyncommkeeper.Keeper, sk stakingkeeper.Keeper) DyncommDecorator { +func NewDyncommDecorator(cdc codec.BinaryCodec, dk dyncommkeeper.Keeper, sk stakingkeeper.Keeper) DyncommDecorator { return DyncommDecorator{ dyncommKeeper: dk, stakingKeeper: sk, + cdc: cdc, } } @@ -41,9 +47,27 @@ func (dd DyncommDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, func (dd DyncommDecorator) FilterMsgsAndProcessMsgs(ctx sdk.Context, msgs ...sdk.Msg) (err error) { for _, msg := range msgs { - switch msg.(type) { + switch msg := msg.(type) { case *stakingtypes.MsgEditValidator: err = dd.ProcessEditValidator(ctx, msg) + case *authz.MsgExec: + messages, msgerr := msg.GetMessages() + if msgerr == nil { + err = dd.FilterMsgsAndProcessMsgs(ctx, messages...) + } + case *channeltypes.MsgRecvPacket: + var data icatypes.InterchainAccountPacketData + err = icatypes.ModuleCdc.UnmarshalJSON(msg.Packet.GetData(), &data) + if err != nil { + continue + } + if data.Type != icatypes.EXECUTE_TX { + continue + } + messages, msgerr := icatypes.DeserializeCosmosTx(dd.cdc, data.Data) + if msgerr == nil { + err = dd.FilterMsgsAndProcessMsgs(ctx, messages...) + } default: continue } diff --git a/x/dyncomm/ante/ante_test.go b/x/dyncomm/ante/ante_test.go index 6d4651b61..e4ba039cb 100644 --- a/x/dyncomm/ante/ante_test.go +++ b/x/dyncomm/ante/ante_test.go @@ -7,6 +7,7 @@ import ( "cosmossdk.io/math" "github.com/classic-terra/core/v2/app" core "github.com/classic-terra/core/v2/types" + "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client" @@ -21,7 +22,11 @@ import ( apptesting "github.com/classic-terra/core/v2/app/testing" dyncommante "github.com/classic-terra/core/v2/x/dyncomm/ante" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authz "github.com/cosmos/cosmos-sdk/x/authz" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icatypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -173,7 +178,7 @@ func (suite *AnteTestSuite) TestAnte_EnsureDynCommissionIsMinComm() { suite.CreateValidator(50_000_000_000) suite.App.DyncommKeeper.UpdateAllBondedValidatorRates(suite.Ctx) - mfd := dyncommante.NewDyncommDecorator(suite.App.DyncommKeeper, suite.App.StakingKeeper) + mfd := dyncommante.NewDyncommDecorator(suite.App.AppCodec(), suite.App.DyncommKeeper, suite.App.StakingKeeper) antehandler := sdk.ChainAnteDecorators(mfd) dyncomm := suite.App.DyncommKeeper.CalculateDynCommission(suite.Ctx, val1) @@ -205,6 +210,129 @@ func (suite *AnteTestSuite) TestAnte_EnsureDynCommissionIsMinComm() { suite.Require().NoError(err) } +func (suite *AnteTestSuite) TestAnte_EnsureDynCommissionIsMinCommAuthz() { + suite.SetupTest() // setup + suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() + suite.txBuilder.SetGasLimit(400_000) + suite.Ctx = suite.Ctx.WithIsCheckTx(false) + + _, _, val1, _ := suite.CreateValidator(50_000_000_000) + priv2, _, acc2 := testdata.KeyTestPubAddr() + suite.CreateValidator(50_000_000_000) + suite.App.DyncommKeeper.UpdateAllBondedValidatorRates(suite.Ctx) + + mfd := dyncommante.NewDyncommDecorator(suite.App.AppCodec(), suite.App.DyncommKeeper, suite.App.StakingKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + + dyncomm := suite.App.DyncommKeeper.CalculateDynCommission(suite.Ctx, val1) + invalidtarget := dyncomm.Mul(sdk.NewDecWithPrec(9, 1)) + validtarget := dyncomm.Mul(sdk.NewDecWithPrec(11, 1)) + + // invalid tx fails + editmsg := stakingtypes.NewMsgEditValidator( + val1.GetOperator(), + val1.Description, &invalidtarget, &val1.MinSelfDelegation, + ) + + execmsg := authz.NewMsgExec(acc2, []sdk.Msg{editmsg}) + + err := suite.txBuilder.SetMsgs(&execmsg) + suite.Require().NoError(err) + tx, err := suite.CreateTestTx([]cryptotypes.PrivKey{priv2}, []uint64{0}, []uint64{0}, suite.Ctx.ChainID()) + suite.Require().NoError(err) + _, err = antehandler(suite.Ctx, tx, false) + suite.Require().Error(err) + + // valid tx passes + editmsg = stakingtypes.NewMsgEditValidator( + val1.GetOperator(), + val1.Description, &validtarget, &val1.MinSelfDelegation, + ) + execmsg = authz.NewMsgExec(acc2, []sdk.Msg{editmsg}) + + err = suite.txBuilder.SetMsgs(editmsg) + suite.Require().NoError(err) + tx, err = suite.CreateTestTx([]cryptotypes.PrivKey{priv2}, []uint64{0}, []uint64{0}, suite.Ctx.ChainID()) + suite.Require().NoError(err) + _, err = antehandler(suite.Ctx, tx, false) + suite.Require().NoError(err) +} + +func (suite *AnteTestSuite) TestAnte_EnsureDynCommissionIsMinCommICA() { + suite.SetupTest() // setup + suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() + suite.txBuilder.SetGasLimit(400_000) + suite.Ctx = suite.Ctx.WithIsCheckTx(false) + + _, _, val1, _ := suite.CreateValidator(50_000_000_000) + priv2, _, _ := testdata.KeyTestPubAddr() + suite.CreateValidator(50_000_000_000) + suite.App.DyncommKeeper.UpdateAllBondedValidatorRates(suite.Ctx) + + mfd := dyncommante.NewDyncommDecorator(suite.App.AppCodec(), suite.App.DyncommKeeper, suite.App.StakingKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + + dyncomm := suite.App.DyncommKeeper.CalculateDynCommission(suite.Ctx, val1) + invalidtarget := dyncomm.Mul(sdk.NewDecWithPrec(9, 1)) + validtarget := dyncomm.Mul(sdk.NewDecWithPrec(11, 1)) + + // prepare invalid tx -> expect it fails + editmsg := stakingtypes.NewMsgEditValidator( + val1.GetOperator(), + val1.Description, &invalidtarget, &val1.MinSelfDelegation, + ) + data, err := icatypes.SerializeCosmosTx(suite.App.AppCodec(), []proto.Message{editmsg}) + suite.Require().NoError(err) + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + packetData := icaPacketData.GetBytes() + packet := channeltypes.NewPacket( + packetData, 1, "source-port", "source-channel", + "dest-port", "dest-channel", + clienttypes.NewHeight(1, 1), 0, + ) + recvmsg := channeltypes.NewMsgRecvPacket( + packet, []byte{}, clienttypes.NewHeight(1, 1), "signer", + ) + + err = suite.txBuilder.SetMsgs(recvmsg) + suite.Require().NoError(err) + tx, err := suite.CreateTestTx([]cryptotypes.PrivKey{priv2}, []uint64{0}, []uint64{0}, suite.Ctx.ChainID()) + suite.Require().NoError(err) + _, err = antehandler(suite.Ctx, tx, false) + suite.Require().Error(err) + + // prepare valid tx -> expect it passes + editmsg = stakingtypes.NewMsgEditValidator( + val1.GetOperator(), + val1.Description, &validtarget, &val1.MinSelfDelegation, + ) + data, err = icatypes.SerializeCosmosTx(suite.App.AppCodec(), []proto.Message{editmsg}) + suite.Require().NoError(err) + icaPacketData = icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() + packet = channeltypes.NewPacket( + packetData, 1, "source-port", "source-channel", + "dest-port", "dest-channel", + clienttypes.NewHeight(1, 1), 0, + ) + recvmsg = channeltypes.NewMsgRecvPacket( + packet, []byte{}, clienttypes.NewHeight(1, 1), "signer", + ) + + err = suite.txBuilder.SetMsgs(recvmsg) + suite.Require().NoError(err) + tx, err = suite.CreateTestTx([]cryptotypes.PrivKey{priv2}, []uint64{0}, []uint64{0}, suite.Ctx.ChainID()) + suite.Require().NoError(err) + _, err = antehandler(suite.Ctx, tx, false) + suite.Require().NoError(err) +} + // go test -v -run ^TestAnteTestSuite/TestAnte_EditValidatorAccountSequence$ github.com/classic-terra/core/v2/x/dyncomm/ante // check that account keeper sequence no longer increases when editing validator unsuccessfully func (suite *AnteTestSuite) TestAnte_EditValidatorAccountSequence() {