Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/exempt-system-tx-min-gas' into e…
Browse files Browse the repository at this point in the history
…xempt-system-tx-min-gas
  • Loading branch information
kingpinXD committed Jan 21, 2024
2 parents 3702dc3 + 75276e0 commit 71869e7
Show file tree
Hide file tree
Showing 17 changed files with 346 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,4 @@ jobs:
- name: Clean Up Workspace
if: always()
shell: bash
run: rm -rf *
run: sudo rm -rf * || echo "failed to cleanup workspace please investigate"
2 changes: 1 addition & 1 deletion .github/workflows/rc-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,4 @@ jobs:
- name: Clean Up Workspace
if: always()
shell: bash
run: rm -rf *
run: sudo rm -rf * || echo "failed to clean workspace please investigate"
93 changes: 54 additions & 39 deletions app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ import (
"fmt"
"runtime/debug"

cctxtypes "github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/authz"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
tmlog "github.com/tendermint/tendermint/libs/log"
cctxtypes "github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

func ValidateHandlerOptions(options HandlerOptions) error {
Expand Down Expand Up @@ -97,46 +96,24 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
// handle as totally normal Cosmos SDK tx
switch tx.(type) {
case sdk.Tx:
// default: handle as normal Cosmos SDK tx
anteHandler = newCosmosAnteHandler(options)
if len(tx.GetMsgs()) != 1 {
break
}

msg := tx.GetMsgs()[0] // now we must have len(tx.GetMsgs()) == 1
var innerMsg sdk.Msg
innerMsg = msg
if mm, ok := msg.(*authz.MsgExec); ok { // authz tx; look inside it
msgs, err := mm.GetMessages()
if err == nil && len(msgs) == 1 {
innerMsg = msgs[0]
}
// if tx is a system tx, and singer is authorized, use system tx handler

isAuthorized := func(creator string) bool {
return options.ObserverKeeper.IsAuthorized(ctx, creator)
}
if IsSystemTx(tx, isAuthorized) {
anteHandler = newCosmosAnteHandlerForSystemTx(options)
}

isAuthorize := options.ObserverKeeper.IsAuthorized
if mm, ok := innerMsg.(*cctxtypes.MsgGasPriceVoter); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*cctxtypes.MsgVoteOnObservedInboundTx); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*cctxtypes.MsgVoteOnObservedOutboundTx); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*cctxtypes.MsgAddToOutTxTracker); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*cctxtypes.MsgCreateTSSVoter); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*observertypes.MsgAddBlockHeader); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if mm, ok := innerMsg.(*observertypes.MsgAddBlameVote); ok && isAuthorize(ctx, mm.Creator) {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
} else if _, ok := innerMsg.(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 {
anteHandler = newCosmosAnteHandlerNoGasFee(options)
break
// if tx is MsgCreatorValidator, use the newCosmosAnteHandlerForSystemTx handler to
// exempt gas fee requirement in genesis because it's not possible to pay gas fee in genesis
if len(tx.GetMsgs()) == 1 {
if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 {
anteHandler = newCosmosAnteHandlerForSystemTx(options)
}
}

default:
Expand Down Expand Up @@ -168,3 +145,41 @@ func Recover(logger tmlog.Logger, err *error) {
}
}
}

// IsSystemTx determines whether tx is a system tx that's signed by an authorized signer
// system tx are special types of txs (see in the switch below), or such txs wrapped inside a MsgExec
// the parameter isAuthorizedSigner is a caller specified function that determines whether the signer of
// the tx is authorized.
func IsSystemTx(tx sdk.Tx, isAuthorizedSigner func(string) bool) bool {
// the following determines whether the tx is a system tx which will uses different handler
// System txs are always single Msg txs, optionally wrapped by one level of MsgExec
if len(tx.GetMsgs()) != 1 { // this is not a system tx
return false
}
msg := tx.GetMsgs()[0]

// if wrapped inside a MsgExec, unwrap it and reveal the innerMsg.
var innerMsg sdk.Msg
innerMsg = msg
if mm, ok := msg.(*authz.MsgExec); ok { // authz tx; look inside it
msgs, err := mm.GetMessages()
if err == nil && len(msgs) == 1 {
innerMsg = msgs[0]
}
}
switch innerMsg.(type) {
case *cctxtypes.MsgGasPriceVoter,
*cctxtypes.MsgVoteOnObservedInboundTx,
*cctxtypes.MsgVoteOnObservedOutboundTx,
*cctxtypes.MsgAddToOutTxTracker,
*cctxtypes.MsgCreateTSSVoter,
*observertypes.MsgAddBlockHeader,
*observertypes.MsgAddBlameVote:
signers := innerMsg.GetSigners()
if len(signers) == 1 {
return isAuthorizedSigner(signers[0].String())
}
}

return false
}
216 changes: 215 additions & 1 deletion app/ante/ante_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package ante_test

import sdk "github.com/cosmos/cosmos-sdk/types"
import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/app"
"github.com/zeta-chain/zetacore/app/ante"
"github.com/zeta-chain/zetacore/testutil/sample"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

var _ sdk.AnteHandler = (&MockAnteHandler{}).AnteHandle

Expand All @@ -16,3 +29,204 @@ func (mah *MockAnteHandler) AnteHandle(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.C
mah.CalledCtx = ctx
return ctx, nil
}

func TestIsSystemTx(t *testing.T) {
// system tx types:
// *cctxtypes.MsgGasPriceVoter,
// *cctxtypes.MsgVoteOnObservedInboundTx,
// *cctxtypes.MsgVoteOnObservedOutboundTx,
// *cctxtypes.MsgAddToOutTxTracker,
// *cctxtypes.MsgCreateTSSVoter,
// *observertypes.MsgAddBlockHeader,
// *observertypes.MsgAddBlameVote:
buildTxFromMsg := func(msg sdk.Msg) sdk.Tx {
txBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder()
txBuilder.SetMsgs(msg)
return txBuilder.GetTx()
}
buildAuthzTxFromMsg := func(msg sdk.Msg) sdk.Tx {
txBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder()
msgExec := authz.NewMsgExec(sample.Bech32AccAddress(), []sdk.Msg{msg})
txBuilder.SetMsgs(&msgExec)
return txBuilder.GetTx()
}
isAuthorized := func(_ string) bool {
return true
}
isAuthorizedFalse := func(_ string) bool {
return false
}

tests := []struct {
name string
tx sdk.Tx
isAuthorized func(string) bool
wantIs bool
}{
{
"MsgCreateTSSVoter",
buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{
Creator: sample.AccAddress(),
TssPubkey: "pubkey1234",
}),
isAuthorizedFalse,
false,
},
{
"MsgCreateTSSVoter",
buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{
Creator: sample.AccAddress(),
TssPubkey: "pubkey1234",
}),
isAuthorized,
true,
},
{
"MsgExec{MsgCreateTSSVoter}",
buildAuthzTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{
Creator: sample.AccAddress(),
TssPubkey: "pubkey1234",
}),
isAuthorized,

true,
},
{
"MsgSend",
buildTxFromMsg(&banktypes.MsgSend{}),
isAuthorized,

false,
},
{
"MsgExec{MsgSend}",
buildAuthzTxFromMsg(&banktypes.MsgSend{}),
isAuthorized,

false,
},
{
"MsgCreateValidator",
buildTxFromMsg(&stakingtypes.MsgCreateValidator{}),
isAuthorized,

false,
},

{
"MsgVoteOnObservedInboundTx",
buildTxFromMsg(&crosschaintypes.MsgVoteOnObservedInboundTx{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgVoteOnObservedInboundTx}",
buildAuthzTxFromMsg(&crosschaintypes.MsgVoteOnObservedInboundTx{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},

{
"MsgVoteOnObservedOutboundTx",
buildTxFromMsg(&crosschaintypes.MsgVoteOnObservedOutboundTx{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgVoteOnObservedOutboundTx}",
buildAuthzTxFromMsg(&crosschaintypes.MsgVoteOnObservedOutboundTx{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgAddToOutTxTracker",
buildTxFromMsg(&crosschaintypes.MsgAddToOutTxTracker{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgAddToOutTxTracker}",
buildAuthzTxFromMsg(&crosschaintypes.MsgAddToOutTxTracker{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgCreateTSSVoter",
buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgCreateTSSVoter}",
buildAuthzTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgAddBlockHeader",
buildTxFromMsg(&observertypes.MsgAddBlockHeader{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgAddBlockHeader}",
buildAuthzTxFromMsg(&observertypes.MsgAddBlockHeader{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgAddBlameVote",
buildTxFromMsg(&observertypes.MsgAddBlameVote{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
{
"MsgExec{MsgAddBlameVote}",
buildAuthzTxFromMsg(&observertypes.MsgAddBlameVote{
Creator: sample.AccAddress(),
}),
isAuthorized,

true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
is := ante.IsSystemTx(tt.tx, tt.isAuthorized)
require.Equal(t, tt.wantIs, is)
})
}
}
11 changes: 8 additions & 3 deletions app/ante/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import (
evmtypes "github.com/evmos/ethermint/x/evm/types"
)

var (
GasPriceReductionRate = "0.01" // 1% of regular tx gas price for system txs
)

// MinGasPriceDecorator will check if the transaction's fee is at least as large
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
// is rejected. This applies for both CheckTx and DeliverTx
Expand Down Expand Up @@ -92,14 +96,15 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
return next(ctx, tx, simulate)
}

// Short-circuit genesis txs gentx
// Short-circuit genesis txs gentx at block 0 (there is no way to pay fee in genesis file)
if len(tx.GetMsgs()) == 1 {
if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok {
if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
}

minGasPrice = minGasPrice.Mul(sdk.NewDecWithPrec(1, 2)) //
reductionRate := sdk.MustNewDecFromStr(GasPriceReductionRate)
minGasPrice = minGasPrice.Mul(reductionRate) // discounts min gas price for system tx

evmParams := mpd.evmKeeper.GetParams(ctx)
evmDenom := evmParams.GetEvmDenom()
Expand Down
Loading

0 comments on commit 71869e7

Please sign in to comment.