diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2020c9cfa4..e6231efc919d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/bank) [\#8517](https://github.com/cosmos/cosmos-sdk/pull/8517) `SupplyI` interface and `Supply` are removed and uses `sdk.Coins` for supply tracking * (x/upgrade) [\#8743](https://github.com/cosmos/cosmos-sdk/pull/8743) `UpgradeHandler` includes a new argument `VersionMap` which helps facilitate in-place migrations. * (x/auth) [\#8129](https://github.com/cosmos/cosmos-sdk/pull/8828) Updated `SigVerifiableTx.GetPubKeys` method signature to return error. +* [\#8682](https://github.com/cosmos/cosmos-sdk/pull/8682) `ante.NewAnteHandler` updated to receive all positional params as `ante.HandlerOptions` struct. If required fields aren't set, throws error accordingly. ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index 97a71d4015e4..e0c4316f30a0 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -56,7 +56,6 @@ import ( evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" feegrant "github.com/cosmos/cosmos-sdk/x/feegrant" - feegrantante "github.com/cosmos/cosmos-sdk/x/feegrant/ante" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegranttypes "github.com/cosmos/cosmos-sdk/x/feegrant/types" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -375,12 +374,22 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler( - feegrantante.NewAnteHandler( - app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, ante.DefaultSigVerificationGasConsumer, - encodingConfig.TxConfig.SignModeHandler(), - ), + + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + FeegrantKeeper: app.FeeGrantKeeper, + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, ) + + if err != nil { + panic(err) + } + + app.SetAnteHandler(anteHandler) app.SetEndBlocker(app.EndBlocker) if loadLatest { diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index 8cc025bad2d2..8df98f0e42c2 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -2,32 +2,57 @@ package ante import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/signing" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/types" ) +// HandlerOptions are the options required for constructing a default SDK AnteHandler. +type HandlerOptions struct { + AccountKeeper AccountKeeper + BankKeeper types.BankKeeper + FeegrantKeeper FeegrantKeeper + SignModeHandler authsigning.SignModeHandler + SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error +} + // NewAnteHandler returns an AnteHandler that checks and increments sequence // numbers, checks signatures & account numbers, and deducts fees from the first // signer. -func NewAnteHandler( - ak AccountKeeper, bankKeeper types.BankKeeper, - sigGasConsumer SignatureVerificationGasConsumer, - signModeHandler signing.SignModeHandler, -) sdk.AnteHandler { - return sdk.ChainAnteDecorators( +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { + if options.AccountKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder") + } + + if options.BankKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder") + } + + if options.SignModeHandler == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + } + + var sigGasConsumer = options.SigGasConsumer + if sigGasConsumer == nil { + sigGasConsumer = DefaultSigVerificationGasConsumer + } + + anteDecorators := []sdk.AnteDecorator{ NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first NewRejectExtensionOptionsDecorator(), NewMempoolFeeDecorator(), NewValidateBasicDecorator(), TxTimeoutHeightDecorator{}, - NewValidateMemoDecorator(ak), - NewConsumeGasForTxSizeDecorator(ak), - NewRejectFeeGranterDecorator(), - NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators - NewValidateSigCountDecorator(ak), - NewDeductFeeDecorator(ak, bankKeeper), - NewSigGasConsumeDecorator(ak, sigGasConsumer), - NewSigVerificationDecorator(ak, signModeHandler), - NewIncrementSequenceDecorator(ak), - ) + NewValidateMemoDecorator(options.AccountKeeper), + NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators + NewValidateSigCountDecorator(options.AccountKeeper), + NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), + NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + NewIncrementSequenceDecorator(options.AccountKeeper), + } + + return sdk.ChainAnteDecorators(anteDecorators...), nil } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index cb45492bd551..f36db301f6c1 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -1010,15 +1010,26 @@ func (suite *AnteTestSuite) TestCustomSignatureVerificationGasConsumer() { suite.SetupTest(false) // setup // setup an ante handler that only accepts PubKeyEd25519 - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error { - switch pubkey := sig.PubKey.(type) { - case *ed25519.PubKey: - meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") - return nil - default: - return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) - } - }, suite.clientCtx.TxConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: suite.clientCtx.TxConfig.SignModeHandler(), + SigGasConsumer: func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error { + switch pubkey := sig.PubKey.(type) { + case *ed25519.PubKey: + meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") + return nil + default: + return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) + } + }, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler // Same data for every test cases accounts := suite.CreateTestAccounts(1) diff --git a/x/auth/ante/expected_keepers.go b/x/auth/ante/expected_keepers.go index d8be4312e5cf..e9c2286f0321 100644 --- a/x/auth/ante/expected_keepers.go +++ b/x/auth/ante/expected_keepers.go @@ -13,3 +13,8 @@ type AccountKeeper interface { SetAccount(ctx sdk.Context, acc types.AccountI) GetModuleAddress(moduleName string) sdk.AccAddress } + +// FeegrantKeeper defines the expected feegrant keeper. +type FeegrantKeeper interface { + UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins) error +} diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 5da4dbbaf5d5..3cc6aee10cf4 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -59,14 +59,16 @@ func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // Call next AnteHandler if fees successfully deducted // CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator type DeductFeeDecorator struct { - ak AccountKeeper - bankKeeper types.BankKeeper + ak AccountKeeper + bankKeeper types.BankKeeper + feegrantKeeper FeegrantKeeper } -func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper) DeductFeeDecorator { +func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper) DeductFeeDecorator { return DeductFeeDecorator{ - ak: ak, - bankKeeper: bk, + ak: ak, + bankKeeper: bk, + feegrantKeeper: fk, } } @@ -80,16 +82,36 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName)) } + fee := feeTx.GetFee() feePayer := feeTx.FeePayer() - feePayerAcc := dfd.ak.GetAccount(ctx, feePayer) + feeGranter := feeTx.FeeGranter() - if feePayerAcc == nil { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", feePayer) + deductFeesFrom := feePayer + + // if feegranter set deduct fee from feegranter account. + // this works with only when feegrant enabled. + if feeGranter != nil { + if dfd.feegrantKeeper == nil { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled") + } else if !feeGranter.Equals(feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee) + + if err != nil { + return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) } // deduct the fees if !feeTx.GetFee().IsZero() { - err = DeductFees(dfd.bankKeeper, ctx, feePayerAcc, feeTx.GetFee()) + err = DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, feeTx.GetFee()) if err != nil { return ctx, err } diff --git a/x/auth/ante/fee_grant.go b/x/auth/ante/fee_grant.go deleted file mode 100644 index 2c37fffa098a..000000000000 --- a/x/auth/ante/fee_grant.go +++ /dev/null @@ -1,27 +0,0 @@ -package ante - -import ( - "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// RejectFeeGranterDecorator is an AnteDecorator which rejects transactions which -// have the Fee.granter field set. It is to be used by chains which do not support -// fee grants. -type RejectFeeGranterDecorator struct{} - -// NewRejectFeeGranterDecorator returns a new RejectFeeGranterDecorator. -func NewRejectFeeGranterDecorator() RejectFeeGranterDecorator { - return RejectFeeGranterDecorator{} -} - -var _ types.AnteDecorator = RejectFeeGranterDecorator{} - -func (d RejectFeeGranterDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (newCtx types.Context, err error) { - feeTx, ok := tx.(types.FeeTx) - if ok && len(feeTx.FeeGranter()) != 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not supported") - } - - return next(ctx, tx, simulate) -} diff --git a/x/auth/ante/fee_grant_test.go b/x/auth/ante/fee_grant_test.go deleted file mode 100644 index 2f07300c7fc4..000000000000 --- a/x/auth/ante/fee_grant_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package ante_test - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/auth/tx" -) - -type setFeeGranter interface { - SetFeeGranter(feeGranter sdk.AccAddress) -} - -func (suite *AnteTestSuite) TestRejectFeeGranter() { - suite.SetupTest(true) // setup - txConfig := tx.NewTxConfig(codec.NewProtoCodec(types.NewInterfaceRegistry()), tx.DefaultSignModes) - txBuilder := txConfig.NewTxBuilder() - d := ante.NewRejectFeeGranterDecorator() - antehandler := sdk.ChainAnteDecorators(d) - - _, err := antehandler(suite.ctx, txBuilder.GetTx(), false) - suite.Require().NoError(err) - - setGranterTx := txBuilder.(setFeeGranter) - _, _, addr := testdata.KeyTestPubAddr() - setGranterTx.SetFeeGranter(addr) - - _, err = antehandler(suite.ctx, txBuilder.GetTx(), false) - suite.Require().Error(err) -} diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index 343e814583d2..46ff5cebc7b1 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -86,7 +86,7 @@ func (suite *AnteTestSuite) TestDeductFees() { err = simapp.FundAccount(suite.app, suite.ctx, addr1, coins) suite.Require().NoError(err) - dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper) + dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper, nil) antehandler := sdk.ChainAnteDecorators(dfd) _, err = antehandler(suite.ctx, tx, false) diff --git a/x/feegrant/ante/fee_test.go b/x/auth/ante/feegrant_test.go similarity index 67% rename from x/feegrant/ante/fee_test.go rename to x/auth/ante/feegrant_test.go index 1a924db6a387..76ed106ec36a 100644 --- a/x/feegrant/ante/fee_test.go +++ b/x/auth/ante/feegrant_test.go @@ -5,9 +5,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -19,42 +17,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/types/tx/signing" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/ante" authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/feegrant/ante" "github.com/cosmos/cosmos-sdk/x/feegrant/types" ) -// AnteTestSuite is a test suite to be used with ante handler tests. -type AnteTestSuite struct { - suite.Suite - - app *simapp.SimApp - anteHandler sdk.AnteHandler - ctx sdk.Context - clientCtx client.Context - txBuilder client.TxBuilder -} - -// SetupTest setups a new test, with new app, context, and anteHandler. -func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { - suite.app, suite.ctx = createTestApp(isCheckTx) - suite.ctx = suite.ctx.WithBlockHeight(1) - - // Set up TxConfig. - encodingConfig := simapp.MakeTestEncodingConfig() - // We're using TestMsg encoding in some tests, so register it here. - encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) - testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry) - - suite.clientCtx = client.Context{}. - WithTxConfig(encodingConfig.TxConfig) - - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, authante.DefaultSigVerificationGasConsumer, encodingConfig.TxConfig.SignModeHandler()) -} - func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { suite.SetupTest(false) // setup @@ -63,8 +32,8 @@ func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes) // this just tests our handler - dfd := ante.NewDeductGrantedFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper) - ourAnteHandler := sdk.ChainAnteDecorators(dfd) + dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper) + feeAnteHandler := sdk.ChainAnteDecorators(dfd) // this tests the whole stack anteHandlerStack := suite.anteHandler @@ -97,79 +66,68 @@ func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { suite.Require().NoError(err) cases := map[string]struct { - signerKey cryptotypes.PrivKey - signer sdk.AccAddress - feeAccount sdk.AccAddress - feeAccountKey cryptotypes.PrivKey - handler sdk.AnteHandler - fee int64 - valid bool + signerKey cryptotypes.PrivKey + signer sdk.AccAddress + feeAccount sdk.AccAddress + fee int64 + valid bool }{ - "paying with low funds (only ours)": { + "paying with low funds": { signerKey: priv1, signer: addr1, fee: 50, - handler: ourAnteHandler, valid: false, }, - "paying with good funds (only ours)": { + "paying with good funds": { signerKey: priv2, signer: addr2, fee: 50, - handler: ourAnteHandler, valid: true, }, - "paying with no account (only ours)": { + "paying with no account": { signerKey: priv3, signer: addr3, fee: 1, - handler: ourAnteHandler, valid: false, }, - "no fee with real account (only ours)": { + "no fee with real account": { signerKey: priv1, signer: addr1, fee: 0, - handler: ourAnteHandler, valid: true, }, - "no fee with no account (only ours)": { + "no fee with no account": { signerKey: priv5, signer: addr5, fee: 0, - handler: ourAnteHandler, valid: false, }, - "valid fee grant without account (only ours)": { + "valid fee grant without account": { signerKey: priv3, signer: addr3, feeAccount: addr2, fee: 50, - handler: ourAnteHandler, valid: true, }, - "no fee grant (only ours)": { + "no fee grant": { signerKey: priv3, signer: addr3, feeAccount: addr1, fee: 2, - handler: ourAnteHandler, valid: false, }, - "allowance smaller than requested fee (only ours)": { + "allowance smaller than requested fee": { signerKey: priv4, signer: addr4, feeAccount: addr2, fee: 50, - handler: ourAnteHandler, valid: false, }, - "granter cannot cover allowed fee grant (only ours)": { + "granter cannot cover allowed fee grant": { signerKey: priv4, signer: addr4, feeAccount: addr1, fee: 50, - handler: ourAnteHandler, valid: false, }, } @@ -188,14 +146,14 @@ func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...) suite.Require().NoError(err) - _, err = ourAnteHandler(ctx, tx, false) + _, err = feeAnteHandler(ctx, tx, false) // tests only feegrant ante if tc.valid { suite.Require().NoError(err) } else { suite.Require().Error(err) } - _, err = anteHandlerStack(ctx, tx, false) + _, err = anteHandlerStack(ctx, tx, false) // tests while stack if tc.valid { suite.Require().NoError(err) } else { @@ -205,15 +163,6 @@ func (suite *AnteTestSuite) TestDeductFeesNoDelegation() { } } -// returns context and app with params set on account keeper -func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { - app := simapp.Setup(isCheckTx) - ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) - app.AccountKeeper.SetParams(ctx, authtypes.DefaultParams()) - - return app, ctx -} - // don't consume any gas func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error { return nil @@ -280,7 +229,3 @@ func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, return tx.GetTx(), nil } - -func TestAnteTestSuite(t *testing.T) { - suite.Run(t, new(AnteTestSuite)) -} diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index 8eb42888aa6b..6e720ac20353 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -203,7 +203,18 @@ func (suite *AnteTestSuite) TestSigVerification_ExplicitAmino() { suite.clientCtx = client.Context{}. WithTxConfig(txConfig) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, ante.DefaultSigVerificationGasConsumer, txConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: txConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() diff --git a/x/auth/ante/testutil_test.go b/x/auth/ante/testutil_test.go index 78af9743eadd..74216420eb14 100644 --- a/x/auth/ante/testutil_test.go +++ b/x/auth/ante/testutil_test.go @@ -63,7 +63,18 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { suite.clientCtx = client.Context{}. WithTxConfig(encodingConfig.TxConfig) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, ante.DefaultSigVerificationGasConsumer, encodingConfig.TxConfig.SignModeHandler()) + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: suite.app.AccountKeeper, + BankKeeper: suite.app.BankKeeper, + FeegrantKeeper: suite.app.FeeGrantKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + ) + + suite.Require().NoError(err) + suite.anteHandler = anteHandler } // CreateTestAccounts creates `numAccs` accounts, and return all relevant diff --git a/x/feegrant/ante/ante.go b/x/feegrant/ante/ante.go deleted file mode 100644 index 483868c23e16..000000000000 --- a/x/feegrant/ante/ante.go +++ /dev/null @@ -1,35 +0,0 @@ -package ante - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/signing" - feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" - feegranttypes "github.com/cosmos/cosmos-sdk/x/feegrant/types" -) - -// NewAnteHandler returns an AnteHandler that checks and increments sequence -// numbers, checks signatures & account numbers, and deducts fees from the -// fee_payer or from fee_granter (if valid grant exist). -func NewAnteHandler( - ak authkeeper.AccountKeeper, bankKeeper feegranttypes.BankKeeper, feeGrantKeeper feegrantkeeper.Keeper, - sigGasConsumer authante.SignatureVerificationGasConsumer, signModeHandler signing.SignModeHandler, -) sdk.AnteHandler { - - return sdk.ChainAnteDecorators( - authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - authante.NewRejectExtensionOptionsDecorator(), - authante.NewMempoolFeeDecorator(), - authante.NewValidateBasicDecorator(), - authante.TxTimeoutHeightDecorator{}, - authante.NewValidateMemoDecorator(ak), - authante.NewConsumeGasForTxSizeDecorator(ak), - NewDeductGrantedFeeDecorator(ak, bankKeeper, feeGrantKeeper), - authante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators - authante.NewValidateSigCountDecorator(ak), - authante.NewSigGasConsumeDecorator(ak, sigGasConsumer), - authante.NewSigVerificationDecorator(ak, signModeHandler), - authante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator - ) -} diff --git a/x/feegrant/ante/fee.go b/x/feegrant/ante/fee.go deleted file mode 100644 index 52cbda7210eb..000000000000 --- a/x/feegrant/ante/fee.go +++ /dev/null @@ -1,82 +0,0 @@ -package ante - -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" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" - "github.com/cosmos/cosmos-sdk/x/feegrant/types" -) - -// DeductGrantedFeeDecorator deducts fees from fee_payer or fee_granter (if exists a valid fee allowance) of the tx -// If the fee_payer or fee_granter does not have the funds to pay for the fees, return with InsufficientFunds error -// Call next AnteHandler if fees successfully deducted -// CONTRACT: Tx must implement GrantedFeeTx interface to use DeductGrantedFeeDecorator -type DeductGrantedFeeDecorator struct { - ak types.AccountKeeper - k keeper.Keeper - bk types.BankKeeper -} - -func NewDeductGrantedFeeDecorator(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) DeductGrantedFeeDecorator { - return DeductGrantedFeeDecorator{ - ak: ak, - k: k, - bk: bk, - } -} - -// AnteHandle performs a decorated ante-handler responsible for deducting transaction -// fees. Fees will be deducted from the account designated by the FeePayer on a -// transaction by default. However, if the fee payer differs from the transaction -// signer, the handler will check if a fee grant has been authorized. If the -// transaction's signer does not exist, it will be created. -func (d DeductGrantedFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a GrantedFeeTx") - } - - // sanity check from DeductFeeDecorator - if addr := d.ak.GetModuleAddress(authtypes.FeeCollectorName); addr == nil { - panic(fmt.Sprintf("%s module account has not been set", authtypes.FeeCollectorName)) - } - - fee := feeTx.GetFee() - feePayer := feeTx.FeePayer() - feeGranter := feeTx.FeeGranter() - - deductFeesFrom := feePayer - - // ensure the grant is allowed, if we request a different fee payer - if feeGranter != nil && !feeGranter.Equals(feePayer) { - err := d.k.UseGrantedFees(ctx, feeGranter, feePayer, fee) - if err != nil { - return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) - } - - deductFeesFrom = feeGranter - } - - // now, either way, we know that we are authorized to deduct the fees from the deductFeesFrom account - deductFeesFromAcc := d.ak.GetAccount(ctx, deductFeesFrom) - if deductFeesFromAcc == nil { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) - } - - // move on if there is no fee to deduct - if fee.IsZero() { - return next(ctx, tx, simulate) - } - - // deduct fee if non-zero - err = authante.DeductFees(d.bk, ctx, deductFeesFromAcc, fee) - if err != nil { - return ctx, err - } - - return next(ctx, tx, simulate) -} diff --git a/x/feegrant/keeper/keeper.go b/x/feegrant/keeper/keeper.go index e6606bf0ca55..b8f30194ff68 100644 --- a/x/feegrant/keeper/keeper.go +++ b/x/feegrant/keeper/keeper.go @@ -8,6 +8,7 @@ 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/ante" "github.com/cosmos/cosmos-sdk/x/feegrant/types" ) @@ -19,6 +20,8 @@ type Keeper struct { authKeeper types.AccountKeeper } +var _ ante.FeegrantKeeper = &Keeper{} + // NewKeeper creates a fee grant Keeper func NewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper) Keeper { return Keeper{