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

Add Fee granter field #7418

Merged
merged 9 commits into from
Oct 5, 2020
5 changes: 5 additions & 0 deletions proto/cosmos/tx/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,9 @@ message Fee {
// the payer must be a tx signer (and thus have signed this field in AuthInfo).
// setting this field does *not* change the ordering of required signers for the transaction.
string payer = 3;

// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used
// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does
// not support fee grants, this will fail
aaronc marked this conversation as resolved.
Show resolved Hide resolved
string granter = 4;
}
161 changes: 108 additions & 53 deletions types/tx/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions types/tx_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type (
GetGas() uint64
GetFee() Coins
FeePayer() AccAddress
FeeGranter() AccAddress
}

// Tx must have GetMemo() method to use ValidateMemoDecorator
Expand Down
1 change: 1 addition & 0 deletions x/auth/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewAnteHandler(
TxTimeoutHeightDecorator{},
NewValidateMemoDecorator(ak),
NewConsumeGasForTxSizeDecorator(ak),
aaronc 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),
Expand Down
27 changes: 27 additions & 0 deletions x/auth/ante/fee_grant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// 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)
}
32 changes: 32 additions & 0 deletions x/auth/ante/fee_grant_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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)
}
5 changes: 5 additions & 0 deletions x/auth/legacy/legacytx/stdtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ func (tx StdTx) FeePayer() sdk.AccAddress {
return sdk.AccAddress{}
}

// FeeGranter always returns nil for StdTx
func (tx StdTx) FeeGranter() sdk.AccAddress {
return nil
}

func (tx StdTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
for _, m := range tx.Msgs {
err := codectypes.UnpackInterfaces(m, unpacker)
Expand Down
3 changes: 3 additions & 0 deletions x/auth/legacy/legacytx/stdtx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ func TestStdTx(t *testing.T) {

feePayer := tx.GetSigners()[0]
require.Equal(t, addr, feePayer)

feeGranter := tx.FeeGranter()
require.Empty(t, feeGranter)
Comment on lines +71 to +72
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
feeGranter := tx.FeeGranter()
require.Empty(t, feeGranter)
require.Empty(t, tx.FeeGranter())

}

func TestStdSignBytes(t *testing.T) {
Expand Down
23 changes: 23 additions & 0 deletions x/auth/tx/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ func (w *wrapper) FeePayer() sdk.AccAddress {
return w.GetSigners()[0]
}

func (w *wrapper) FeeGranter() sdk.AccAddress {
feePayer := w.tx.AuthInfo.Fee.Granter
if feePayer != "" {
granterAddr, err := sdk.AccAddressFromBech32(feePayer)
if err != nil {
panic(err)
}
return granterAddr
}
return nil
}

func (w *wrapper) GetMemo() string {
return w.tx.Body.Memo
}
Expand Down Expand Up @@ -255,6 +267,17 @@ func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) {
w.authInfoBz = nil
}

func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) {
if w.tx.AuthInfo.Fee == nil {
w.tx.AuthInfo.Fee = &tx.Fee{}
}

w.tx.AuthInfo.Fee.Granter = feeGranter.String()

// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
w.authInfoBz = nil
}

func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error {
n := len(signatures)
signerInfos := make([]*tx.SignerInfo, n)
Expand Down
22 changes: 22 additions & 0 deletions x/auth/tx/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,25 @@ func TestBuilderFeePayer(t *testing.T) {
})
}
}

func TestBuilderFeeGranter(t *testing.T) {
// keys and addresses
_, _, addr1 := testdata.KeyTestPubAddr()

// msg and signatures
msg1 := testdata.NewTestMsg(addr1, addr2)
feeAmount := testdata.NewTestFeeAmount()
msgs := []sdk.Msg{msg1}

txBuilder := newBuilder()
err := txBuilder.SetMsgs(msgs...)
require.NoError(t, err)
txBuilder.SetGasLimit(200000)
txBuilder.SetFeeAmount(feeAmount)

require.Empty(t, txBuilder.GetTx().FeeGranter())

// set fee granter
txBuilder.SetFeeGranter(addr1)
require.Equal(t, addr1, txBuilder.GetTx().FeeGranter())
}