generated from dymensionxyz/rollapp
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create account if not found and skip fees for IBC relayer messages
- Loading branch information
Showing
8 changed files
with
512 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package app | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" | ||
conntypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" | ||
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" | ||
) | ||
|
||
type anteHandler interface { | ||
AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) | ||
} | ||
|
||
type BypassIBCFeeDecorator struct { | ||
nextAnte anteHandler | ||
} | ||
|
||
func NewBypassIBCFeeDecorator(nextAnte anteHandler) BypassIBCFeeDecorator { | ||
return BypassIBCFeeDecorator{nextAnte: nextAnte} | ||
} | ||
|
||
// SKIP FEE DEDUCT and MIN GAS PRICE Ante handlers for IBC relayer messages | ||
func (n BypassIBCFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { | ||
// ======== HACK ================ | ||
if isIBCRelayerMsg(tx.GetMsgs()) { | ||
return next(ctx, tx, simulate) | ||
} | ||
// ============================== | ||
|
||
// If it's not an IBC Relayer transfer, proceed with the default fee handling | ||
return n.nextAnte.AnteHandle(ctx, tx, simulate, next) | ||
} | ||
|
||
// isIBCRelayerMsg checks if all the messages in the transaction are IBC relayer messages | ||
func isIBCRelayerMsg(msgs []sdk.Msg) bool { | ||
isIBCRelayer := false | ||
|
||
for _, msg := range msgs { | ||
switch msg.(type) { | ||
// IBC Client Messages | ||
case *clienttypes.MsgCreateClient, *clienttypes.MsgUpdateClient, | ||
*clienttypes.MsgUpgradeClient, *clienttypes.MsgSubmitMisbehaviour: | ||
isIBCRelayer = true | ||
|
||
// IBC Connection Messages | ||
case *conntypes.MsgConnectionOpenInit, *conntypes.MsgConnectionOpenTry, | ||
*conntypes.MsgConnectionOpenAck, *conntypes.MsgConnectionOpenConfirm: | ||
isIBCRelayer = true | ||
|
||
// IBC Channel Messages | ||
case *channeltypes.MsgChannelOpenInit, *channeltypes.MsgChannelOpenTry, | ||
*channeltypes.MsgChannelOpenAck, *channeltypes.MsgChannelOpenConfirm, | ||
*channeltypes.MsgChannelCloseInit, *channeltypes.MsgChannelCloseConfirm: | ||
isIBCRelayer = true | ||
|
||
// IBC Packet Messages | ||
case *channeltypes.MsgRecvPacket, *channeltypes.MsgAcknowledgement, | ||
*channeltypes.MsgTimeout, *channeltypes.MsgTimeoutOnClose: | ||
isIBCRelayer = true | ||
default: | ||
return false | ||
} | ||
} | ||
|
||
return isIBCRelayer | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package app | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" | ||
"github.com/cosmos/cosmos-sdk/x/auth/types" | ||
) | ||
|
||
type createAccountDecorator struct { | ||
ak accountKeeper | ||
} | ||
|
||
type accountKeeper interface { | ||
authante.AccountKeeper | ||
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) types.AccountI | ||
} | ||
|
||
func NewCreateAccountDecorator(ak accountKeeper) createAccountDecorator { | ||
return createAccountDecorator{ak: ak} | ||
} | ||
|
||
const newAccountCtxKeyPrefix = "new-account/" | ||
|
||
func CtxKeyNewAccount(acc string) string { | ||
return newAccountCtxKeyPrefix + acc | ||
} | ||
|
||
func (cad createAccountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { | ||
sigTx, ok := tx.(authsigning.SigVerifiableTx) | ||
if !ok { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") | ||
} | ||
|
||
pubkeys, err := sigTx.GetPubKeys() | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
ibcRelayerMsg := isIBCRelayerMsg(tx.GetMsgs()) | ||
|
||
for i, pk := range pubkeys { | ||
if pk == nil { | ||
continue | ||
} | ||
|
||
acc, err := authante.GetSignerAcc(ctx, cad.ak, sigTx.GetSigners()[i]) | ||
Check failure on line 48 in app/create_account_decorator.go
|
||
if err != nil { | ||
// ======= HACK ========================= | ||
// for IBC relayer messages, create an account if it doesn't exist | ||
if ibcRelayerMsg { | ||
address := sdk.AccAddress(pk.Address()) | ||
acc = cad.ak.NewAccountWithAddress(ctx, address) | ||
// inject the new account flag into the context, in order to signal | ||
// the account creation to the subsequent decorators (sigchecker) | ||
ctx = ctx.WithValue(CtxKeyNewAccount(address.String()), struct{}{}) | ||
cad.ak.SetAccount(ctx, acc) | ||
} else { | ||
return ctx, err | ||
} | ||
// ====================================== | ||
} | ||
} | ||
|
||
return next(ctx, tx, simulate) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package app | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" | ||
) | ||
|
||
type sigCheckDecorator struct { | ||
ak accountKeeper | ||
signModeHandler authsigning.SignModeHandler | ||
} | ||
|
||
func NewSigCheckDecorator(ak accountKeeper, signModeHandler authsigning.SignModeHandler) sigCheckDecorator { | ||
return sigCheckDecorator{ak: ak, signModeHandler: signModeHandler} | ||
} | ||
|
||
// Copied from github.com/cosmos/[email protected]/x/auth/ante/sigverify.go:235 | ||
// and modified to set account number to 0 when verifying for IBC relayer messages from a new account | ||
func (svd sigCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { | ||
sigTx, ok := tx.(authsigning.SigVerifiableTx) | ||
if !ok { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") | ||
} | ||
|
||
// stdSigs contains the sequence number, account number, and signatures. | ||
// When simulating, this would just be a 0-length slice. | ||
sigs, err := sigTx.GetSignaturesV2() | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
signerAddrs := sigTx.GetSigners() | ||
|
||
// check that signer length and signature length are the same | ||
if len(sigs) != len(signerAddrs) { | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs)) | ||
} | ||
|
||
ibcRelayerMsg := isIBCRelayerMsg(tx.GetMsgs()) | ||
|
||
for i, sig := range sigs { | ||
acc, err := authante.GetSignerAcc(ctx, svd.ak, signerAddrs[i]) | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
// retrieve pubkey | ||
pubKey := acc.GetPubKey() | ||
if !simulate && pubKey == nil { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set") | ||
} | ||
|
||
// Check account sequence number. | ||
if sig.Sequence != acc.GetSequence() { | ||
return ctx, sdkerrors.Wrapf( | ||
sdkerrors.ErrWrongSequence, | ||
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, | ||
) | ||
} | ||
|
||
// retrieve signer data | ||
genesis := ctx.BlockHeight() == 0 | ||
chainID := ctx.ChainID() | ||
var accNum uint64 | ||
|
||
// ======= HACK ==================== | ||
_, isNewAcc := ctx.Value(CtxKeyNewAccount(acc.GetAddress().String())).(struct{}) | ||
isNewRelayerAcc := ibcRelayerMsg && isNewAcc | ||
if !genesis && !isNewRelayerAcc { | ||
accNum = acc.GetAccountNumber() | ||
} | ||
// ================================= | ||
|
||
signerData := authsigning.SignerData{ | ||
Address: acc.GetAddress().String(), | ||
ChainID: chainID, | ||
AccountNumber: accNum, | ||
Sequence: acc.GetSequence(), | ||
PubKey: pubKey, | ||
} | ||
|
||
// no need to verify signatures on recheck tx | ||
if !simulate && !ctx.IsReCheckTx() { | ||
err := authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx) | ||
if err != nil { | ||
var errMsg string | ||
if authante.OnlyLegacyAminoSigners(sig.Data) { | ||
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number, | ||
// and therefore communicate sequence number as a potential cause of error. | ||
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID) | ||
} else { | ||
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID) | ||
} | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg) | ||
|
||
} | ||
} | ||
} | ||
|
||
return next(ctx, tx, simulate) | ||
} |
Oops, something went wrong.