diff --git a/PENDING.md b/PENDING.md index 545d74380d..9e3f1c1eb9 100644 --- a/PENDING.md +++ b/PENDING.md @@ -58,6 +58,8 @@ IMPROVEMENTS * [\#3418](https://github.com/cosmos/cosmos-sdk/issues/3418) Add vesting account genesis validation checks to `GaiaValidateGenesisState`. * [\#3420](https://github.com/cosmos/cosmos-sdk/issues/3420) Added maximum length to governance proposal descriptions and titles + * [\#3256](https://github.com/cosmos/cosmos-sdk/issues/3256) Add gas consumption + for tx size in the ante handler. * [\#3454](https://github.com/cosmos/cosmos-sdk/pull/3454) Add `--jail-whitelist` to `gaiad export` to enable testing of complex exports * [\#3424](https://github.com/cosmos/cosmos-sdk/issues/3424) Allow generation of gentxs with empty memo field. diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ef5c692b9b..6a6cc79602 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -390,7 +390,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc if err != nil { result = err.Result() } else { - result = app.Simulate(tx) + result = app.Simulate(txBytes, tx) } case "version": return abci.ResponseQuery{ @@ -718,7 +718,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk if r := recover(); r != nil { switch rType := r.(type) { case sdk.ErrorOutOfGas: - log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) + log := fmt.Sprintf( + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(), + ) result = sdk.ErrOutOfGas(log).Result() default: log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack())) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 82ee0bd9c3..3782491061 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -655,20 +655,20 @@ func TestSimulateTx(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{}) tx := newTxCounter(count, count) + txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + require.Nil(t, err) // simulate a message, check gas reported - result := app.Simulate(tx) + result := app.Simulate(txBytes, tx) require.True(t, result.IsOK(), result.Log) require.Equal(t, gasConsumed, result.GasUsed) // simulate again, same result - result = app.Simulate(tx) + result = app.Simulate(txBytes, tx) require.True(t, result.IsOK(), result.Log) require.Equal(t, gasConsumed, result.GasUsed) // simulate by calling Query with encoded tx - txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) - require.Nil(t, err) query := abci.RequestQuery{ Path: "/app/simulate", Data: txBytes, diff --git a/baseapp/helpers.go b/baseapp/helpers.go index 0ac99887a3..fbc3df99d0 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -14,8 +14,8 @@ func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) { } // nolint - full tx execution -func (app *BaseApp) Simulate(tx sdk.Tx) (result sdk.Result) { - return app.runTx(runTxModeSimulate, nil, tx) +func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx) (result sdk.Result) { + return app.runTx(runTxModeSimulate, txBytes, tx) } // nolint diff --git a/client/flags.go b/client/flags.go index 31feacf6cd..c87a8933c5 100644 --- a/client/flags.go +++ b/client/flags.go @@ -11,9 +11,9 @@ import ( // nolint const ( - // DefaultGasAdjustment is applied to gas estimates to avoid tx - // execution failures due to state changes that might - // occur between the tx simulation and the actual run. + // DefaultGasAdjustment is applied to gas estimates to avoid tx execution + // failures due to state changes that might occur between the tx simulation + // and the actual run. DefaultGasAdjustment = 1.0 DefaultGasLimit = 200000 GasFlagAuto = "auto" diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index c531a00404..c29eb64a7b 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -209,7 +209,9 @@ func TestCoinSend(t *testing.T) { require.Equal(t, http.StatusInternalServerError, res.StatusCode, body) // run simulation and test success with estimated gas - res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "10000", 1.0, true, false, fees) + res, body, _ = doTransferWithGas( + t, port, seed, name1, memo, pw, addr, "10000", 1.0, true, false, fees, + ) require.Equal(t, http.StatusOK, res.StatusCode, body) var gasEstResp rest.GasEstimateResponse @@ -285,7 +287,9 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { acc := getAccount(t, port, addr) // simulate tx - res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, true, false, fees) + res, body, _ := doTransferWithGas( + t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1.0, true, false, fees, + ) require.Equal(t, http.StatusOK, res.StatusCode, body) var gasEstResp rest.GasEstimateResponse diff --git a/client/utils/utils.go b/client/utils/utils.go index daad43156a..b5ae87eab6 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -19,6 +19,15 @@ import ( authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" ) +// GasEstimateResponse defines a response definition for tx gas estimation. +type GasEstimateResponse struct { + GasEstimate uint64 `json:"gas_estimate"` +} + +func (gr GasEstimateResponse) String() string { + return fmt.Sprintf("gas estimate: %d", gr.GasEstimate) +} + // CompleteAndBroadcastTxCLI implements a utility function that facilitates // sending a series of messages in a signed transaction given a TxBuilder and a // QueryContext. It ensures that the account exists, has a proper number and @@ -39,8 +48,11 @@ func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIConte if err != nil { return err } - fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas()) + + gasEst := GasEstimateResponse{GasEstimate: txBldr.GetGas()} + fmt.Fprintf(os.Stderr, gasEst.String()) } + if cliCtx.Simulate { return nil } diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index dae525342a..f7d645a61b 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -79,7 +79,7 @@ func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisT privKey := secp256k1.GenPrivKeySecp256k1(privkeySeed) newAccs = append(newAccs, simulation.Account{privKey, privKey.PubKey(), acc.Address}) } - return json.RawMessage(genesis.AppState), newAccs, genesis.ChainID + return genesis.AppState, newAccs, genesis.ChainID } func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) { @@ -138,11 +138,11 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest authGenesis := auth.GenesisState{ Params: auth.Params{ - MemoCostPerByte: uint64(r.Intn(10) + 1), - MaxMemoCharacters: uint64(r.Intn(200-100) + 100), + MaxMemoCharacters: uint64(randIntBetween(r, 100, 200)), TxSigLimit: uint64(r.Intn(7) + 1), - SigVerifyCostED25519: uint64(r.Intn(1000-500) + 500), - SigVerifyCostSecp256k1: uint64(r.Intn(1000-500) + 500), + TxSizeCostPerByte: uint64(randIntBetween(r, 5, 15)), + SigVerifyCostED25519: uint64(randIntBetween(r, 500, 1000)), + SigVerifyCostSecp256k1: uint64(randIntBetween(r, 500, 1000)), }, } fmt.Printf("Selected randomly generated auth parameters:\n\t%+v\n", authGenesis) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 6e2e60536c..0b6d5790df 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -279,7 +279,7 @@ func TestGaiaCLIGasAuto(t *testing.T) { }{} err := cdc.UnmarshalJSON([]byte(stdout), &sendResp) require.Nil(t, err) - require.Equal(t, sendResp.Response.GasWanted, sendResp.Response.GasUsed) + require.True(t, sendResp.Response.GasWanted >= sendResp.Response.GasUsed) tests.WaitForNextNBlocksTM(1, f.Port) // Check state has changed accordingly @@ -690,7 +690,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { // Unmarshal the response and ensure that gas was properly used require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result)) - require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasUsed)) + require.True(t, msg.Fee.Gas >= uint64(result.Response.GasUsed)) require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasWanted)) tests.WaitForNextNBlocksTM(1, f.Port) diff --git a/docs/spec/auth/gas_fees.md b/docs/spec/auth/gas_fees.md index fbe2103946..533ccb0025 100644 --- a/docs/spec/auth/gas_fees.md +++ b/docs/spec/auth/gas_fees.md @@ -7,9 +7,11 @@ general purpose censorship of transactions of little economic value. Fees are best suited as an anti-spam mechanism where validators are disinterested in the use of the network and identities of users. -Fees are determined by the gas limits and gas prices transactions provide. -Operators should set minimum gas prices when starting their nodes. They must set -the unit costs of gas in each token denomination they wish to support: +Fees are determined by the gas limits and gas prices transactions provide, where +`fees = ceil(gasLimit * gasPrices)`. Txs incur gas costs for all state reads/writes, +signature verification, as well as costs proportional to the tx size. Operators +should set minimum gas prices when starting their nodes. They must set the unit +costs of gas in each token denomination they wish to support: `gaiad start ... --minimum-gas-prices=0.00001steak,0.05photinos` diff --git a/x/auth/ante.go b/x/auth/ante.go index f82b7fc650..bc39f5323a 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -15,6 +15,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +var ( + // simulation signature values used to estimate gas consumption + simSecp256k1Pubkey secp256k1.PubKeySecp256k1 + simSecp256k1Sig [64]byte +) + +func init() { + bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") + copy(simSecp256k1Pubkey[:], bz) +} + // NewAnteHandler returns an AnteHandler that checks and increments sequence // numbers, checks signatures & account numbers, and deducts fees from the first // signer. @@ -54,8 +65,12 @@ func NewAnteHandler(ak AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler { if r := recover(); r != nil { switch rType := r.(type) { case sdk.ErrorOutOfGas: - log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) + log := fmt.Sprintf( + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, stdTx.Fee.Gas, newCtx.GasMeter().GasConsumed(), + ) res = sdk.ErrOutOfGas(log).Result() + res.GasWanted = stdTx.Fee.Gas res.GasUsed = newCtx.GasMeter().GasConsumed() abort = true @@ -69,7 +84,9 @@ func NewAnteHandler(ak AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler { return newCtx, err.Result(), true } - if res := ValidateMemo(newCtx.GasMeter(), stdTx, params); !res.IsOK() { + newCtx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*sdk.Gas(len(newCtx.TxBytes())), "txSize") + + if res := ValidateMemo(stdTx, params); !res.IsOK() { return newCtx, res, true } @@ -131,9 +148,8 @@ func GetSignerAcc(ctx sdk.Context, ak AccountKeeper, addr sdk.AccAddress) (Accou return nil, sdk.ErrUnknownAddress(addr.String()).Result() } -// ValidateMemo validates the memo and if successful consumes gas for -// verification. -func ValidateMemo(gasMeter sdk.GasMeter, stdTx StdTx, params Params) sdk.Result { +// ValidateMemo validates the memo size. +func ValidateMemo(stdTx StdTx, params Params) sdk.Result { memoLength := len(stdTx.GetMemo()) if uint64(memoLength) > params.MaxMemoCharacters { return sdk.ErrMemoTooLarge( @@ -144,7 +160,6 @@ func ValidateMemo(gasMeter sdk.GasMeter, stdTx StdTx, params Params) sdk.Result ).Result() } - gasMeter.ConsumeGas(params.MemoCostPerByte*sdk.Gas(memoLength), "memo") return sdk.Result{} } @@ -164,7 +179,15 @@ func processSig( return nil, sdk.ErrInternal("setting PubKey on signer's account").Result() } - consumeSignatureVerificationGas(ctx.GasMeter(), sig.Signature, pubKey, params) + if simulate { + // Simulated txs should not contain a signature and are not required to + // contain a pubkey, so we must account for tx size of including a + // StdSignature (Amino encoding) and simulate gas consumption + // (assuming a SECP256k1 simulation key). + consumeSimSigGas(ctx.GasMeter(), pubKey, sig, params) + } + + consumeSigVerificationGas(ctx.GasMeter(), sig.Signature, pubKey, params) if !simulate && !pubKey.VerifyBytes(signBytes, sig.Signature) { return nil, sdk.ErrUnauthorized("signature verification failed").Result() } @@ -178,11 +201,22 @@ func processSig( return acc, res } -var dummySecp256k1Pubkey secp256k1.PubKeySecp256k1 +func consumeSimSigGas(gasmeter sdk.GasMeter, pubkey crypto.PubKey, sig StdSignature, params Params) { + simSig := StdSignature{PubKey: pubkey} + if len(sig.Signature) == 0 { + simSig.Signature = simSecp256k1Sig[:] + } -func init() { - bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") - copy(dummySecp256k1Pubkey[:], bz) + sigBz := msgCdc.MustMarshalBinaryLengthPrefixed(simSig) + cost := sdk.Gas(len(sigBz) + 6) + + // If the pubkey is a multi-signature pubkey, then we estimate for the maximum + // number of signers. + if _, ok := pubkey.(multisig.PubKeyMultisigThreshold); ok { + cost *= params.TxSigLimit + } + + gasmeter.ConsumeGas(params.TxSizeCostPerByte*cost, "txSize") } // ProcessPubKey verifies that the given account address matches that of the @@ -197,7 +231,7 @@ func ProcessPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, // shall consume the largest amount, i.e. it takes more gas to verify // secp256k1 keys than ed25519 ones. if pubKey == nil { - return dummySecp256k1Pubkey, sdk.Result{} + return simSecp256k1Pubkey, sdk.Result{} } return pubKey, sdk.Result{} @@ -218,25 +252,27 @@ func ProcessPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, return pubKey, sdk.Result{} } -// consumeSignatureVerificationGas consumes gas for signature verification based -// upon the public key type. The cost is fetched from the given params and is -// matched by the concrete type. +// consumeSigVerificationGas consumes gas for signature verification based upon +// the public key type. The cost is fetched from the given params and is matched +// by the concrete type. // // TODO: Design a cleaner and flexible way to match concrete public key types. -func consumeSignatureVerificationGas(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params Params) { +func consumeSigVerificationGas(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params Params) { pubkeyType := strings.ToLower(fmt.Sprintf("%T", pubkey)) switch { case strings.Contains(pubkeyType, "ed25519"): meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") + case strings.Contains(pubkeyType, "secp256k1"): meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1") - case strings.Contains(pubkeyType, "multisigthreshold"): + case strings.Contains(pubkeyType, "multisigthreshold"): var multisignature multisig.Multisignature codec.Cdc.MustUnmarshalBinaryBare(sig, &multisignature) - multisigPubKey := pubkey.(multisig.PubKeyMultisigThreshold) + multisigPubKey := pubkey.(multisig.PubKeyMultisigThreshold) consumeMultisignatureVerificationGas(meter, multisignature, multisigPubKey, params) + default: panic(fmt.Sprintf("unrecognized signature type: %s", pubkeyType)) } @@ -250,7 +286,7 @@ func consumeMultisignatureVerificationGas(meter sdk.GasMeter, sigIndex := 0 for i := 0; i < size; i++ { if sig.BitArray.GetIndex(i) { - consumeSignatureVerificationGas(meter, sig.Sigs[sigIndex], pubkey.PubKeys[i], params) + consumeSigVerificationGas(meter, sig.Sigs[sigIndex], pubkey.PubKeys[i], params) sigIndex++ } } @@ -294,8 +330,6 @@ func DeductFees(blockTime time.Time, acc Account, fee StdFee) (Account, sdk.Resu // enough fees to cover a proposer's minimum fees. An result object is returned // indicating success or failure. // -// TODO: Account for transaction size. -// // Contract: This should only be called during CheckTx as it cannot be part of // consensus. func EnsureSufficientMempoolFees(ctx sdk.Context, stdFee StdFee) sdk.Result { diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index bbe4f62fd6..21e9f50cde 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -595,9 +595,9 @@ func TestConsumeSignatureVerificationGas(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.wantPanic { - require.Panics(t, func() { consumeSignatureVerificationGas(tt.args.meter, tt.args.sig, tt.args.pubkey, tt.args.params) }) + require.Panics(t, func() { consumeSigVerificationGas(tt.args.meter, tt.args.sig, tt.args.pubkey, tt.args.params) }) } else { - consumeSignatureVerificationGas(tt.args.meter, tt.args.sig, tt.args.pubkey, tt.args.params) + consumeSigVerificationGas(tt.args.meter, tt.args.sig, tt.args.pubkey, tt.args.params) require.Equal(t, tt.gasConsumed, tt.args.meter.GasConsumed(), fmt.Sprintf("%d != %d", tt.gasConsumed, tt.args.meter.GasConsumed())) } }) diff --git a/x/auth/genesis.go b/x/auth/genesis.go index fa9fa2d82a..2836fd899c 100644 --- a/x/auth/genesis.go +++ b/x/auth/genesis.go @@ -54,8 +54,8 @@ func ValidateGenesis(data GenesisState) error { if data.Params.MaxMemoCharacters == 0 { return fmt.Errorf("invalid max memo characters: %d", data.Params.MaxMemoCharacters) } - if data.Params.MemoCostPerByte == 0 { - return fmt.Errorf("invalid memo cost per byte: %d", data.Params.MemoCostPerByte) + if data.Params.TxSizeCostPerByte == 0 { + return fmt.Errorf("invalid tx size cost per byte: %d", data.Params.TxSizeCostPerByte) } return nil diff --git a/x/auth/params.go b/x/auth/params.go index 9fcde581cd..2831dbd32a 100644 --- a/x/auth/params.go +++ b/x/auth/params.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -15,18 +14,18 @@ const DefaultParamspace = "auth" // Default parameter values const ( - DefaultMemoCostPerByte sdk.Gas = 3 - DefaultMaxMemoCharacters uint64 = 256 - DefaultTxSigLimit uint64 = 7 - DefaultSigVerifyCostED25519 uint64 = 590 - DefaultSigVerifyCostSecp256k1 uint64 = 1000 + DefaultMaxMemoCharacters uint64 = 256 + DefaultTxSigLimit uint64 = 7 + DefaultTxSizeCostPerByte uint64 = 10 + DefaultSigVerifyCostED25519 uint64 = 590 + DefaultSigVerifyCostSecp256k1 uint64 = 1000 ) // Parameter keys var ( - KeyMemoCostPerByte = []byte("MemoCostPerByte") KeyMaxMemoCharacters = []byte("MaxMemoCharacters") KeyTxSigLimit = []byte("TxSigLimit") + KeyTxSizeCostPerByte = []byte("TxSizeCostPerByte") KeySigVerifyCostED25519 = []byte("SigVerifyCostED25519") KeySigVerifyCostSecp256k1 = []byte("SigVerifyCostSecp256k1") ) @@ -35,9 +34,9 @@ var _ params.ParamSet = &Params{} // Params defines the parameters for the auth module. type Params struct { - MemoCostPerByte sdk.Gas MaxMemoCharacters uint64 TxSigLimit uint64 // max total number of signatures per tx + TxSizeCostPerByte uint64 SigVerifyCostED25519 uint64 SigVerifyCostSecp256k1 uint64 } @@ -52,9 +51,9 @@ func ParamTypeTable() params.TypeTable { // nolint func (p *Params) KeyValuePairs() params.KeyValuePairs { return params.KeyValuePairs{ - {KeyMemoCostPerByte, &p.MemoCostPerByte}, {KeyMaxMemoCharacters, &p.MaxMemoCharacters}, {KeyTxSigLimit, &p.TxSigLimit}, + {KeyTxSizeCostPerByte, &p.TxSizeCostPerByte}, {KeySigVerifyCostED25519, &p.SigVerifyCostED25519}, {KeySigVerifyCostSecp256k1, &p.SigVerifyCostSecp256k1}, } @@ -70,9 +69,9 @@ func (p Params) Equal(p2 Params) bool { // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - MemoCostPerByte: DefaultMemoCostPerByte, MaxMemoCharacters: DefaultMaxMemoCharacters, TxSigLimit: DefaultTxSigLimit, + TxSizeCostPerByte: DefaultTxSizeCostPerByte, SigVerifyCostED25519: DefaultSigVerifyCostED25519, SigVerifyCostSecp256k1: DefaultSigVerifyCostSecp256k1, } @@ -83,9 +82,9 @@ func (p Params) String() string { var sb strings.Builder sb.WriteString("Params: \n") - sb.WriteString(fmt.Sprintf("MemoCostPerByte: %v\n", p.MemoCostPerByte)) sb.WriteString(fmt.Sprintf("MaxMemoCharacters: %d\n", p.MaxMemoCharacters)) sb.WriteString(fmt.Sprintf("TxSigLimit: %d\n", p.TxSigLimit)) + sb.WriteString(fmt.Sprintf("TxSizeCostPerByte: %d\n", p.TxSizeCostPerByte)) sb.WriteString(fmt.Sprintf("SigVerifyCostED25519: %d\n", p.SigVerifyCostED25519)) sb.WriteString(fmt.Sprintf("SigVerifyCostSecp256k1: %d\n", p.SigVerifyCostSecp256k1)) diff --git a/x/bank/app_test.go b/x/bank/app_test.go index a6e9d6dfef..f32d037810 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -141,7 +141,7 @@ func TestMsgSendWithAccounts(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -180,7 +180,7 @@ func TestMsgSendMultipleOut(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -224,7 +224,7 @@ func TestSengMsgMultipleInOut(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -269,7 +269,7 @@ func TestMsgSendDependent(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 8129783d44..6527c79ebd 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -72,10 +72,10 @@ func TestIBCMsgs(t *testing.T) { Sequence: 0, } - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{0}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, emptyCoins) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{1}, false, false, priv1) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, true, true, priv1) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{1}, false, false, priv1) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, coins) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, false, false, priv1) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, false, false, priv1) } diff --git a/x/mock/app.go b/x/mock/app.go index 541d923dcd..902873ba1f 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -51,10 +51,7 @@ func NewApp() *App { db := dbm.NewMemDB() // Create the cdc with some standard codecs - cdc := codec.New() - sdk.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - auth.RegisterCodec(cdc) + cdc := createCodec() // Create your application object app := &App{ @@ -337,3 +334,11 @@ func incrementAllSequenceNumbers(initSeqNums []uint64) { initSeqNums[i]++ } } + +func createCodec() *codec.Codec { + cdc := codec.New() + sdk.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + auth.RegisterCodec(cdc) + return cdc +} diff --git a/x/mock/app_test.go b/x/mock/app_test.go index 098126d896..a101168381 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -61,14 +61,14 @@ func TestCheckAndDeliverGenTx(t *testing.T) { require.Equal(t, accs[0], acct.(*auth.BaseAccount)) SignCheckDeliver( - t, mApp.BaseApp, []sdk.Msg{msg}, + t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{msg}, []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence()}, true, true, privKeys[0], ) // Signing a tx with the wrong privKey should result in an auth error res := SignCheckDeliver( - t, mApp.BaseApp, []sdk.Msg{msg}, + t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{msg}, []uint64{accs[1].GetAccountNumber()}, []uint64{accs[1].GetSequence() + 1}, true, false, privKeys[1], ) @@ -78,7 +78,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) { // Resigning the tx with the correct privKey should result in an OK result SignCheckDeliver( - t, mApp.BaseApp, []sdk.Msg{msg}, + t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{msg}, []uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence() + 1}, true, true, privKeys[0], ) diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index 9c24967aba..f2af216e13 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -5,6 +5,8 @@ import ( "math/rand" "testing" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" @@ -71,12 +73,16 @@ func CheckGenTx( // the parameter 'expPass' against the result. A corresponding result is // returned. func SignCheckDeliver( - t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []uint64, - seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, + t *testing.T, cdc *codec.Codec, app *baseapp.BaseApp, msgs []sdk.Msg, + accNums []uint64, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, ) sdk.Result { tx := GenTx(msgs, accNums, seq, priv...) + + txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + require.Nil(t, err) + // Must simulate now as CheckTx doesn't run Msgs anymore - res := app.Simulate(tx) + res := app.Simulate(txBytes, tx) if expSimPass { require.Equal(t, sdk.CodeOK, res.Code, res.Log) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index e9c17b89a5..20e5380809 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -26,6 +26,8 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { mapp := mock.NewApp() RegisterCodec(mapp.Cdc) + stakingTypes.RegisterCodec(mapp.Cdc) + keyStaking := sdk.NewKVStoreKey(staking.StoreKey) tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keySlashing := sdk.NewKVStoreKey(StoreKey) @@ -107,7 +109,7 @@ func TestSlashingMsgs(t *testing.T) { createValidatorMsg := staking.NewMsgCreateValidator( sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commission, ) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mapp.BeginBlock(abci.RequestBeginBlock{}) @@ -121,7 +123,7 @@ func TestSlashingMsgs(t *testing.T) { checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false) // unjail should fail with unknown validator - res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) + res := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) require.EqualValues(t, CodeValidatorNotJailed, res.Code) require.EqualValues(t, DefaultCodespace, res.Codespace) } diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 852a9593ab..c7203c6e7f 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -120,7 +120,7 @@ func TestStakingMsgs(t *testing.T) { sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commissionMsg, ) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) + mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) @@ -134,7 +134,7 @@ func TestStakingMsgs(t *testing.T) { addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, commissionMsg, ) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []uint64{0, 0}, []uint64{1, 0}, true, true, priv1, priv2) + mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []uint64{0, 0}, []uint64{1, 0}, true, true, priv1, priv2) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) @@ -150,7 +150,7 @@ func TestStakingMsgs(t *testing.T) { description = NewDescription("bar_moniker", "", "", "") editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description, nil) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{2}, true, true, priv1) + mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{2}, true, true, priv1) validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) require.Equal(t, description, validator.Description) @@ -158,13 +158,13 @@ func TestStakingMsgs(t *testing.T) { mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []uint64{0}, []uint64{1}, true, true, priv2) + mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{delegateMsg}, []uint64{0}, []uint64{1}, true, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10)) // begin unbonding beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), sdk.NewDec(10)) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []uint64{0}, []uint64{2}, true, true, priv2) + mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []uint64{0}, []uint64{2}, true, true, priv2) // delegation should exist anymore checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})