move feegrant ante to auth ante (#8682)
* move feegrant ante to auth ante * update ante builder * remove commented code * review changes * fix lint * review changes * review changes * review changes * review changes * fix ante builder * review changes * update ante builder with options struct * review changes * review changes * add changelog Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com> Co-authored-by: Aaron Craelius <aaron@regen.network>
This commit is contained in:
parent
e30959ce4a
commit
025d226099
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue