Skip to content

Commit

Permalink
Add Fee granter field (#7418)
Browse files Browse the repository at this point in the history
* WIP on adding Fee granter field

* WIP on adding Fee granter field

* WIP on adding Fee granter field

* Update comments, add tests
  • Loading branch information
aaronc authored Oct 5, 2020
1 parent 435fc83 commit 4a1b2fb
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 53 deletions.
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
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),
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
// 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)
}

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())
}

0 comments on commit 4a1b2fb

Please sign in to comment.