Skip to content

Commit eaf531f

Browse files
committed
feat: added ante handlers changes
1 parent e168340 commit eaf531f

File tree

9 files changed

+1048
-18
lines changed

9 files changed

+1048
-18
lines changed

app/ante/ante.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// Copyright 2021 Evmos Foundation
2+
// This file is part of Evmos' Ethermint library.
3+
//
4+
// The Ethermint library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The Ethermint library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the Ethermint library. If not, see https://github.com/zeta-chain/ethermint/blob/main/LICENSE
16+
package ante
17+
18+
import (
19+
"fmt"
20+
"runtime/debug"
21+
22+
errorsmod "cosmossdk.io/errors"
23+
tmlog "github.com/cometbft/cometbft/libs/log"
24+
sdk "github.com/cosmos/cosmos-sdk/types"
25+
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
26+
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
27+
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
28+
// crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
29+
// observertypes "github.com/zeta-chain/node/x/observer/types"
30+
)
31+
32+
func ValidateHandlerOptions(options HandlerOptions) error {
33+
if options.AccountKeeper == nil {
34+
return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler")
35+
}
36+
if options.BankKeeper == nil {
37+
return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler")
38+
}
39+
if options.SignModeHandler == nil {
40+
return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for ante builder")
41+
}
42+
if options.FeeMarketKeeper == nil {
43+
return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler")
44+
}
45+
if options.EvmKeeper == nil {
46+
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
47+
}
48+
// if options.ObserverKeeper == nil {
49+
// return errorsmod.Wrap(errortypes.ErrLogic, "observer keeper is required for AnteHandler")
50+
// }
51+
return nil
52+
}
53+
54+
// NewAnteHandler returns an ante handler responsible for attempting to route an
55+
// Ethereum or SDK transaction to an internal ante handler for performing
56+
// transaction-level processing (e.g. fee payment, signature verification) before
57+
// being passed onto it's respective handler.
58+
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
59+
if err := ValidateHandlerOptions(options); err != nil {
60+
return nil, err
61+
}
62+
63+
return func(
64+
ctx sdk.Context, tx sdk.Tx, sim bool,
65+
) (newCtx sdk.Context, err error) {
66+
var anteHandler sdk.AnteHandler
67+
68+
defer Recover(ctx.Logger(), &err)
69+
70+
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
71+
if ok {
72+
opts := txWithExtensions.GetExtensionOptions()
73+
if len(opts) > 0 {
74+
switch typeURL := opts[0].GetTypeUrl(); typeURL {
75+
case "/ethermint.evm.v1.ExtensionOptionsEthereumTx":
76+
// handle as *evmtypes.MsgEthereumTx
77+
anteHandler = newEthAnteHandler(options)
78+
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
79+
// Deprecated: Handle as normal Cosmos SDK tx, except signature is checked for Legacy EIP712 representation
80+
anteHandler = NewLegacyCosmosAnteHandlerEip712(options)
81+
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
82+
// cosmos-sdk tx with dynamic fee extension
83+
anteHandler = newCosmosAnteHandler(options)
84+
default:
85+
return ctx, errorsmod.Wrapf(
86+
errortypes.ErrUnknownExtensionOptions,
87+
"rejecting tx with unsupported extension option: %s", typeURL,
88+
)
89+
}
90+
91+
return anteHandler(ctx, tx, sim)
92+
}
93+
}
94+
95+
// handle as totally normal Cosmos SDK tx
96+
switch tx.(type) {
97+
case sdk.Tx:
98+
// default: handle as normal Cosmos SDK tx
99+
anteHandler = newCosmosAnteHandler(options)
100+
101+
// if tx is a system tx, and singer is authorized, use system tx handler
102+
103+
// isAuthorized := func(creator string) bool {
104+
// return options.ObserverKeeper.IsNonTombstonedObserver(ctx, creator)
105+
// }
106+
// if IsSystemTx(tx, isAuthorized) {
107+
// anteHandler = newCosmosAnteHandlerForSystemTx(options)
108+
// }
109+
110+
// if tx is MsgCreatorValidator, use the newCosmosAnteHandlerForSystemTx handler to
111+
// exempt gas fee requirement in genesis because it's not possible to pay gas fee in genesis
112+
if len(tx.GetMsgs()) == 1 {
113+
if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 {
114+
anteHandler = newCosmosAnteHandlerForSystemTx(options)
115+
}
116+
}
117+
118+
default:
119+
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx)
120+
}
121+
122+
return anteHandler(ctx, tx, sim)
123+
}, nil
124+
}
125+
126+
func Recover(logger tmlog.Logger, err *error) {
127+
if r := recover(); r != nil {
128+
if err != nil {
129+
// #nosec G703 err is checked non-nil above
130+
*err = errorsmod.Wrapf(errortypes.ErrPanic, "%v", r)
131+
}
132+
133+
if e, ok := r.(error); ok {
134+
logger.Error(
135+
"ante handler panicked",
136+
"error", e,
137+
"stack trace", string(debug.Stack()),
138+
)
139+
} else {
140+
logger.Error(
141+
"ante handler panicked",
142+
"recover", fmt.Sprintf("%v", r),
143+
)
144+
}
145+
}
146+
}
147+
148+
// IsSystemTx determines whether tx is a system tx that's signed by an authorized signer
149+
// system tx are special types of txs (see in the switch below), or such txs wrapped inside a MsgExec
150+
// the parameter isAuthorizedSigner is a caller specified function that determines whether the signer of
151+
// the tx is authorized.
152+
func IsSystemTx(tx sdk.Tx, isAuthorizedSigner func(string) bool) bool {
153+
// the following determines whether the tx is a system tx which will uses different handler
154+
// System txs are always single Msg txs, optionally wrapped by one level of MsgExec
155+
if len(tx.GetMsgs()) != 1 { // this is not a system tx
156+
return false
157+
}
158+
// msg := tx.GetMsgs()[0]
159+
160+
// if wrapped inside a MsgExec, unwrap it and reveal the innerMsg.
161+
// var innerMsg sdk.Msg
162+
// innerMsg = msg
163+
// if mm, ok := msg.(*authz.MsgExec); ok { // authz tx; look inside it
164+
// msgs, err := mm.GetMessages()
165+
// if err == nil && len(msgs) == 1 {
166+
// innerMsg = msgs[0]
167+
// }
168+
// }
169+
// switch innerMsg.(type) {
170+
// case *crosschaintypes.MsgVoteGasPrice,
171+
// *crosschaintypes.MsgVoteOutbound,
172+
// *crosschaintypes.MsgVoteInbound,
173+
// *crosschaintypes.MsgAddOutboundTracker,
174+
// *crosschaintypes.MsgAddInboundTracker,
175+
// *observertypes.MsgVoteBlockHeader,
176+
// *observertypes.MsgVoteTSS,
177+
// *observertypes.MsgVoteBlame:
178+
// signers := innerMsg.GetSigners()
179+
// if len(signers) == 1 {
180+
// return isAuthorizedSigner(signers[0].String())
181+
// }
182+
// }
183+
184+
return false
185+
}

app/ante/authz.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package ante
2+
3+
import (
4+
"fmt"
5+
6+
errorsmod "cosmossdk.io/errors"
7+
sdk "github.com/cosmos/cosmos-sdk/types"
8+
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
9+
"github.com/cosmos/cosmos-sdk/x/authz"
10+
"github.com/cosmos/cosmos-sdk/x/group"
11+
)
12+
13+
// maxNestedMsgs defines a cap for the number of nested messages on a MsgExec message
14+
const maxNestedMsgs = 15
15+
16+
// AuthzLimiterDecorator blocks certain msg types from being granted or executed
17+
// within the authorization module.
18+
type AuthzLimiterDecorator struct {
19+
// disabledMsgTypes is the type urls of the msgs to block.
20+
disabledMsgTypes []string
21+
}
22+
23+
// NewAuthzLimiterDecorator creates a decorator to block certain msg types from being granted or executed within authz.
24+
func NewAuthzLimiterDecorator(disabledMsgTypes ...string) AuthzLimiterDecorator {
25+
return AuthzLimiterDecorator{
26+
disabledMsgTypes: disabledMsgTypes,
27+
}
28+
}
29+
30+
func (ald AuthzLimiterDecorator) AnteHandle(
31+
ctx sdk.Context,
32+
tx sdk.Tx,
33+
simulate bool,
34+
next sdk.AnteHandler,
35+
) (newCtx sdk.Context, err error) {
36+
if err := ald.checkDisabledMsgs(tx.GetMsgs(), false, 1); err != nil {
37+
return ctx, errorsmod.Wrap(errortypes.ErrUnauthorized, err.Error())
38+
}
39+
return next(ctx, tx, simulate)
40+
}
41+
42+
// checkDisabledMsgs iterates through the msgs and returns an error if it finds any unauthorized msgs.
43+
//
44+
// When searchOnlyInAuthzMsgs is enabled, only authz MsgGrant and MsgExec are blocked, if they contain unauthorized msg types.
45+
// Otherwise any msg matching the disabled types are blocked, regardless of being in an authz msg or not.
46+
//
47+
// This method is recursive as MsgExec's can wrap other MsgExecs. The check for nested messages is performed up to the
48+
// maxNestedMsgs threshold. If there are more than that limit, it returns an error
49+
func (ald AuthzLimiterDecorator) checkDisabledMsgs(msgs []sdk.Msg, isAuthzInnerMsg bool, nestedLvl int) error {
50+
if nestedLvl >= maxNestedMsgs {
51+
return fmt.Errorf("found more nested msgs than permited. Limit is : %d", maxNestedMsgs)
52+
}
53+
for _, msg := range msgs {
54+
switch msg := msg.(type) {
55+
case *authz.MsgExec:
56+
innerMsgs, err := msg.GetMessages()
57+
if err != nil {
58+
return err
59+
}
60+
nestedLvl++
61+
if err := ald.checkDisabledMsgs(innerMsgs, true, nestedLvl); err != nil {
62+
return err
63+
}
64+
case *group.MsgSubmitProposal:
65+
innerMsgs, err := msg.GetMsgs()
66+
if err != nil {
67+
return err
68+
}
69+
nestedLvl++
70+
if err := ald.checkDisabledMsgs(innerMsgs, true, nestedLvl); err != nil {
71+
return err
72+
}
73+
case *authz.MsgGrant:
74+
authorization, err := msg.GetAuthorization()
75+
if err != nil {
76+
return err
77+
}
78+
79+
url := authorization.MsgTypeURL()
80+
if ald.isDisabledMsg(url) {
81+
return fmt.Errorf("found disabled msg type: %s", url)
82+
}
83+
84+
default:
85+
url := sdk.MsgTypeURL(msg)
86+
if isAuthzInnerMsg && ald.isDisabledMsg(url) {
87+
return fmt.Errorf("found disabled msg type: %s", url)
88+
}
89+
}
90+
}
91+
return nil
92+
}
93+
94+
// isDisabledMsg returns true if the given message is in the list of restricted
95+
// messages from the AnteHandler.
96+
func (ald AuthzLimiterDecorator) isDisabledMsg(msgTypeURL string) bool {
97+
for _, disabledType := range ald.disabledMsgTypes {
98+
if msgTypeURL == disabledType {
99+
return true
100+
}
101+
}
102+
103+
return false
104+
}

0 commit comments

Comments
 (0)