Skip to content

Commit

Permalink
Merge pull request #160 from crescent-network/amm-module-add-midblock…
Browse files Browse the repository at this point in the history
…-batch-msgs-filter

feat!: add ante msg filter for mixed batch msg, deprecated module msgs
  • Loading branch information
crypin authored Jun 21, 2023
2 parents effd294 + bc7b57c commit bacb608
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 41 deletions.
60 changes: 35 additions & 25 deletions app/ante/msg_ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/authz"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"

claimtypes "github.com/crescent-network/crescent/v5/x/claim/types"
exchangetypes "github.com/crescent-network/crescent/v5/x/exchange/types"
farmingtypes "github.com/crescent-network/crescent/v5/x/farming/types"
liquiditytypes "github.com/crescent-network/crescent/v5/x/liquidity/types"
)

// initial deposit must be greater than or equal to 50% of the minimum deposit
Expand All @@ -38,22 +41,23 @@ func (d MsgFilterDecorator) AnteHandle(
if !d.enabled {
return next(ctx, tx, simulate)
}
msgs := tx.GetMsgs()
if err = d.ValidateMsgs(ctx, msgs); err != nil {
if err = d.ValidateMsgs(ctx, tx.GetMsgs()); err != nil {
return ctx, err
}

return next(ctx, tx, simulate)
}

func (d MsgFilterDecorator) ValidateMsgs(ctx sdk.Context, msgs []sdk.Msg) error {
numMsg, numBatchMsg := 0, 0
var minInitialDeposit sdk.Coins
validateMsg := func(msg sdk.Msg, nested bool) error {
// mempool(check tx) level msg filter
if ctx.IsCheckTx() {
switch msg := msg.(type) {
// prevent messages with insufficient initial deposit amount
case *govtypes.MsgSubmitProposal:
numMsg++
switch msg := msg.(type) {
// prevent gov messages with insufficient initial deposit amount
case *govtypes.MsgSubmitProposal:
// mempool(check tx) level msg filter
if ctx.IsCheckTx() {
if minInitialDeposit.Empty() {
depositParams := d.govKeeper.GetDepositParams(ctx)
minInitialDeposit = CalcMinInitialDeposit(depositParams.MinDeposit, minInitialDepositFraction)
Expand All @@ -63,32 +67,31 @@ func (d MsgFilterDecorator) ValidateMsgs(ctx sdk.Context, msgs []sdk.Msg) error
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "insufficient initial deposit amount - required: %v", minInitialDeposit)
}
}
}

// deliver tx level msg filter
switch msg := msg.(type) {
// deprecated msgs
case *claimtypes.MsgClaim,
*farmingtypes.MsgCreateFixedAmountPlan,
*farmingtypes.MsgCreateRatioPlan,
*farmingtypes.MsgStake,
*farmingtypes.MsgUnstake,
*farmingtypes.MsgHarvest,
*farmingtypes.MsgRemovePlan,
*farmingtypes.MsgAdvanceEpoch:
return fmt.Errorf("%s is deprecated msg type", sdk.MsgTypeURL(msg))
// tracking mixed batch msg with regular msg
case *exchangetypes.MsgPlaceBatchLimitOrder,
*exchangetypes.MsgPlaceMMBatchLimitOrder,
*exchangetypes.MsgCancelOrder:
numMsg--
numBatchMsg++

// block double nested MsgExec
case *authz.MsgExec:
if nested {
return fmt.Errorf("double nested %s is not allowed", sdk.MsgTypeURL(msg))
}
default:
// block deprecated module's msgs
if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok {
switch legacyMsg.Route() {
case liquiditytypes.RouterKey,
farmingtypes.RouterKey,
claimtypes.RouterKey:
return fmt.Errorf("%s is deprecated msg type", sdk.MsgTypeURL(msg))
}
}
}

// TODO: on next PR
// - add other deprecated msg types
// - prevent authz nested midblock, batch msgs
// - prevent multi msgs midblock, batch msgs with normal msg

return nil
}

Expand All @@ -107,6 +110,7 @@ func (d MsgFilterDecorator) ValidateMsgs(ctx sdk.Context, msgs []sdk.Msg) error
}

for _, m := range msgs {
// validate authz nested msgs
if authzMsg, ok := m.(*authz.MsgExec); ok {
if err := validateAuthz(authzMsg); err != nil {
return err
Expand All @@ -119,6 +123,12 @@ func (d MsgFilterDecorator) ValidateMsgs(ctx sdk.Context, msgs []sdk.Msg) error
return err
}
}

// block mixed batch msg with regular msg
if numBatchMsg > 0 && numMsg > 0 {
return fmt.Errorf("cannot mix batch msg and regular msg in one tx")
}

return nil
}

Expand Down
221 changes: 219 additions & 2 deletions app/ante/msg_ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"

claimtypes "github.com/crescent-network/crescent/v5/x/claim/types"
exchangetypes "github.com/crescent-network/crescent/v5/x/exchange/types"
farmingtypes "github.com/crescent-network/crescent/v5/x/farming/types"
liquiditytypes "github.com/crescent-network/crescent/v5/x/liquidity/types"
)

type runTxMode uint8
Expand All @@ -30,7 +33,6 @@ func (suite *AnteTestSuite) TestAnteHandlerSubmitProposalMsg() {
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
acc := accounts[0].acc.GetAddress()
//accStr := acc.String()

// Variable data per test case
var (
Expand Down Expand Up @@ -322,6 +324,53 @@ func (suite *AnteTestSuite) TestAnteHandlerDeprecatedMsg() {
false,
fmt.Errorf("/crescent.claim.v1beta1.MsgClaim is deprecated msg type"),
},
{
"deprecated msg - farming",
func() {
msg := &farmingtypes.MsgStake{
Farmer: accStr,
StakingCoins: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1))),
}
msgs = []sdk.Msg{msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{0}
},
runTxModeDeliver,
false,
fmt.Errorf("/crescent.farming.v1beta1.MsgStake is deprecated msg type"),
},
{
"deprecated msg - liquidity",
func() {
msg := &liquiditytypes.MsgCreatePair{
Creator: accStr,
BaseCoinDenom: "abc",
QuoteCoinDenom: "stake",
}
msgs = []sdk.Msg{msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{0}
},
runTxModeDeliver,
false,
fmt.Errorf("/crescent.liquidity.v1beta1.MsgCreatePair is deprecated msg type"),
},
{
"not deprecated msg",
func() {
msg := &exchangetypes.MsgCreateMarket{
Sender: accStr,
BaseDenom: "abc",
QuoteDenom: "stake",
}
msgs = []sdk.Msg{msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{1}
},
runTxModeDeliver,
true,
nil,
},
}

for _, tc := range testCases {
Expand All @@ -342,7 +391,6 @@ func (suite *AnteTestSuite) TestDoubleNestedAuthzMsg() {
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
acc := accounts[0].acc.GetAddress()
//accStr := acc.String()

// Variable data per test case
var (
Expand Down Expand Up @@ -404,3 +452,172 @@ func (suite *AnteTestSuite) TestDoubleNestedAuthzMsg() {
})
}
}

func (suite *AnteTestSuite) TestMixedBatchMsg() {
suite.SetupTest(false) // reset

// Same data for every test cases
accounts := suite.CreateTestAccounts(2)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
acc := accounts[0].acc.GetAddress()

// Variable data per test case
var (
accNums []uint64
msgs []sdk.Msg
privs []cryptotypes.PrivKey
accSeqs []uint64
)

msg := testdata.NewTestMsg(acc)
batchMsg := exchangetypes.NewMsgPlaceBatchLimitOrder(acc, 1, true, sdk.ZeroDec(), sdk.ZeroInt(), 0)
authzMsg := authz.NewMsgExec(acc, []sdk.Msg{batchMsg, msg})
authzMsg2 := authz.NewMsgExec(acc, []sdk.Msg{batchMsg})
authzMsg3 := authz.NewMsgExec(acc, []sdk.Msg{batchMsg, batchMsg})
//authzMsgNested := authz.NewMsgExec(acc, []sdk.Msg{&authzMsg})

testCases := []TestCase{
{
"only batch msg",
func() {

msgs = []sdk.Msg{batchMsg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{0}
},
runTxModeDeliver,
true,
nil,
},
{
"only batch msgs",
func() {

msgs = []sdk.Msg{batchMsg, batchMsg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{1}
},
runTxModeDeliver,
true,
nil,
},
{
"mixed batch msg with multi msg",
func() {

msgs = []sdk.Msg{batchMsg, msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"mixed batch msg with multi msg - check tx",
func() {

msgs = []sdk.Msg{batchMsg, msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeCheck,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"mixed batch msg with multi msg",
func() {

msgs = []sdk.Msg{msg, batchMsg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"mixed batch msg with authz msg",
func() {

msgs = []sdk.Msg{msg, &authzMsg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"mixed batch msg with authz msg - 2",
func() {

msgs = []sdk.Msg{&authzMsg, msg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"mixed batch msg with authz msg - 3",
func() {

msgs = []sdk.Msg{msg, &authzMsg2}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
false,
fmt.Errorf("cannot mix batch msg and regular msg in one tx"),
},
{
"authz only batch msg",
func() {

msgs = []sdk.Msg{&authzMsg2}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{2}
},
runTxModeDeliver,
true,
nil,
},
{
"authz only batch msg - 2",
func() {

msgs = []sdk.Msg{&authzMsg3}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{3}
},
runTxModeDeliver,
true,
nil,
},
{
"authz only batch msg - 3",
func() {

msgs = []sdk.Msg{&authzMsg3, batchMsg}

privs, accNums, accSeqs = []cryptotypes.PrivKey{accounts[0].priv}, []uint64{0}, []uint64{4}
},
runTxModeDeliver,
true,
nil,
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.desc), func() {
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
tc.malleate()

suite.RunTestCase(privs, msgs, feeAmount, gasLimit, accNums, accSeqs, suite.ctx.ChainID(), tc)
})
}
}
Loading

0 comments on commit bacb608

Please sign in to comment.