github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/ante/testutil_test.go (about) 1 package ante_test 2 3 import ( 4 "testing" 5 6 abci "github.com/cometbft/cometbft/abci/types" 7 "github.com/golang/mock/gomock" 8 "github.com/stretchr/testify/require" 9 10 // TODO We don't need to import these API types if we use gogo's registry 11 // ref: https://github.com/cosmos/cosmos-sdk/issues/14647 12 _ "cosmossdk.io/api/cosmos/bank/v1beta1" 13 _ "cosmossdk.io/api/cosmos/crypto/secp256k1" 14 storetypes "cosmossdk.io/store/types" 15 16 "github.com/cosmos/cosmos-sdk/client" 17 "github.com/cosmos/cosmos-sdk/client/tx" 18 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 19 "github.com/cosmos/cosmos-sdk/runtime" 20 "github.com/cosmos/cosmos-sdk/testutil" 21 clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" 22 "github.com/cosmos/cosmos-sdk/testutil/testdata" 23 _ "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" 24 sdk "github.com/cosmos/cosmos-sdk/types" 25 moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" 26 "github.com/cosmos/cosmos-sdk/types/tx/signing" 27 "github.com/cosmos/cosmos-sdk/x/auth" 28 "github.com/cosmos/cosmos-sdk/x/auth/ante" 29 antetestutil "github.com/cosmos/cosmos-sdk/x/auth/ante/testutil" 30 authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" 31 "github.com/cosmos/cosmos-sdk/x/auth/keeper" 32 xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 33 authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil" 34 txtestutil "github.com/cosmos/cosmos-sdk/x/auth/tx/testutil" 35 "github.com/cosmos/cosmos-sdk/x/auth/types" 36 "github.com/cosmos/cosmos-sdk/x/bank" 37 ) 38 39 // TestAccount represents an account used in the tests in x/auth/ante. 40 type TestAccount struct { 41 acc sdk.AccountI 42 priv cryptotypes.PrivKey 43 } 44 45 // AnteTestSuite is a test suite to be used with ante handler tests. 46 type AnteTestSuite struct { 47 anteHandler sdk.AnteHandler 48 ctx sdk.Context 49 clientCtx client.Context 50 txBuilder client.TxBuilder 51 accountKeeper keeper.AccountKeeper 52 bankKeeper *authtestutil.MockBankKeeper 53 txBankKeeper *txtestutil.MockBankKeeper 54 feeGrantKeeper *antetestutil.MockFeegrantKeeper 55 encCfg moduletestutil.TestEncodingConfig 56 } 57 58 // SetupTest setups a new test, with new app, context, and anteHandler. 59 func SetupTestSuite(t *testing.T, isCheckTx bool) *AnteTestSuite { 60 suite := &AnteTestSuite{} 61 ctrl := gomock.NewController(t) 62 suite.bankKeeper = authtestutil.NewMockBankKeeper(ctrl) 63 suite.txBankKeeper = txtestutil.NewMockBankKeeper(ctrl) 64 suite.feeGrantKeeper = antetestutil.NewMockFeegrantKeeper(ctrl) 65 66 key := storetypes.NewKVStoreKey(types.StoreKey) 67 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 68 suite.ctx = testCtx.Ctx.WithIsCheckTx(isCheckTx).WithBlockHeight(1) // app.BaseApp.NewContext(isCheckTx, cmtproto.Header{}).WithBlockHeight(1) 69 suite.encCfg = moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, bank.AppModuleBasic{}) 70 71 maccPerms := map[string][]string{ 72 "fee_collector": nil, 73 "mint": {"minter"}, 74 "bonded_tokens_pool": {"burner", "staking"}, 75 "not_bonded_tokens_pool": {"burner", "staking"}, 76 "multiPerm": {"burner", "minter", "staking"}, 77 "random": {"random"}, 78 } 79 80 suite.accountKeeper = keeper.NewAccountKeeper( 81 suite.encCfg.Codec, runtime.NewKVStoreService(key), types.ProtoBaseAccount, maccPerms, authcodec.NewBech32Codec("cosmos"), 82 sdk.Bech32MainPrefix, types.NewModuleAddress("gov").String(), 83 ) 84 suite.accountKeeper.GetModuleAccount(suite.ctx, types.FeeCollectorName) 85 err := suite.accountKeeper.Params.Set(suite.ctx, types.DefaultParams()) 86 require.NoError(t, err) 87 88 // We're using TestMsg encoding in some tests, so register it here. 89 suite.encCfg.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) 90 testdata.RegisterInterfaces(suite.encCfg.InterfaceRegistry) 91 92 suite.clientCtx = client.Context{}. 93 WithTxConfig(suite.encCfg.TxConfig). 94 WithClient(clitestutil.NewMockCometRPC(abci.ResponseQuery{})) 95 96 anteHandler, err := ante.NewAnteHandler( 97 ante.HandlerOptions{ 98 AccountKeeper: suite.accountKeeper, 99 BankKeeper: suite.bankKeeper, 100 FeegrantKeeper: suite.feeGrantKeeper, 101 SignModeHandler: suite.encCfg.TxConfig.SignModeHandler(), 102 SigGasConsumer: ante.DefaultSigVerificationGasConsumer, 103 }, 104 ) 105 106 require.NoError(t, err) 107 suite.anteHandler = anteHandler 108 109 suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() 110 111 return suite 112 } 113 114 func (suite *AnteTestSuite) CreateTestAccounts(numAccs int) []TestAccount { 115 var accounts []TestAccount 116 117 for i := 0; i < numAccs; i++ { 118 priv, _, addr := testdata.KeyTestPubAddr() 119 acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr) 120 acc.SetAccountNumber(uint64(i + 1000)) 121 suite.accountKeeper.SetAccount(suite.ctx, acc) 122 accounts = append(accounts, TestAccount{acc, priv}) 123 } 124 125 return accounts 126 } 127 128 // TestCase represents a test case used in test tables. 129 type TestCase struct { 130 desc string 131 malleate func(*AnteTestSuite) TestCaseArgs 132 simulate bool 133 expPass bool 134 expErr error 135 } 136 137 type TestCaseArgs struct { 138 chainID string 139 accNums []uint64 140 accSeqs []uint64 141 feeAmount sdk.Coins 142 gasLimit uint64 143 msgs []sdk.Msg 144 privs []cryptotypes.PrivKey 145 } 146 147 func (t TestCaseArgs) WithAccountsInfo(accs []TestAccount) TestCaseArgs { 148 newT := t 149 for _, acc := range accs { 150 newT.accNums = append(newT.accNums, acc.acc.GetAccountNumber()) 151 newT.accSeqs = append(newT.accSeqs, acc.acc.GetSequence()) 152 newT.privs = append(newT.privs, acc.priv) 153 } 154 return newT 155 } 156 157 // DeliverMsgs constructs a tx and runs it through the ante handler. This is used to set the context for a test case, for 158 // example to test for replay protection. 159 func (suite *AnteTestSuite) DeliverMsgs(t *testing.T, privs []cryptotypes.PrivKey, msgs []sdk.Msg, feeAmount sdk.Coins, gasLimit uint64, accNums, accSeqs []uint64, chainID string, simulate bool) (sdk.Context, error) { 160 require.NoError(t, suite.txBuilder.SetMsgs(msgs...)) 161 suite.txBuilder.SetFeeAmount(feeAmount) 162 suite.txBuilder.SetGasLimit(gasLimit) 163 164 tx, txErr := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, chainID, signing.SignMode_SIGN_MODE_DIRECT) 165 require.NoError(t, txErr) 166 txBytes, err := suite.clientCtx.TxConfig.TxEncoder()(tx) 167 bytesCtx := suite.ctx.WithTxBytes(txBytes) 168 require.NoError(t, err) 169 return suite.anteHandler(bytesCtx, tx, simulate) 170 } 171 172 func (suite *AnteTestSuite) RunTestCase(t *testing.T, tc TestCase, args TestCaseArgs) { 173 require.NoError(t, suite.txBuilder.SetMsgs(args.msgs...)) 174 suite.txBuilder.SetFeeAmount(args.feeAmount) 175 suite.txBuilder.SetGasLimit(args.gasLimit) 176 177 // Theoretically speaking, ante handler unit tests should only test 178 // ante handlers, but here we sometimes also test the tx creation 179 // process. 180 tx, txErr := suite.CreateTestTx(suite.ctx, args.privs, args.accNums, args.accSeqs, args.chainID, signing.SignMode_SIGN_MODE_DIRECT) 181 txBytes, err := suite.clientCtx.TxConfig.TxEncoder()(tx) 182 require.NoError(t, err) 183 bytesCtx := suite.ctx.WithTxBytes(txBytes) 184 newCtx, anteErr := suite.anteHandler(bytesCtx, tx, tc.simulate) 185 186 if tc.expPass { 187 require.NoError(t, txErr) 188 require.NoError(t, anteErr) 189 require.NotNil(t, newCtx) 190 191 suite.ctx = newCtx 192 } else { 193 switch { 194 case txErr != nil: 195 require.Error(t, txErr) 196 require.ErrorIs(t, txErr, tc.expErr) 197 198 case anteErr != nil: 199 require.Error(t, anteErr) 200 require.ErrorIs(t, anteErr, tc.expErr) 201 202 default: 203 t.Fatal("expected one of txErr, anteErr to be an error") 204 } 205 } 206 } 207 208 // CreateTestTx is a helper function to create a tx given multiple inputs. 209 func (suite *AnteTestSuite) CreateTestTx( 210 ctx sdk.Context, privs []cryptotypes.PrivKey, 211 accNums, accSeqs []uint64, 212 chainID string, signMode signing.SignMode, 213 ) (xauthsigning.Tx, error) { 214 // First round: we gather all the signer infos. We use the "set empty 215 // signature" hack to do that. 216 var sigsV2 []signing.SignatureV2 217 for i, priv := range privs { 218 sigV2 := signing.SignatureV2{ 219 PubKey: priv.PubKey(), 220 Data: &signing.SingleSignatureData{ 221 SignMode: signMode, 222 Signature: nil, 223 }, 224 Sequence: accSeqs[i], 225 } 226 227 sigsV2 = append(sigsV2, sigV2) 228 } 229 err := suite.txBuilder.SetSignatures(sigsV2...) 230 if err != nil { 231 return nil, err 232 } 233 234 // Second round: all signer infos are set, so each signer can sign. 235 sigsV2 = []signing.SignatureV2{} 236 for i, priv := range privs { 237 signerData := xauthsigning.SignerData{ 238 Address: sdk.AccAddress(priv.PubKey().Address()).String(), 239 ChainID: chainID, 240 AccountNumber: accNums[i], 241 Sequence: accSeqs[i], 242 PubKey: priv.PubKey(), 243 } 244 sigV2, err := tx.SignWithPrivKey( 245 ctx, signMode, signerData, 246 suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i]) 247 if err != nil { 248 return nil, err 249 } 250 251 sigsV2 = append(sigsV2, sigV2) 252 } 253 err = suite.txBuilder.SetSignatures(sigsV2...) 254 if err != nil { 255 return nil, err 256 } 257 258 return suite.txBuilder.GetTx(), nil 259 }