github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/ante/feegrant_test.go (about)

     1  package ante_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"math/rand"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/cometbft/cometbft/crypto"
    11  	"github.com/golang/mock/gomock"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	storetypes "cosmossdk.io/store/types"
    15  
    16  	"github.com/cosmos/cosmos-sdk/client"
    17  	"github.com/cosmos/cosmos-sdk/codec"
    18  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    19  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    20  	sdk "github.com/cosmos/cosmos-sdk/types"
    21  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    22  	"github.com/cosmos/cosmos-sdk/types/simulation"
    23  	"github.com/cosmos/cosmos-sdk/types/tx/signing"
    24  	"github.com/cosmos/cosmos-sdk/x/auth/ante"
    25  	authsign "github.com/cosmos/cosmos-sdk/x/auth/signing"
    26  	"github.com/cosmos/cosmos-sdk/x/auth/testutil"
    27  	"github.com/cosmos/cosmos-sdk/x/auth/tx"
    28  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    29  )
    30  
    31  func TestDeductFeesNoDelegation(t *testing.T) {
    32  	cases := map[string]struct {
    33  		fee      int64
    34  		valid    bool
    35  		err      error
    36  		errMsg   string
    37  		malleate func(*AnteTestSuite) (signer TestAccount, feeAcc sdk.AccAddress)
    38  	}{
    39  		"paying with low funds": {
    40  			fee:   50,
    41  			valid: false,
    42  			err:   sdkerrors.ErrInsufficientFunds,
    43  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
    44  				accs := suite.CreateTestAccounts(1)
    45  				// 2 calls are needed because we run the ante twice
    46  				suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[0].acc.GetAddress(), authtypes.FeeCollectorName, gomock.Any()).Return(sdkerrors.ErrInsufficientFunds).Times(2)
    47  				return accs[0], nil
    48  			},
    49  		},
    50  		"paying with good funds": {
    51  			fee:   50,
    52  			valid: true,
    53  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
    54  				accs := suite.CreateTestAccounts(1)
    55  				suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[0].acc.GetAddress(), authtypes.FeeCollectorName, gomock.Any()).Return(nil).Times(2)
    56  				return accs[0], nil
    57  			},
    58  		},
    59  		"paying with no account": {
    60  			fee:   1,
    61  			valid: false,
    62  			err:   sdkerrors.ErrUnknownAddress,
    63  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
    64  				// Do not register the account
    65  				priv, _, addr := testdata.KeyTestPubAddr()
    66  				return TestAccount{
    67  					acc:  authtypes.NewBaseAccountWithAddress(addr),
    68  					priv: priv,
    69  				}, nil
    70  			},
    71  		},
    72  		"no fee with real account": {
    73  			fee:   0,
    74  			valid: true,
    75  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
    76  				accs := suite.CreateTestAccounts(1)
    77  				return accs[0], nil
    78  			},
    79  		},
    80  		"no fee with no account": {
    81  			fee:   0,
    82  			valid: false,
    83  			err:   sdkerrors.ErrUnknownAddress,
    84  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
    85  				// Do not register the account
    86  				priv, _, addr := testdata.KeyTestPubAddr()
    87  				return TestAccount{
    88  					acc:  authtypes.NewBaseAccountWithAddress(addr),
    89  					priv: priv,
    90  				}, nil
    91  			},
    92  		},
    93  		"valid fee grant": {
    94  			// note: the original test said "valid fee grant with no account".
    95  			// this is impossible given that feegrant.GrantAllowance calls
    96  			// SetAccount for the grantee.
    97  			fee:   50,
    98  			valid: true,
    99  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
   100  				accs := suite.CreateTestAccounts(2)
   101  
   102  				suite.feeGrantKeeper.EXPECT().UseGrantedFees(gomock.Any(), accs[1].acc.GetAddress(), accs[0].acc.GetAddress(), gomock.Any(), gomock.Any()).Return(nil).Times(2)
   103  				suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[1].acc.GetAddress(), authtypes.FeeCollectorName, gomock.Any()).Return(nil).Times(2)
   104  				return accs[0], accs[1].acc.GetAddress()
   105  			},
   106  		},
   107  		"no fee grant": {
   108  			fee:   2,
   109  			valid: false,
   110  			err:   sdkerrors.ErrNotFound,
   111  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
   112  				accs := suite.CreateTestAccounts(2)
   113  				suite.feeGrantKeeper.EXPECT().
   114  					UseGrantedFees(gomock.Any(), accs[1].acc.GetAddress(), accs[0].acc.GetAddress(), gomock.Any(), gomock.Any()).
   115  					Return(sdkerrors.ErrNotFound.Wrap("fee-grant not found")).
   116  					Times(2)
   117  				return accs[0], accs[1].acc.GetAddress()
   118  			},
   119  		},
   120  		"allowance smaller than requested fee": {
   121  			fee:    50,
   122  			valid:  false,
   123  			errMsg: "fee limit exceeded",
   124  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
   125  				accs := suite.CreateTestAccounts(2)
   126  				suite.feeGrantKeeper.EXPECT().
   127  					UseGrantedFees(gomock.Any(), accs[1].acc.GetAddress(), accs[0].acc.GetAddress(), gomock.Any(), gomock.Any()).
   128  					Return(errors.New("fee limit exceeded")).
   129  					Times(2)
   130  				return accs[0], accs[1].acc.GetAddress()
   131  			},
   132  		},
   133  		"granter cannot cover allowed fee grant": {
   134  			fee:   50,
   135  			valid: false,
   136  			err:   sdkerrors.ErrInsufficientFunds,
   137  			malleate: func(suite *AnteTestSuite) (TestAccount, sdk.AccAddress) {
   138  				accs := suite.CreateTestAccounts(2)
   139  				suite.feeGrantKeeper.EXPECT().UseGrantedFees(gomock.Any(), accs[1].acc.GetAddress(), accs[0].acc.GetAddress(), gomock.Any(), gomock.Any()).Return(nil).Times(2)
   140  				suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[1].acc.GetAddress(), authtypes.FeeCollectorName, gomock.Any()).Return(sdkerrors.ErrInsufficientFunds).Times(2)
   141  				return accs[0], accs[1].acc.GetAddress()
   142  			},
   143  		},
   144  	}
   145  
   146  	for name, stc := range cases {
   147  		tc := stc // to make scopelint happy
   148  		t.Run(name, func(t *testing.T) {
   149  			suite := SetupTestSuite(t, false)
   150  			protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(suite.encCfg.InterfaceRegistry), tx.DefaultSignModes)
   151  			// this just tests our handler
   152  			dfd := ante.NewDeductFeeDecorator(suite.accountKeeper, suite.bankKeeper, suite.feeGrantKeeper, nil)
   153  			feeAnteHandler := sdk.ChainAnteDecorators(dfd)
   154  
   155  			// this tests the whole stack
   156  			anteHandlerStack := suite.anteHandler
   157  
   158  			signer, feeAcc := stc.malleate(suite)
   159  
   160  			fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee))
   161  			msgs := []sdk.Msg{testdata.NewTestMsg(signer.acc.GetAddress())}
   162  
   163  			acc := suite.accountKeeper.GetAccount(suite.ctx, signer.acc.GetAddress())
   164  			privs, accNums, seqs := []cryptotypes.PrivKey{signer.priv}, []uint64{0}, []uint64{0}
   165  			if acc != nil {
   166  				accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()}
   167  			}
   168  
   169  			var defaultGenTxGas uint64 = 10000000
   170  			tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, defaultGenTxGas, suite.ctx.ChainID(), accNums, seqs, feeAcc, privs...)
   171  			require.NoError(t, err)
   172  			txBytes, err := protoTxCfg.TxEncoder()(tx)
   173  			require.NoError(t, err)
   174  			bytesCtx := suite.ctx.WithTxBytes(txBytes)
   175  			require.NoError(t, err)
   176  			_, err = feeAnteHandler(bytesCtx, tx, false) // tests only feegrant ante
   177  			if tc.valid {
   178  				require.NoError(t, err)
   179  			} else {
   180  				testutil.AssertError(t, err, tc.err, tc.errMsg)
   181  			}
   182  
   183  			_, err = anteHandlerStack(bytesCtx, tx, false) // tests whole stack
   184  			if tc.valid {
   185  				require.NoError(t, err)
   186  			} else {
   187  				testutil.AssertError(t, err, tc.err, tc.errMsg)
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  // don't consume any gas
   194  func SigGasNoConsumer(meter storetypes.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error {
   195  	return nil
   196  }
   197  
   198  func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums,
   199  	accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey,
   200  ) (sdk.Tx, error) {
   201  	sigs := make([]signing.SignatureV2, len(priv))
   202  
   203  	// create a random length memo
   204  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
   205  
   206  	memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))
   207  
   208  	signMode := signing.SignMode_SIGN_MODE_DIRECT
   209  
   210  	// 1st round: set SignatureV2 with empty signatures, to set correct
   211  	// signer infos.
   212  	for i, p := range priv {
   213  		sigs[i] = signing.SignatureV2{
   214  			PubKey: p.PubKey(),
   215  			Data: &signing.SingleSignatureData{
   216  				SignMode: signMode,
   217  			},
   218  			Sequence: accSeqs[i],
   219  		}
   220  	}
   221  
   222  	tx := gen.NewTxBuilder()
   223  	err := tx.SetMsgs(msgs...)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	err = tx.SetSignatures(sigs...)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	tx.SetMemo(memo)
   232  	tx.SetFeeAmount(feeAmt)
   233  	tx.SetGasLimit(gas)
   234  	tx.SetFeeGranter(feeGranter)
   235  
   236  	// 2nd round: once all signer infos are set, every signer can sign.
   237  	for i, p := range priv {
   238  		signerData := authsign.SignerData{
   239  			ChainID:       chainID,
   240  			AccountNumber: accNums[i],
   241  			Sequence:      accSeqs[i],
   242  			PubKey:        p.PubKey(),
   243  		}
   244  		signBytes, err := authsign.GetSignBytesAdapter(
   245  			context.Background(), gen.SignModeHandler(), signMode, signerData, tx.GetTx())
   246  		if err != nil {
   247  			panic(err)
   248  		}
   249  		sig, err := p.Sign(signBytes)
   250  		if err != nil {
   251  			panic(err)
   252  		}
   253  		sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
   254  		err = tx.SetSignatures(sigs...)
   255  		if err != nil {
   256  			panic(err)
   257  		}
   258  	}
   259  
   260  	return tx.GetTx(), nil
   261  }