github.com/Finschia/finschia-sdk@v0.49.1/x/auth/ante/feegrant_test.go (about)

     1  package ante_test
     2  
     3  import (
     4  	"math/rand"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/Finschia/ostracon/crypto"
     9  
    10  	"github.com/Finschia/finschia-sdk/client"
    11  	"github.com/Finschia/finschia-sdk/codec"
    12  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    13  	"github.com/Finschia/finschia-sdk/simapp"
    14  	"github.com/Finschia/finschia-sdk/simapp/helpers"
    15  	"github.com/Finschia/finschia-sdk/testutil/testdata"
    16  	sdk "github.com/Finschia/finschia-sdk/types"
    17  	"github.com/Finschia/finschia-sdk/types/simulation"
    18  	"github.com/Finschia/finschia-sdk/types/tx/signing"
    19  	"github.com/Finschia/finschia-sdk/x/auth/ante"
    20  	authsign "github.com/Finschia/finschia-sdk/x/auth/signing"
    21  	"github.com/Finschia/finschia-sdk/x/auth/tx"
    22  	authtypes "github.com/Finschia/finschia-sdk/x/auth/types"
    23  	"github.com/Finschia/finschia-sdk/x/feegrant"
    24  )
    25  
    26  func (suite *AnteTestSuite) TestDeductFeesNoDelegation() {
    27  	suite.SetupTest(false)
    28  	// setup
    29  	app, ctx := suite.app, suite.ctx
    30  
    31  	protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes)
    32  
    33  	// this just tests our handler
    34  	dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper)
    35  	feeAnteHandler := sdk.ChainAnteDecorators(dfd)
    36  
    37  	// this tests the whole stack
    38  	anteHandlerStack := suite.anteHandler
    39  
    40  	// keys and addresses
    41  	priv1, _, addr1 := testdata.KeyTestPubAddr()
    42  	priv2, _, addr2 := testdata.KeyTestPubAddr()
    43  	priv3, _, addr3 := testdata.KeyTestPubAddr()
    44  	priv4, _, addr4 := testdata.KeyTestPubAddr()
    45  	priv5, _, addr5 := testdata.KeyTestPubAddr()
    46  
    47  	// Set addr1 with insufficient funds
    48  	err := simapp.FundAccount(suite.app, suite.ctx, addr1, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))})
    49  	suite.Require().NoError(err)
    50  
    51  	// Set addr2 with more funds
    52  	err = simapp.FundAccount(suite.app, suite.ctx, addr2, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(99999))})
    53  	suite.Require().NoError(err)
    54  
    55  	// grant fee allowance from `addr2` to `addr3` (plenty to pay)
    56  	err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr3, &feegrant.BasicAllowance{
    57  		SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 500)),
    58  	})
    59  	suite.Require().NoError(err)
    60  
    61  	// grant low fee allowance (20atom), to check the tx requesting more than allowed.
    62  	err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr4, &feegrant.BasicAllowance{
    63  		SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 20)),
    64  	})
    65  	suite.Require().NoError(err)
    66  
    67  	cases := map[string]struct {
    68  		signerKey  cryptotypes.PrivKey
    69  		signer     sdk.AccAddress
    70  		feeAccount sdk.AccAddress
    71  		fee        int64
    72  		valid      bool
    73  	}{
    74  		"paying with low funds": {
    75  			signerKey: priv1,
    76  			signer:    addr1,
    77  			fee:       50,
    78  			valid:     false,
    79  		},
    80  		"paying with good funds": {
    81  			signerKey: priv2,
    82  			signer:    addr2,
    83  			fee:       50,
    84  			valid:     true,
    85  		},
    86  		"paying with no account": {
    87  			signerKey: priv3,
    88  			signer:    addr3,
    89  			fee:       1,
    90  			valid:     false,
    91  		},
    92  		"no fee with real account": {
    93  			signerKey: priv1,
    94  			signer:    addr1,
    95  			fee:       0,
    96  			valid:     true,
    97  		},
    98  		"no fee with no account": {
    99  			signerKey: priv5,
   100  			signer:    addr5,
   101  			fee:       0,
   102  			valid:     false,
   103  		},
   104  		"valid fee grant without account": {
   105  			signerKey:  priv3,
   106  			signer:     addr3,
   107  			feeAccount: addr2,
   108  			fee:        50,
   109  			valid:      true,
   110  		},
   111  		"no fee grant": {
   112  			signerKey:  priv3,
   113  			signer:     addr3,
   114  			feeAccount: addr1,
   115  			fee:        2,
   116  			valid:      false,
   117  		},
   118  		"allowance smaller than requested fee": {
   119  			signerKey:  priv4,
   120  			signer:     addr4,
   121  			feeAccount: addr2,
   122  			fee:        50,
   123  			valid:      false,
   124  		},
   125  		"granter cannot cover allowed fee grant": {
   126  			signerKey:  priv4,
   127  			signer:     addr4,
   128  			feeAccount: addr1,
   129  			fee:        50,
   130  			valid:      false,
   131  		},
   132  	}
   133  
   134  	for name, stc := range cases {
   135  		tc := stc // to make scopelint happy
   136  		suite.T().Run(name, func(t *testing.T) {
   137  			fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee))
   138  			msgs := []sdk.Msg{testdata.NewTestMsg(tc.signer)}
   139  
   140  			acc := app.AccountKeeper.GetAccount(ctx, tc.signer)
   141  			privs, accNums, seqs := []cryptotypes.PrivKey{tc.signerKey}, []uint64{0}, []uint64{0}
   142  			if acc != nil {
   143  				accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()}
   144  			}
   145  
   146  			tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...)
   147  			suite.Require().NoError(err)
   148  			_, err = feeAnteHandler(ctx, tx, false) // tests only feegrant ante
   149  			if tc.valid {
   150  				suite.Require().NoError(err)
   151  			} else {
   152  				suite.Require().Error(err)
   153  			}
   154  
   155  			_, err = anteHandlerStack(ctx, tx, false) // tests while stack
   156  			if tc.valid {
   157  				suite.Require().NoError(err)
   158  			} else {
   159  				suite.Require().Error(err)
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  // don't consume any gas
   166  func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error {
   167  	return nil
   168  }
   169  
   170  func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums,
   171  	accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey,
   172  ) (sdk.Tx, error) {
   173  	sigs := make([]signing.SignatureV2, len(priv))
   174  
   175  	// create a random length memo
   176  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
   177  
   178  	memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))
   179  
   180  	signMode := gen.SignModeHandler().DefaultMode()
   181  
   182  	// 1st round: set SignatureV2 with empty signatures, to set correct
   183  	// signer infos.
   184  	for i, p := range priv {
   185  		sigs[i] = signing.SignatureV2{
   186  			PubKey: p.PubKey(),
   187  			Data: &signing.SingleSignatureData{
   188  				SignMode: signMode,
   189  			},
   190  			Sequence: accSeqs[i],
   191  		}
   192  	}
   193  
   194  	tx := gen.NewTxBuilder()
   195  	err := tx.SetMsgs(msgs...)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	err = tx.SetSignatures(sigs...)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	tx.SetMemo(memo)
   204  	tx.SetFeeAmount(feeAmt)
   205  	tx.SetGasLimit(gas)
   206  	tx.SetFeeGranter(feeGranter)
   207  
   208  	// 2nd round: once all signer infos are set, every signer can sign.
   209  	for i, p := range priv {
   210  		signerData := authsign.SignerData{
   211  			ChainID:       chainID,
   212  			AccountNumber: accNums[i],
   213  			Sequence:      accSeqs[i],
   214  		}
   215  		signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx())
   216  		if err != nil {
   217  			panic(err)
   218  		}
   219  		sig, err := p.Sign(signBytes)
   220  		if err != nil {
   221  			panic(err)
   222  		}
   223  		sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
   224  		err = tx.SetSignatures(sigs...)
   225  		if err != nil {
   226  			panic(err)
   227  		}
   228  	}
   229  
   230  	return tx.GetTx(), nil
   231  }