Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move feegrant ante to auth ante #8682

Merged
merged 39 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d7b83ba
move feegrant ante to auth ante
atheeshp Feb 22, 2021
967dd28
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Feb 24, 2021
d692f10
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Feb 25, 2021
b229812
update ante builder
atheeshp Feb 26, 2021
7eb8897
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Feb 26, 2021
f3874a7
Merge branch 'atheesh/move_feegrant_ante' of github.com:cosmos/cosmos…
atheeshp Feb 26, 2021
c8b38fa
remove commented code
atheeshp Feb 26, 2021
d1d74b8
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 3, 2021
8bd1cfe
review changes
atheeshp Mar 5, 2021
b282167
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 5, 2021
5e2c190
fix lint
atheeshp Mar 5, 2021
3c6c8a1
review changes
atheeshp Mar 5, 2021
3d633df
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 5, 2021
f29391f
review changes
atheeshp Mar 8, 2021
81bfce6
review changes
atheeshp Mar 8, 2021
a652ace
review changes
atheeshp Mar 8, 2021
6fa68e3
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 8, 2021
8fdf57b
fix ante builder
atheeshp Mar 8, 2021
a1e986c
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 9, 2021
87f2ecd
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 9, 2021
88b38e5
review changes
atheeshp Mar 9, 2021
6fd08a2
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 12, 2021
2355779
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 12, 2021
3d72ad3
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 18, 2021
b5404aa
update ante builder with options struct
atheeshp Mar 18, 2021
587b681
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 18, 2021
4343835
Merge branch 'atheesh/move_feegrant_ante' of github.com:cosmos/cosmos…
atheeshp Mar 18, 2021
576a93a
review changes
atheeshp Mar 18, 2021
0e47dcf
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 18, 2021
6ac8011
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 19, 2021
943190c
review changes
atheeshp Mar 19, 2021
3e4649c
Merge branch 'atheesh/move_feegrant_ante' of github.com:cosmos/cosmos…
atheeshp Mar 19, 2021
bb91e5b
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 20, 2021
7c08eba
Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/mo…
atheeshp Mar 22, 2021
e852d05
add changelog
atheeshp Mar 22, 2021
7ca23a6
Merge branch 'atheesh/move_feegrant_ante' of github.com:cosmos/cosmos…
atheeshp Mar 22, 2021
dcfdf08
Merge branch 'master' into atheesh/move_feegrant_ante
amaury1093 Mar 22, 2021
4a6199f
Merge branch 'master' into atheesh/move_feegrant_ante
aaronc Mar 22, 2021
148294a
Merge branch 'master' into atheesh/move_feegrant_ante
atheeshp Mar 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -435,7 +434,7 @@ func NewSimApp(
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(
feegrantante.NewAnteHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, ante.DefaultSigVerificationGasConsumer,
encodingConfig.TxConfig.SignModeHandler(),
),
Expand Down
8 changes: 5 additions & 3 deletions x/auth/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper"
)

// 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,
ak AccountKeeper, bankKeeper types.BankKeeper, feeGrantKeeper feegrantkeeper.Keeper,
sigGasConsumer SignatureVerificationGasConsumer,
signModeHandler signing.SignModeHandler,
) sdk.AnteHandler {
Expand All @@ -22,10 +23,11 @@ func NewAnteHandler(
TxTimeoutHeightDecorator{},
NewValidateMemoDecorator(ak),
NewConsumeGasForTxSizeDecorator(ak),
NewRejectFeeGranterDecorator(),
NewDeductGrantedFeeDecorator(ak, bankKeeper, feeGrantKeeper),
atheeshp marked this conversation as resolved.
Show resolved Hide resolved
// NewRejectFeeGranterDecorator(),
NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
NewValidateSigCountDecorator(ak),
NewDeductFeeDecorator(ak, bankKeeper),
// NewDeductFeeDecorator(ak, bankKeeper),
NewSigGasConsumeDecorator(ak, sigGasConsumer),
NewSigVerificationDecorator(ak, signModeHandler),
NewIncrementSequenceDecorator(ak),
Expand Down
2 changes: 1 addition & 1 deletion x/auth/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ 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 {
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, 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")
Expand Down
2 changes: 2 additions & 0 deletions x/auth/ante/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ type AccountKeeper interface {
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
SetAccount(ctx sdk.Context, acc types.AccountI)
GetModuleAddress(moduleName string) sdk.AccAddress
GetModuleAccount(ctx sdk.Context, moduleName string) types.ModuleAccountI
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
}
81 changes: 81 additions & 0 deletions x/auth/ante/feegrant_ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ante

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
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 = DeductFees(d.bk, ctx, deductFeesFromAcc, fee)
if err != nil {
return ctx, err
}

return next(ctx, tx, simulate)
}
242 changes: 242 additions & 0 deletions x/auth/ante/feegrant_ante_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package ante_test

import (
"math/rand"
"testing"
"time"

"github.com/tendermint/tendermint/crypto"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"

"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"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/types"
)

func (suite *AnteTestSuite) TestDeductFeesNoDelegation() {
suite.SetupTest(false)
// setup
app, ctx := suite.app, suite.ctx

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)

// this tests the whole stack
anteHandlerStack := suite.anteHandler

// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()
priv4, _, addr4 := testdata.KeyTestPubAddr()
priv5, _, addr5 := testdata.KeyTestPubAddr()

// Set addr1 with insufficient funds
err := simapp.FundAccount(suite.app, suite.ctx, addr1, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))})
suite.Require().NoError(err)

// Set addr2 with more funds
err = simapp.FundAccount(suite.app, suite.ctx, addr2, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(99999))})
suite.Require().NoError(err)

// grant fee allowance from `addr2` to `addr3` (plenty to pay)
err = app.FeeGrantKeeper.GrantFeeAllowance(ctx, addr2, addr3, &types.BasicFeeAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 500)),
})
suite.Require().NoError(err)

// grant low fee allowance (20atom), to check the tx requesting more than allowed.
err = app.FeeGrantKeeper.GrantFeeAllowance(ctx, addr2, addr4, &types.BasicFeeAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 20)),
})
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
}{
"paying with low funds (only ours)": {
signerKey: priv1,
signer: addr1,
fee: 50,
handler: ourAnteHandler,
valid: false,
},
"paying with good funds (only ours)": {
signerKey: priv2,
signer: addr2,
fee: 50,
handler: ourAnteHandler,
valid: true,
},
"paying with no account (only ours)": {
signerKey: priv3,
signer: addr3,
fee: 1,
handler: ourAnteHandler,
valid: false,
},
"no fee with real account (only ours)": {
signerKey: priv1,
signer: addr1,
fee: 0,
handler: ourAnteHandler,
valid: true,
},
"no fee with no account (only ours)": {
signerKey: priv5,
signer: addr5,
fee: 0,
handler: ourAnteHandler,
valid: false,
},
"valid fee grant without account (only ours)": {
signerKey: priv3,
signer: addr3,
feeAccount: addr2,
fee: 50,
handler: ourAnteHandler,
valid: true,
},
"no fee grant (only ours)": {
signerKey: priv3,
signer: addr3,
feeAccount: addr1,
fee: 2,
handler: ourAnteHandler,
valid: false,
},
"allowance smaller than requested fee (only ours)": {
signerKey: priv4,
signer: addr4,
feeAccount: addr2,
fee: 50,
handler: ourAnteHandler,
valid: false,
},
"granter cannot cover allowed fee grant (only ours)": {
signerKey: priv4,
signer: addr4,
feeAccount: addr1,
fee: 50,
handler: ourAnteHandler,
valid: false,
},
}

for name, stc := range cases {
tc := stc // to make scopelint happy
suite.T().Run(name, func(t *testing.T) {
fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee))
msgs := []sdk.Msg{testdata.NewTestMsg(tc.signer)}

acc := app.AccountKeeper.GetAccount(ctx, tc.signer)
privs, accNums, seqs := []cryptotypes.PrivKey{tc.signerKey}, []uint64{0}, []uint64{0}
if acc != nil {
accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()}
}

tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...)
suite.Require().NoError(err)
_, err = ourAnteHandler(ctx, tx, false)
if tc.valid {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}

_, err = anteHandlerStack(ctx, tx, false)
if tc.valid {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

// don't consume any gas
func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error {
return nil
}

func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums,
accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey) (sdk.Tx, error) {
sigs := make([]signing.SignatureV2, len(priv))

// create a random length memo
r := rand.New(rand.NewSource(time.Now().UnixNano()))

memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))

signMode := gen.SignModeHandler().DefaultMode()

// 1st round: set SignatureV2 with empty signatures, to set correct
// signer infos.
for i, p := range priv {
sigs[i] = signing.SignatureV2{
PubKey: p.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signMode,
},
Sequence: accSeqs[i],
}
}

tx := gen.NewTxBuilder()
err := tx.SetMsgs(msgs...)
if err != nil {
return nil, err
}
err = tx.SetSignatures(sigs...)
if err != nil {
return nil, err
}
tx.SetMemo(memo)
tx.SetFeeAmount(feeAmt)
tx.SetGasLimit(gas)
tx.SetFeeGranter(feeGranter)

// 2nd round: once all signer infos are set, every signer can sign.
for i, p := range priv {
signerData := authsign.SignerData{
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
}
signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx())
if err != nil {
panic(err)
}
sig, err := p.Sign(signBytes)
if err != nil {
panic(err)
}
sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
err = tx.SetSignatures(sigs...)
if err != nil {
panic(err)
}
}

return tx.GetTx(), nil
}
2 changes: 1 addition & 1 deletion x/auth/ante/sigverify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ 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())
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.FeeGrantKeeper, ante.DefaultSigVerificationGasConsumer, txConfig.SignModeHandler())

suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()

Expand Down
Loading