From c588d13552e0500614930aecc5f6aaa5547510e7 Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 5 Jul 2022 21:17:51 +0700 Subject: [PATCH] chore: fumpt sdk v45 series #12442 --- baseapp/baseapp.go | 11 +- client/config/toml.go | 2 +- client/debug/main.go | 57 +- client/grpc/cmtservice/service.go | 11 +- client/grpc_query_test.go | 3 + client/input/input_test.go | 1 - client/keys/import_test.go | 2 +- client/keys/list_test.go | 2 +- client/keys/migrate_test.go | 65 +- client/query_test.go | 2 +- codec/amino_codec_test.go | 2 +- codec/codec_common_test.go | 8 +- codec/proto_codec.go | 5 +- crypto/armor.go | 6 +- crypto/hd/algo.go | 2 +- crypto/keyring/keyring.go | 2 +- crypto/keyring/keyring_ledger_test.go | 5 +- crypto/keys/internal/ecdsa/privkey.go | 4 - .../internal/ecdsa/privkey_internal_test.go | 10 +- crypto/keys/internal/ecdsa/pubkey.go | 1 - crypto/keys/multisig/multisig.go | 4 +- .../secp256k1/internal/secp256k1/curve.go | 12 +- .../secp256k1/libsecp256k1/contrib/dummy.go | 1 + .../internal/secp256k1/libsecp256k1/dummy.go | 1 + .../secp256k1/libsecp256k1/include/dummy.go | 1 + .../secp256k1/libsecp256k1/src/dummy.go | 1 + .../libsecp256k1/src/modules/dummy.go | 1 + .../libsecp256k1/src/modules/ecdh/dummy.go | 1 + .../src/modules/recovery/dummy.go | 1 + .../internal/secp256k1/secp256_test.go | 2 +- crypto/ledger/ledger_mock.go | 3 +- crypto/ledger/ledger_secp256k1.go | 9 +- math/int.go | 3 - server/config/toml.go | 2 +- server/mock/app.go | 8 +- server/mock/app_test.go | 3 +- server/mock/store.go | 1 + server/mock/tx.go | 27 +- simapp/app.go | 27 +- simapp/sim_test.go | 61 +- simapp/simd/cmd/root.go | 23 +- simapp/simd/cmd/testnet.go | 87 +-- simapp/test_helpers.go | 1 - simapp/testutil_network_test.go | 5 +- store/cachemulti/store.go | 2 +- store/iavl/store_test.go | 3 +- store/listenkv/store_test.go | 6 +- store/rootmulti/store.go | 15 - store/snapshots/store.go | 20 +- store/types/errors.go | 21 +- tests/integration/server/grpc/server_test.go | 3 + testutil/network/network.go | 6 +- testutil/network/util.go | 8 +- testutil/testdata/tx.go | 8 + types/address.go | 51 +- types/address/hash_test.go | 5 - types/address_test.go | 60 ++ types/coin_test.go | 12 +- types/context.go | 45 +- types/module/module.go | 21 +- types/module/module_test.go | 47 +- types/query/filtered_pagination.go | 7 +- types/query/pagination.go | 7 +- types/simulation/rand_util.go | 4 +- types/simulation/types.go | 5 +- types/tx/types.go | 2 +- types/utils_test.go | 47 ++ x/auth/ante/ante.go | 7 +- x/auth/ante/ante_test.go | 3 +- x/auth/ante/basic_test.go | 4 +- x/auth/ante/fee.go | 6 +- x/auth/ante/setup.go | 3 + x/auth/ante/sigverify.go | 5 - x/auth/client/cli/tx_multisign.go | 19 +- x/auth/client/cli/tx_sign.go | 9 +- x/auth/client/tx_test.go | 20 + x/auth/keeper/grpc_query.go | 12 +- x/auth/keeper/keeper.go | 5 + x/auth/tx/encoder.go | 10 +- x/auth/tx/query.go | 2 + x/auth/tx/service.go | 4 +- x/auth/tx/testutil/suite.go | 4 +- x/authz/authorization_grant.go | 2 +- x/authz/authorization_grant_test.go | 3 +- x/authz/client/cli/tx.go | 37 +- x/authz/generic_authorization.go | 4 +- x/authz/keeper/grpc_query.go | 2 - x/authz/keeper/keeper_test.go | 38 +- x/authz/keeper/keys.go | 7 + x/authz/msgs_test.go | 1 + x/bank/keeper/grpc_query.go | 27 +- x/bank/keeper/invariants.go | 2 +- x/bank/keeper/keeper.go | 5 +- x/bank/keeper/keeper_test.go | 12 +- x/bank/keeper/send.go | 4 - x/bank/types/genesis_test.go | 3 +- x/bank/types/msgs_test.go | 163 ++++- x/bank/types/send_authorization.go | 5 +- x/distribution/client/cli/tx.go | 34 +- x/distribution/keeper/allocation.go | 12 +- x/distribution/keeper/delegation.go | 6 +- x/distribution/keeper/grpc_query.go | 16 +- x/distribution/keeper/store.go | 24 +- x/distribution/types/query.go | 11 +- x/evidence/keeper/grpc_query.go | 28 +- x/evidence/keeper/keeper.go | 15 +- x/feegrant/client/cli/tx.go | 2 +- x/feegrant/filtered_fee.go | 4 +- x/feegrant/grant.go | 2 +- x/feegrant/keeper/grpc_query.go | 23 +- x/feegrant/keeper/grpc_query_test.go | 5 - x/feegrant/keeper/keeper.go | 22 +- x/feegrant/keeper/keeper_test.go | 108 +-- x/feegrant/keeper/msg_server_test.go | 64 -- x/feegrant/key.go | 6 +- x/genutil/client/cli/gentx.go | 4 +- x/genutil/gentx.go | 2 +- x/genutil/module.go | 21 +- x/genutil/types/genesis_state.go | 4 +- x/genutil/utils.go | 19 +- x/gov/client/utils/query.go | 73 +- x/gov/client/utils/query_test.go | 9 +- x/gov/keeper/common_test.go | 16 +- x/gov/keeper/grpc_query.go | 41 +- x/gov/keeper/hooks_test.go | 4 +- x/gov/keeper/keeper.go | 7 +- x/gov/types/hooks.go | 6 +- x/gov/types/v1beta1/tally.go | 4 +- x/mint/module.go | 6 +- x/mint/types/codec.go | 4 +- x/mint/types/minter_test.go | 8 +- x/mint/types/params.go | 38 +- x/simulation/event_stats.go | 2 +- x/simulation/mock_cometbft.go | 8 +- x/simulation/simulate.go | 20 +- x/simulation/util.go | 2 +- x/slashing/keeper/grpc_query_test.go | 6 +- x/slashing/keeper/keeper_test.go | 102 ++- x/slashing/keeper/signing_info.go | 45 +- x/staking/client/cli/tx_test.go | 12 +- x/staking/keeper/alias_functions.go | 22 +- x/staking/keeper/delegation_test.go | 54 +- x/staking/keeper/grpc_query.go | 52 +- x/staking/keeper/grpc_query_test.go | 687 +++++++++++++++++- x/staking/keeper/keeper_test.go | 58 +- x/staking/keeper/slash.go | 34 +- x/staking/keeper/validator.go | 44 +- x/staking/keeper/validator_test.go | 158 +++- x/staking/types/authz.go | 23 +- x/staking/types/delegation.go | 3 +- x/staking/types/hooks.go | 36 +- x/staking/types/keys_test.go | 82 ++- x/staking/types/validator.go | 15 + x/upgrade/keeper/keeper_test.go | 27 - x/upgrade/types/storeloader_test.go | 2 +- 155 files changed, 2165 insertions(+), 1296 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 06543047e209..578115bc5423 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -47,16 +47,7 @@ type ( StoreLoader func(ms storetypes.CommitMultiStore) error ) -const ( - execModeCheck execMode = iota // Check a transaction - execModeReCheck // Recheck a (pending) transaction after a commit - execModeSimulate // Simulate a transaction - execModePrepareProposal // Prepare a block proposal - execModeProcessProposal // Process a block proposal - execModeVoteExtension // Extend or verify a pre-commit vote - execModeVerifyVoteExtension // Verify a vote extension - execModeFinalize // Finalize a block proposal -) +var _ abci.Application = (*BaseApp)(nil) var _ servertypes.ABCI = (*BaseApp)(nil) diff --git a/client/config/toml.go b/client/config/toml.go index 35787219a236..28edd28ecec0 100644 --- a/client/config/toml.go +++ b/client/config/toml.go @@ -59,7 +59,7 @@ func setConfigTemplate(customTemplate string) error { return err } - return nil + return ioutil.WriteFile(configFilePath, buffer.Bytes(), 0o600) } // writeConfigFile renders config using the template and writes it to diff --git a/client/debug/main.go b/client/debug/main.go index fdfb32cbdd23..9cdcfd3a3a0c 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -191,16 +191,8 @@ func PubkeyRawCmd() *cobra.Command { `, version.AppName, version.AppName, version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - pubkeyType, err := cmd.Flags().GetString(flagPubkeyType) - if err != nil { - return err - } - pubkeyType = strings.ToLower(pubkeyType) - if pubkeyType != "secp256k1" && pubkeyType != ed { - return errorsmod.Wrapf(errors.ErrInvalidType, "invalid pubkey type, expected oneof ed25519 or secp256k1") - } + addrString := args[0] + var addr []byte pk, err := getPubKeyFromRawString(args[0], pubkeyType) if err != nil { @@ -239,49 +231,8 @@ func PubkeyRawCmd() *cobra.Command { cmd.Println("Bech32 Validator Consensus:", consensusPub) } - return nil - }, - } - cmd.Flags().StringP(flagPubkeyType, "t", ed, "Pubkey type to decode (oneof secp256k1, ed25519)") - return cmd -} - -func AddrCmd() *cobra.Command { - return &cobra.Command{ - Use: "addr
", - Short: "Convert an address between hex and bech32", - Example: fmt.Sprintf("%s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg", version.AppName), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - addrString := args[0] - // try hex, then bech32 - var ( - addr []byte - err error - ) - decodeFns := []func(text string) ([]byte, error){ - hex.DecodeString, - clientCtx.AddressCodec.StringToBytes, - clientCtx.ValidatorAddressCodec.StringToBytes, - clientCtx.ConsensusAddressCodec.StringToBytes, - } - errs := make([]any, 0, len(decodeFns)) - for _, fn := range decodeFns { - if addr, err = fn(addrString); err == nil { - break - } - errs = append(errs, err) - } - if len(errs) == len(decodeFns) { - errTags := []string{ - "hex", "bech32 acc", "bech32 val", "bech32 con", - } - format := "" - for i := range errs { - if format != "" { - format += ", " + if err3 != nil { + return fmt.Errorf("expected hex or bech32. Got errors: hex: %v, bech32 acc: %v, bech32 val: %v", err, err2, err3) } format += errTags[i] + ": %w" } diff --git a/client/grpc/cmtservice/service.go b/client/grpc/cmtservice/service.go index ab2cbaf8598d..422ac469da1d 100644 --- a/client/grpc/cmtservice/service.go +++ b/client/grpc/cmtservice/service.go @@ -26,14 +26,9 @@ var ( _ gogoprotoany.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{} ) -type ( - abciQueryFn = func(context.Context, *abci.QueryRequest) (*abci.QueryResponse, error) - - queryServer struct { - rpc CometRPC - queryFn abciQueryFn - consensusCodec address.Codec - } +var ( + _ ServiceServer = queryServer{} + _ codectypes.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{} ) // NewQueryServer creates a new CometBFT query server. diff --git a/client/grpc_query_test.go b/client/grpc_query_test.go index d0d43a6d3023..d0406a50ef9e 100644 --- a/client/grpc_query_test.go +++ b/client/grpc_query_test.go @@ -1,3 +1,6 @@ +//go:build norace +// +build norace + package client_test import ( diff --git a/client/input/input_test.go b/client/input/input_test.go index 9e85eb256a20..3132afcdfaa4 100644 --- a/client/input/input_test.go +++ b/client/input/input_test.go @@ -53,5 +53,4 @@ func TestReadLineFromBuf(t *testing.T) { _, err := readLineFromBuf(buf) require.ErrorIs(t, err, expectedErr) }) - } diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 1d01f3312090..08a4a12e2e2f 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -97,7 +97,7 @@ HbP+c6JmeJy9JXe2rbbF1QtCX1gLqGcDQPBXiCtFvP7/8wTZtVOPj8vREzhZ9ElO keyfile := filepath.Join(kbHome, "key.asc") - require.NoError(t, ioutil.WriteFile(keyfile, []byte(armoredKey), 0644)) + require.NoError(t, ioutil.WriteFile(keyfile, []byte(armoredKey), 0o644)) defer func() { _ = os.RemoveAll(kbHome) diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 8360dcaa614e..662c60f819bc 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -49,7 +49,7 @@ func Test_runListCmd(t *testing.T) { WithValidatorAddressCodec(addresscodec.NewBech32Codec("cosmosvaloper")). WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons")) - path := "" //sdk.GetConfig().GetFullBIP44Path() + path := "" // sdk.GetConfig().GetFullBIP44Path() _, err = kb.NewAccount("something", testdata.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index 0e7adb4e6ca1..01b27ad69299 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -29,65 +29,16 @@ type setter interface { type MigrateTestSuite struct { suite.Suite - dir string - appName string - cdc codec.Codec - priv cryptotypes.PrivKey - pub cryptotypes.PubKey -} - -func TestMigrateTestSuite(t *testing.T) { - suite.Run(t, new(MigrateTestSuite)) -} - -func (s *MigrateTestSuite) SetupSuite() { - s.dir = s.T().TempDir() - s.cdc = moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}).Codec - s.appName = "cosmos" - s.priv = cryptotypes.PrivKey(secp256k1.GenPrivKey()) - s.pub = s.priv.PubKey() -} - -func (s *MigrateTestSuite) Test_runListAndShowCmd() { - // adding LegacyInfo item into keyring - multi := multisig.NewLegacyAminoPubKey( - 1, []cryptotypes.PubKey{ - s.pub, - }, - ) - legacyMultiInfo, err := keyring.NewLegacyMultiInfo(s.appName, multi) - s.Require().NoError(err) - serializedLegacyMultiInfo := keyring.MarshalInfo(legacyMultiInfo) - - item := design99keyring.Item{ - Key: s.appName + ".info", - Data: serializedLegacyMultiInfo, - Description: "SDK keyring version", - } - - // run test simd keys list - to see that the migrated key is there - cmd := ListKeysCmd() - cmd.Flags().AddFlagSet(Commands().PersistentFlags()) - - mockIn := testutil.ApplyMockIODiscardOutErr(cmd) - kb, err := keyring.New(s.appName, keyring.BackendTest, s.dir, mockIn, s.cdc) - s.Require().NoError(err) - - setter, ok := kb.(setter) - s.Require().True(ok) - s.Require().NoError(setter.SetItem(item)) - - clientCtx := client.Context{}. - WithKeyring(kb). - WithAddressCodec(addresscodec.NewBech32Codec("cosmos")). - WithValidatorAddressCodec(addresscodec.NewBech32Codec("cosmosvaloper")). - WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons")) - - ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) + cmd := MigrateCommand() + cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) + // mockIn := testutil.ApplyMockIODiscardOutErr(cmd) + mockIn, mockOut := testutil.ApplyMockIO(cmd) cmd.SetArgs([]string{ - fmt.Sprintf("--%s=%s", flags.FlagKeyringDir, s.dir), - fmt.Sprintf("--%s=false", flagListNames), + kbHome, + // fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flags.FlagDryRun), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), }) s.Require().NoError(cmd.ExecuteContext(ctx)) diff --git a/client/query_test.go b/client/query_test.go index 14cc25ba9d97..04532f566ba3 100644 --- a/client/query_test.go +++ b/client/query_test.go @@ -1,3 +1,4 @@ +//go:build norace // +build norace package client_test @@ -11,7 +12,6 @@ import ( ) func (s *IntegrationTestSuite) TestQueryABCIHeight() { - testCases := []struct { name string reqHeight int64 diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go index 97673b1d9a44..829be41fd96d 100644 --- a/codec/amino_codec_test.go +++ b/codec/amino_codec_test.go @@ -118,7 +118,7 @@ func TestAminoCodecUnpackAnyFails(t *testing.T) { func TestAminoCodecFullDecodeAndEncode(t *testing.T) { // This tx comes from https://github.com/cosmos/cosmos-sdk/issues/8117. txSigned := `{"type":"cosmos-sdk/StdTx","value":{"msg":[{"type":"cosmos-sdk/MsgCreateValidator","value":{"description":{"moniker":"fulltest","identity":"satoshi","website":"example.com","details":"example inc"},"commission":{"rate":"0.500000000000000000","max_rate":"1.000000000000000000","max_change_rate":"0.200000000000000000"},"min_self_delegation":"1000000","delegator_address":"cosmos14pt0q5cwf38zt08uu0n6yrstf3rndzr5057jys","validator_address":"cosmosvaloper14pt0q5cwf38zt08uu0n6yrstf3rndzr52q28gr","pubkey":{"type":"tendermint/PubKeyEd25519","value":"CYrOiM3HtS7uv1B1OAkknZnFYSRpQYSYII8AtMMtev0="},"value":{"denom":"umuon","amount":"700000000"}}}],"fee":{"amount":[{"denom":"umuon","amount":"6000"}],"gas":"160000"},"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AwAOXeWgNf1FjMaayrSnrOOKz+Fivr6DiI/i0x0sZCHw"},"signature":"RcnfS/u2yl7uIShTrSUlDWvsXo2p2dYu6WJC8VDVHMBLEQZWc8bsINSCjOnlsIVkUNNe1q/WCA9n3Gy1+0zhYA=="}],"memo":"","timeout_height":"0"}}` - var legacyCdc = simapp.MakeTestEncodingConfig().Amino + legacyCdc := simapp.MakeTestEncodingConfig().Amino var tx legacytx.StdTx err := legacyCdc.UnmarshalJSON([]byte(txSigned), &tx) require.NoError(t, err) diff --git a/codec/codec_common_test.go b/codec/codec_common_test.go index 4c0118f41994..904742f8a3e1 100644 --- a/codec/codec_common_test.go +++ b/codec/codec_common_test.go @@ -126,10 +126,10 @@ func testMarshaling(t *testing.T, cdc interface { m1 := mustMarshaler{cdc.Marshal, cdc.MustMarshal, cdc.Unmarshal, cdc.MustUnmarshal} m2 := mustMarshaler{cdc.MarshalLengthPrefixed, cdc.MustMarshalLengthPrefixed, cdc.UnmarshalLengthPrefixed, cdc.MustUnmarshalLengthPrefixed} m3 := mustMarshaler{ - func(i proto.Message) ([]byte, error) { return cdc.MarshalJSON(i) }, - func(i proto.Message) []byte { return cdc.MustMarshalJSON(i) }, - func(bz []byte, ptr proto.Message) error { return cdc.UnmarshalJSON(bz, ptr) }, - func(bz []byte, ptr proto.Message) { cdc.MustUnmarshalJSON(bz, ptr) }, + func(i codec.ProtoMarshaler) ([]byte, error) { return cdc.MarshalJSON(i) }, + func(i codec.ProtoMarshaler) []byte { return cdc.MustMarshalJSON(i) }, + func(bz []byte, ptr codec.ProtoMarshaler) error { return cdc.UnmarshalJSON(bz, ptr) }, + func(bz []byte, ptr codec.ProtoMarshaler) { cdc.MustUnmarshalJSON(bz, ptr) }, } t.Run(tc.name+"_BinaryBare", diff --git a/codec/proto_codec.go b/codec/proto_codec.go index 2c0c081896b1..c7f54a9c754c 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -34,7 +34,10 @@ type ProtoCodec struct { interfaceRegistry types.InterfaceRegistry } -var _ Codec = (*ProtoCodec)(nil) +var ( + _ Codec = &ProtoCodec{} + _ ProtoCodecMarshaler = &ProtoCodec{} +) // NewProtoCodec returns a reference to a new ProtoCodec func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec { diff --git a/crypto/armor.go b/crypto/armor.go index ac84ca6b5b07..fcff904d602c 100644 --- a/crypto/armor.go +++ b/crypto/armor.go @@ -161,11 +161,7 @@ func EncryptArmorPrivKey(privKey cryptotypes.PrivKey, passphrase, algo string) s func encryptPrivKey(privKey cryptotypes.PrivKey, passphrase string) (saltBytes, encBytes []byte) { saltBytes = crypto.CRandBytes(16) - - key := argon2.IDKey([]byte(passphrase), saltBytes, argon2Time, argon2Memory, argon2Threads, chacha20poly1305.KeySize) - privKeyBytes := legacy.Cdc.MustMarshal(privKey) - - aead, err := chacha20poly1305.New(key) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { panic(errorsmod.Wrap(err, "error generating cypher from key")) } diff --git a/crypto/hd/algo.go b/crypto/hd/algo.go index 885490c811fd..e1f06fae772a 100644 --- a/crypto/hd/algo.go +++ b/crypto/hd/algo.go @@ -30,7 +30,7 @@ const ( var Secp256k1 = secp256k1Algo{} type ( - DeriveFn func(mnemonic, bip39Passphrase, hdPath string) ([]byte, error) + DeriveFn func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) GenerateFn func(bz []byte) types.PrivKey ) diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index cb56990564da..f6b3dedeeb66 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -784,7 +784,7 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { continue } - if err := os.WriteFile(keyhashFilePath, passwordHash, 0o600); err != nil { + if err := ioutil.WriteFile(dir+"/keyhash", passwordHash, 0o555); err != nil { return "", err } diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go index 614017c65101..8099cc5b3e6d 100644 --- a/crypto/keyring/keyring_ledger_test.go +++ b/crypto/keyring/keyring_ledger_test.go @@ -20,10 +20,9 @@ import ( ) func TestInMemoryCreateLedger(t *testing.T) { - cdc := getCodec() - kb := NewInMemory(cdc) + kb := NewInMemory() - k, err := kb.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1) + ledger, err := kb.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1) if err != nil { require.Error(t, err) require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index 690c07670d64..2aeedb1c4ddc 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -29,7 +29,6 @@ func IsSNormalized(sigS *big.Int) bool { // NormalizeS will invert the s value if not already in the lower half // of curve order value func NormalizeS(sigS *big.Int) *big.Int { - if IsSNormalized(sigS) { return sigS } @@ -41,7 +40,6 @@ func NormalizeS(sigS *big.Int) *big.Int { // R, S are padded to 32 bytes respectively. // code roughly copied from secp256k1_nocgo.go func signatureRaw(r *big.Int, s *big.Int) []byte { - rBytes := r.Bytes() sBytes := s.Bytes() sigBytes := make([]byte, 64) @@ -90,10 +88,8 @@ func (sk *PrivKey) Bytes() []byte { // It then raw encodes the signature as two fixed width 32-byte values // concatenated, reusing the code copied from secp256k1_nocgo.go func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { - digest := sha256.Sum256(msg) r, s, err := ecdsa.Sign(rand.Reader, &sk.PrivateKey, digest[:]) - if err != nil { return nil, err } diff --git a/crypto/keys/internal/ecdsa/privkey_internal_test.go b/crypto/keys/internal/ecdsa/privkey_internal_test.go index 12bdaa45d726..ce8c60590be6 100644 --- a/crypto/keys/internal/ecdsa/privkey_internal_test.go +++ b/crypto/keys/internal/ecdsa/privkey_internal_test.go @@ -4,10 +4,11 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/sha256" - "github.com/tendermint/tendermint/crypto" "math/big" "testing" + "github.com/tendermint/tendermint/crypto" + "github.com/stretchr/testify/suite" ) @@ -39,11 +40,10 @@ func (suite *SKSuite) TestMarshal() { const size = 32 buffer := make([]byte, size) - _, err := suite.sk.MarshalTo(buffer) - require.NoError(err) + suite.sk.MarshalTo(buffer) sk := new(PrivKey) - err = sk.Unmarshal(buffer, secp256r1, size) + err := sk.Unmarshal(buffer, secp256r1, size) require.NoError(err) require.True(sk.Equal(&suite.sk.PrivateKey)) } @@ -81,7 +81,7 @@ func (suite *SKSuite) TestSign() { // leave r untouched! high_s := new(big.Int).Mod(new(big.Int).Neg(low_s), elliptic.P256().Params().N) - require.False(suite.pk.VerifySignature(msg, signatureRaw(r,high_s))) + require.False(suite.pk.VerifySignature(msg, signatureRaw(r, high_s))) // Valid signature using low_s, but too long sigCpy = make([]byte, len(sig)+2) diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go index 2743b4554c16..a0b5df4401c7 100644 --- a/crypto/keys/internal/ecdsa/pubkey.go +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -62,7 +62,6 @@ func (pk *PubKey) Bytes() []byte { // lower half of the curve order // 7/21/21 - expects raw encoded signature (fixed-width 64-bytes, R || S) func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { - // check length for raw signature // which is two 32-byte padded big.Ints // concatenated diff --git a/crypto/keys/multisig/multisig.go b/crypto/keys/multisig/multisig.go index 1fc3f8e28098..392738ad87df 100644 --- a/crypto/keys/multisig/multisig.go +++ b/crypto/keys/multisig/multisig.go @@ -13,8 +13,8 @@ import ( ) var ( - _ multisigtypes.PubKey = &LegacyAminoPubKey{} - _ gogoprotoany.UnpackInterfacesMessage = &LegacyAminoPubKey{} + _ multisigtypes.PubKey = &LegacyAminoPubKey{} + _ types.UnpackInterfacesMessage = &LegacyAminoPubKey{} ) // NewLegacyAminoPubKey returns a new LegacyAminoPubKey. diff --git a/crypto/keys/secp256k1/internal/secp256k1/curve.go b/crypto/keys/secp256k1/internal/secp256k1/curve.go index 790d6f7f47ce..efa503c2acf7 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/curve.go +++ b/crypto/keys/secp256k1/internal/secp256k1/curve.go @@ -94,13 +94,13 @@ func (bitCurve *BitCurve) Params() *elliptic.CurveParams { func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) // y² - y2.Mod(y2, bitCurve.P) // y²%P + y2.Mod(y2, BitCurve.P) // y²%P x3 := new(big.Int).Mul(x, x) // x² x3.Mul(x3, x) // x³ - x3.Add(x3, bitCurve.B) // x³+B - x3.Mod(x3, bitCurve.P) // (x³+B)%P + x3.Add(x3, BitCurve.B) // x³+B + x3.Mod(x3, BitCurve.P) //(x³+B)%P return x3.Cmp(y2) == 0 } @@ -222,9 +222,9 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, c := new(big.Int).Mul(b, b) // B² d := new(big.Int).Add(x, b) // X1+B - d.Mul(d, d) // (X1+B)² - d.Sub(d, a) // (X1+B)²-A - d.Sub(d, c) // (X1+B)²-A-C + d.Mul(d, d) //(X1+B)² + d.Sub(d, a) //(X1+B)²-A + d.Sub(d, c) //(X1+B)²-A-C d.Mul(d, big.NewInt(2)) // 2*((X1+B)²-A-C) e := new(big.Int).Mul(big.NewInt(3), a) // 3*A diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/contrib/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/contrib/dummy.go index fda594be9914..2c946210c54d 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/contrib/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/contrib/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/dummy.go index 379b16992f47..04bbe3d76ecc 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/include/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/include/dummy.go index 5af540c73c4a..64c71b8451d8 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/include/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/include/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/dummy.go index 65868f38a8ea..2df270adc35e 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/dummy.go index 3c7a696439f0..99c538db51b0 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go index b6fc38327ec8..48c2e0aa5453 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/recovery/dummy.go b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/recovery/dummy.go index b9491f0cb9f4..8efbd7abe71b 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/recovery/dummy.go +++ b/crypto/keys/secp256k1/internal/secp256k1/libsecp256k1/src/modules/recovery/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/keys/secp256k1/internal/secp256k1/secp256_test.go b/crypto/keys/secp256k1/internal/secp256k1/secp256_test.go index ef2a3a3790b4..dbf61b37879f 100644 --- a/crypto/keys/secp256k1/internal/secp256k1/secp256_test.go +++ b/crypto/keys/secp256k1/internal/secp256k1/secp256_test.go @@ -48,7 +48,7 @@ func randSig() []byte { // tests for malleability // highest bit of signature ECDSA s value must be 0, in the 33th byte func compactSigCheck(t *testing.T, sig []byte) { - var b = int(sig[32]) + b := int(sig[32]) if b < 0 { t.Errorf("highest bit is negative: %d", b) } diff --git a/crypto/ledger/ledger_mock.go b/crypto/ledger/ledger_mock.go index cf1f3d348b58..a763bcf9cdf5 100644 --- a/crypto/ledger/ledger_mock.go +++ b/crypto/ledger/ledger_mock.go @@ -27,8 +27,7 @@ func init() { return LedgerSECP256K1Mock{}, nil } - initOptionsDefault() -} +type LedgerSECP256K1Mock struct{} type LedgerSECP256K1Mock struct{} diff --git a/crypto/ledger/ledger_secp256k1.go b/crypto/ledger/ledger_secp256k1.go index b5efe2bf9b5b..ed1dbfec0d78 100644 --- a/crypto/ledger/ledger_secp256k1.go +++ b/crypto/ledger/ledger_secp256k1.go @@ -15,8 +15,9 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/types" ) -// options stores the Ledger Options that can be used to customize Ledger usage -var options Options +// discoverLedger defines a function to be invoked at runtime for discovering +// a connected Ledger device. +var discoverLedger discoverLedgerFn type ( // discoverLedgerFn defines a Ledger discovery function that returns a @@ -158,7 +159,9 @@ func (pkl PrivKeyLedgerSecp256k1) SignLedgerAminoJSON(message []byte) ([]byte, e } // ShowAddress triggers a ledger device to show the corresponding address. -func ShowAddress(path hd.BIP44Params, expectedPubKey types.PubKey, accountAddressPrefix string) error { +func ShowAddress(path hd.BIP44Params, expectedPubKey types.PubKey, + accountAddressPrefix string, +) error { device, err := getDevice() if err != nil { return err diff --git a/math/int.go b/math/int.go index 893f77692960..3b188593337d 100644 --- a/math/int.go +++ b/math/int.go @@ -6,9 +6,6 @@ import ( "errors" "fmt" "math/big" - "math/bits" - "strings" - "sync" "testing" ) diff --git a/server/config/toml.go b/server/config/toml.go index 750d09e05541..ec215d8379e7 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -253,5 +253,5 @@ func WriteConfigFile(configFilePath string, config interface{}) error { return fmt.Errorf("failed to write file: %w", err) } - return nil + tmos.MustWriteFile(configFilePath, buffer.Bytes(), 0o644) } diff --git a/server/mock/app.go b/server/mock/app.go index b7357d801638..df24e97cc853 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -122,7 +122,9 @@ func InitChainer(key storetypes.StoreKey) func(sdk.Context, *abci.InitChainReque // AppGenState can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func AppGenState(_ *codec.LegacyAmino, _ genutiltypes.AppGenesis, _ []json.RawMessage) (appState json.RawMessage, err error) { +func AppGenState(_ *codec.LegacyAmino, _ types.GenesisDoc, _ []json.RawMessage) (appState json. + RawMessage, err error, +) { appState = json.RawMessage(`{ "values": [ { @@ -139,7 +141,9 @@ func AppGenState(_ *codec.LegacyAmino, _ genutiltypes.AppGenesis, _ []json.RawMe } // AppGenStateEmpty returns an empty transaction state for mocking. -func AppGenStateEmpty(_ *codec.LegacyAmino, _ genutiltypes.AppGenesis, _ []json.RawMessage) (appState json.RawMessage, err error) { +func AppGenStateEmpty(_ *codec.LegacyAmino, _ types.GenesisDoc, _ []json.RawMessage) ( + appState json.RawMessage, err error, +) { appState = json.RawMessage(``) return } diff --git a/server/mock/app_test.go b/server/mock/app_test.go index c749927c0a8d..ca084a9eacd0 100644 --- a/server/mock/app_test.go +++ b/server/mock/app_test.go @@ -37,7 +37,8 @@ func TestInitApp(t *testing.T) { appState, err := AppGenState(nil, genutiltypes.AppGenesis{}, nil) require.NoError(t, err) - req := abci.InitChainRequest{ + // TODO test validators in the init chain? + req := abci.RequestInitChain{ AppStateBytes: appState, } res, err := app.InitChain(&req) diff --git a/server/mock/store.go b/server/mock/store.go index 4dbb418b623c..6f56da0ba882 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -140,6 +140,7 @@ func (ms multiStore) SetIAVLCacheSize(size int) { func (ms multiStore) SetIAVLDisableFastNode(disable bool) { panic("not implemented") } + func (ms multiStore) SetIAVLCacheSize(size int) { panic("not implemented") } diff --git a/server/mock/tx.go b/server/mock/tx.go index 22a709452b0a..0b5753019ef5 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -73,26 +73,21 @@ func (msg *KVStoreTx) Equals(key cryptotypes.PubKey) bool { } // dummy implementation of proto.Message - -func (msg *KVStoreTx) Reset() {} -func (msg *KVStoreTx) String() string { return "TODO" } -func (msg *KVStoreTx) ProtoMessage() {} +func (msg kvstoreTx) Reset() {} +func (msg kvstoreTx) String() string { return "TODO" } +func (msg kvstoreTx) ProtoMessage() {} var ( - _ sdk.Tx = &KVStoreTx{} - _ sdk.Msg = &KVStoreTx{} - _ signing.SigVerifiableTx = &KVStoreTx{} - _ cryptotypes.PubKey = &KVStoreTx{} - _ cryptotypes.PubKey = &testPubKey{} + _ sdk.Tx = kvstoreTx{} + _ sdk.Msg = kvstoreTx{} ) -func NewTx(key, value string, accAddress sdk.AccAddress) *KVStoreTx { - bytes := fmt.Sprintf("%s=%s=%s", key, value, accAddress) - return &KVStoreTx{ - key: []byte(key), - value: []byte(value), - bytes: []byte(bytes), - address: accAddress, +func NewTx(key, value string) kvstoreTx { + bytes := fmt.Sprintf("%s=%s", key, value) + return kvstoreTx{ + key: []byte(key), + value: []byte(value), + bytes: []byte(bytes), } } diff --git a/simapp/app.go b/simapp/app.go index fa00c5c65b65..c6ec1ab13e68 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -165,26 +165,9 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - interfaceRegistry, _ := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ - ProtoFiles: proto.HybridResolver, - SigningOptions: signing.Options{ - AddressCodec: address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), - ValidatorAddressCodec: address.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), - }, - }) - appCodec := codec.NewProtoCodec(interfaceRegistry) - legacyAmino := codec.NewLegacyAmino() - signingCtx := interfaceRegistry.SigningContext() - txConfig := authtx.NewTxConfig(appCodec, signingCtx.AddressCodec(), signingCtx.ValidatorAddressCodec(), authtx.DefaultSignModes) - - govModuleAddr, err := signingCtx.AddressCodec().BytesToString(authtypes.NewModuleAddress(govtypes.ModuleName)) - if err != nil { - panic(err) - } - - if err := signingCtx.Validate(); err != nil { - panic(err) - } + appCodec := encodingConfig.Marshaler + legacyAmino := encodingConfig.Amino + interfaceRegistry := encodingConfig.InterfaceRegistry std.RegisterLegacyAminoCodec(legacyAmino) std.RegisterInterfaces(interfaceRegistry) @@ -419,7 +402,9 @@ func NewSimApp( ), ) - /**** Module Options ****/ + // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment + // we prefer to be more strict in what arguments the modules expect. + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 0fa1a5a472ca..6e935a3b3b61 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -73,41 +73,36 @@ var ( exportWithValidatorSet []string ) -func TestAppImportExport(t *testing.T) { - simsx.Run(t, NewSimApp, setupStateFactory, func(t testing.TB, ti simsx.TestInstance[*SimApp], _ []simtypes.Account) { - app := ti.App - t.Log("exporting genesis...\n") - exported, err := app.ExportAppStateAndValidators(false, exportWithValidatorSet, exportAllModules) - require.NoError(t, err) - - t.Log("importing genesis...\n") - newTestInstance := simsx.NewSimulationAppInstance(t, ti.Cfg, NewSimApp) - newApp := newTestInstance.App - var genesisState GenesisState - require.NoError(t, json.Unmarshal(exported.AppState, &genesisState)) - ctxB := newApp.NewContextLegacy(true, cmtproto.Header{Height: app.LastBlockHeight()}) - _, err = newApp.ModuleManager.InitGenesis(ctxB, genesisState) - if IsEmptyValidatorSetErr(err) { - t.Skip("Skipping simulation as all validators have been unbonded") - return - } - require.NoError(t, err) - err = newApp.StoreConsensusParams(ctxB, exported.ConsensusParams) - require.NoError(t, err) - - t.Log("comparing stores...") - // skip certain prefixes - skipPrefixes := map[string][][]byte{ - stakingtypes.StoreKey: { + storeKeysPrefixes := []StoreKeysPrefixes{ + {app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}}, + { + app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey], + [][]byte{ stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey, - stakingtypes.UnbondingIDKey, stakingtypes.UnbondingIndexKey, stakingtypes.UnbondingTypeKey, + stakingtypes.HistoricalInfoKey, }, - authzkeeper.StoreKey: {authzkeeper.GrantQueuePrefix}, - feegrant.StoreKey: {feegrant.FeeAllowanceQueueKeyPrefix}, - slashingtypes.StoreKey: {slashingtypes.ValidatorMissedBlockBitmapKeyPrefix}, - } - AssertEqualStores(t, app, newApp, app.SimulationManager().StoreDecoders, skipPrefixes) - }) + }, // ordering may change but it doesn't matter + {app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}}, + {app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}}, + {app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}}, + {app.keys[banktypes.StoreKey], newApp.keys[banktypes.StoreKey], [][]byte{banktypes.BalancesPrefix}}, + {app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}}, + {app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}}, + {app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}}, + {app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}}, + {app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{}}, + } + + for _, skp := range storeKeysPrefixes { + storeA := ctxA.KVStore(skp.A) + storeB := ctxB.KVStore(skp.B) + + failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes) + require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") + + fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) + require.Equal(t, len(failedKVAs), 0, GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, failedKVAs, failedKVBs)) + } } // Scenario: diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index ce46f9f81a2f..d41557790b1b 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -121,11 +121,26 @@ func NewRootCmd() *cobra.Command { autoCliOpts := tempApp.AutoCliOpts() autoCliOpts.ClientCtx = initClientCtx - nodeCmds := nodeservice.NewNodeCommands() - autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions() +// appExport creates a new simapp (optionally at a given height) +// and exports state. +func (a appCreator) appExport( + logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, + appOpts servertypes.AppOptions, +) (servertypes.ExportedApp, error) { + var simApp *simapp.SimApp + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } - if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { - panic(err) + if height != -1 { + simApp = simapp.NewSimApp(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) } return rootCmd diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index 55793bc3f719..52b472efeacd 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -176,43 +176,7 @@ Example: return cmd } -// testnetStartCmd returns a cmd to start multi validator in-process testnet -func testnetStartCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "start", - Short: "Launch an in-process multi-validator testnet", - Long: fmt.Sprintf(`testnet will launch an in-process multi-validator testnet, -and generate a directory for each validator populated with necessary -configuration files (private validator, genesis, config, etc.). - -Example: - %s testnet --validator-count4 --output-dir ./.testnets - `, version.AppName), - RunE: func(cmd *cobra.Command, _ []string) (err error) { - args := startArgs{} - args.outputDir, _ = cmd.Flags().GetString(flagOutputDir) - args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID) - args.minGasPrices, _ = cmd.Flags().GetString(server.FlagMinGasPrices) - args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators) - args.algo, _ = cmd.Flags().GetString(flags.FlagKeyType) - args.enableLogging, _ = cmd.Flags().GetBool(flagEnableLogging) - args.rpcAddress, _ = cmd.Flags().GetString(flagRPCAddress) - args.apiAddress, _ = cmd.Flags().GetString(flagAPIAddress) - args.grpcAddress, _ = cmd.Flags().GetString(flagGRPCAddress) - args.printMnemonic, _ = cmd.Flags().GetBool(flagPrintMnemonic) - - return startTestnet(cmd, args) - }, - } - - addTestnetFlagsToCmd(cmd) - cmd.Flags().Bool(flagEnableLogging, false, "Enable INFO logging of CometBFT validator nodes") - cmd.Flags().String(flagRPCAddress, "tcp://127.0.0.1:26657", "the RPC address to listen on") - cmd.Flags().String(flagAPIAddress, "tcp://127.0.0.1:1317", "the address to listen on for REST API") - cmd.Flags().String(flagGRPCAddress, "127.0.0.1:9090", "the gRPC server address to listen on") - cmd.Flags().Bool(flagPrintMnemonic, true, "print mnemonic of first validator to stdout for manual testing") - return cmd -} +const nodeDirPerm = 0o755 const nodeDirPerm = 0o755 @@ -224,8 +188,8 @@ func initTestnetFiles( mm *module.Manager, args initArgs, ) error { - if args.chainID == "" { - args.chainID = "chain-" + unsafe.Str(6) + if chainID == "" { + chainID = "chain-" + tmrand.NewRand().Str(6) } nodeIDs := make([]string, args.numValidators) valPubKeys := make([]cryptotypes.PubKey, args.numValidators) @@ -421,7 +385,7 @@ func initGenFiles( genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string, numValidators int, ) error { - appGenState := mm.DefaultGenesis() + appGenState := mbm.DefaultGenesis(clientCtx.Codec) // set the accounts in the genesis state var authGenState authtypes.GenesisState @@ -544,50 +508,13 @@ func calculateIP(ip string, i int) (string, error) { func writeFile(name, dir string, contents []byte) error { file := filepath.Join(dir, name) - if err := os.MkdirAll(dir, 0o755); err != nil { - return fmt.Errorf("could not create directory %q: %w", dir, err) - } - - return os.WriteFile(file, contents, 0o600) -} - -// startTestnet starts an in-process testnet -func startTestnet(cmd *cobra.Command, args startArgs) error { - networkConfig := network.DefaultConfig(simapp.NewTestNetworkFixture) - - // Default networkConfig.ChainID is random, and we should only override it if chainID provided - // is non-empty - if args.chainID != "" { - networkConfig.ChainID = args.chainID - } - networkConfig.SigningAlgo = args.algo - networkConfig.MinGasPrices = args.minGasPrices - networkConfig.NumValidators = args.numValidators - networkConfig.EnableLogging = args.enableLogging - networkConfig.RPCAddress = args.rpcAddress - networkConfig.APIAddress = args.apiAddress - networkConfig.GRPCAddress = args.grpcAddress - networkConfig.PrintMnemonic = args.printMnemonic - networkConfig.TimeoutCommit = args.timeoutCommit - networkLogger := network.NewCLILogger(cmd) - - baseDir := fmt.Sprintf("%s/%s", args.outputDir, networkConfig.ChainID) - if _, err := os.Stat(baseDir); !os.IsNotExist(err) { - return fmt.Errorf( - "testnests directory already exists for chain-id '%s': %s, please remove or select a new --chain-id", - networkConfig.ChainID, baseDir) - } - - testnet, err := network.New(networkLogger, baseDir, networkConfig) + err := tmos.EnsureDir(writePath, 0o755) if err != nil { return err } - if _, err := testnet.WaitForHeight(1); err != nil { - return err - } - cmd.Println("press the Enter Key to terminate") - if _, err := fmt.Scanln(); err != nil { // wait for Enter Key + err = tmos.WriteFile(file, contents, 0o644) + if err != nil { return err } testnet.Cleanup() diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index f8bd0c4fc62f..ce84a6d614c8 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -255,7 +255,6 @@ func SignCheckDeliver( t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, ) (sdk.GasInfo, *sdk.Result, error) { - tx, err := helpers.GenTx( rand.New(rand.NewSource(time.Now().UnixNano())), txCfg, diff --git a/simapp/testutil_network_test.go b/simapp/testutil_network_test.go index 6d551b1dfd47..7cdc219dcf1b 100644 --- a/simapp/testutil_network_test.go +++ b/simapp/testutil_network_test.go @@ -1,4 +1,7 @@ -package simapp_test +//go:build norace +// +build norace + +package network_test import ( "testing" diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index 42742f566ed9..e80d1fa4bb37 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -68,7 +68,7 @@ func NewStore( db corestore.KVStoreWithBatch, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, ) Store { - return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext) + return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext, listeners) } func newCacheMultiStoreFromCMS(cms Store) Store { diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 27cf3be0b02a..1c4f4c9b20cd 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -298,8 +298,7 @@ func TestIAVLReverseIterator(t *testing.T) { iavlStore.Set([]byte{0x00, 0x02}, []byte("0 2")) iavlStore.Set([]byte{0x01}, []byte("1")) - testReverseIterator := func(t *testing.T, start, end []byte, expected []string) { - t.Helper() + testReverseIterator := func(t *testing.T, start []byte, end []byte, expected []string) { iter := iavlStore.ReverseIterator(start, end) var i int for i = 0; iter.Valid(); iter.Next() { diff --git a/store/listenkv/store_test.go b/store/listenkv/store_test.go index 7b1b17fd6755..508ddc00b186 100644 --- a/store/listenkv/store_test.go +++ b/store/listenkv/store_test.go @@ -25,7 +25,11 @@ var kvPairs = []kv.Pair{ //nolint:staticcheck // We are in store v1. {Key: keyFmt(3), Value: valFmt(3)}, } -var testStoreKey = types.NewKVStoreKey("listen_test") +var ( + testStoreKey = types.NewKVStoreKey("listen_test") + interfaceRegistry = codecTypes.NewInterfaceRegistry() + testMarshaller = codec.NewProtoCodec(interfaceRegistry) +) func newListenKVStore(listener *types.MemoryListener) *listenkv.Store { store := newEmptyListenKVStore(listener) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 69dbe5df3fc1..b4cd221baa27 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -211,21 +211,6 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { storesKeys := make([]types.StoreKey, 0, len(rs.storesParams)) - for key := range rs.storesParams { - storesKeys = append(storesKeys, key) - } - - if upgrades != nil { - // deterministic iteration order for upgrades - // (as the underlying store may change and - // upgrades make store changes where the execution order may matter) - sort.Slice(storesKeys, func(i, j int) bool { - return storesKeys[i].Name() < storesKeys[j].Name() - }) - } - - storesKeys := make([]types.StoreKey, 0, len(rs.storesParams)) - for key := range rs.storesParams { storesKeys = append(storesKeys, key) } diff --git a/store/snapshots/store.go b/store/snapshots/store.go index 71a0d8291f8b..7767ceaab1c6 100644 --- a/store/snapshots/store.go +++ b/store/snapshots/store.go @@ -270,14 +270,18 @@ func (s *Store) Save( snapshotHasher := sha256.New() chunkHasher := sha256.New() for chunkBody := range chunks { - // Only create the snapshot directory on encountering the first chunk. - // If the directory disappears during chunk saving, - // the whole operation will fail anyway. - if !dirCreated { - dir := s.pathSnapshot(height, format) - if err := os.MkdirAll(dir, 0o755); err != nil { - return nil, errors.Wrapf(err, "failed to create snapshot directory %q", dir) - } + defer chunkBody.Close() // nolint: staticcheck + dir := s.pathSnapshot(height, format) + err = os.MkdirAll(dir, 0o755) + if err != nil { + return nil, sdkerrors.Wrapf(err, "failed to create snapshot directory %q", dir) + } + path := s.pathChunk(height, format, index) + file, err := os.Create(path) + if err != nil { + return nil, sdkerrors.Wrapf(err, "failed to create snapshot chunk file %q", path) + } + defer file.Close() // nolint: staticcheck dirCreated = true } diff --git a/store/types/errors.go b/store/types/errors.go index db86a3cc6558..da5a854aed98 100644 --- a/store/types/errors.go +++ b/store/types/errors.go @@ -6,23 +6,4 @@ import ( const StoreCodespace = "store" -var ( - // ErrInvalidProof is returned when a proof is invalid - ErrInvalidProof = errors.Register(StoreCodespace, 2, "invalid proof") - // ErrTxDecode is returned if we cannot parse a transaction - ErrTxDecode = errors.Register(StoreCodespace, 3, "tx parse error") - - // ErrUnknownRequest to doc - ErrUnknownRequest = errors.Register(StoreCodespace, 4, "unknown request") - - // ErrLogic defines an internal logic error, e.g. an invariant or assertion - // that is violated. It is a programmer error, not a user-facing error. - ErrLogic = errors.Register(StoreCodespace, 5, "internal logic error") - - // ErrConflict defines a conflict error, e.g. when two goroutines try to access - // the same resource and one of them fails. - ErrConflict = errors.Register(StoreCodespace, 6, "conflict") - // ErrInvalidRequest defines an ABCI typed error where the request contains - // invalid data. - ErrInvalidRequest = errors.Register(StoreCodespace, 7, "invalid request") -) +var ErrInvalidProof = sdkerrors.Register(StoreCodespace, 2, "invalid proof") diff --git a/tests/integration/server/grpc/server_test.go b/tests/integration/server/grpc/server_test.go index 9b2aad91c244..367f125615ac 100644 --- a/tests/integration/server/grpc/server_test.go +++ b/tests/integration/server/grpc/server_test.go @@ -1,3 +1,6 @@ +//go:build norace +// +build norace + package grpc_test import ( diff --git a/testutil/network/network.go b/testutil/network/network.go index af1f4902f139..8d871372e17d 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -397,10 +397,8 @@ func New(l Logger, baseDir string, cfg Config) (NetworkI, error) { clientDir := filepath.Join(network.BaseDir, nodeDirName, "simcli") gentxsDir := filepath.Join(network.BaseDir, "gentxs") - err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755) - if err != nil { - return nil, err - } + require.NoError(t, os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755)) + require.NoError(t, os.MkdirAll(clientDir, 0o755)) err = os.MkdirAll(clientDir, 0o755) if err != nil { diff --git a/testutil/network/util.go b/testutil/network/util.go index ee898545d726..96e19874ee94 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -244,11 +244,13 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance func writeFile(name, dir string, contents []byte) error { file := filepath.Join(dir, name) - if err := os.MkdirAll(dir, 0o755); err != nil { - return fmt.Errorf("could not create directory %q: %w", dir, err) + err := tmos.EnsureDir(writePath, 0o755) + if err != nil { + return err } - if err := os.WriteFile(file, contents, 0o600); err != nil { + err = tmos.WriteFile(file, contents, 0o644) + if err != nil { return err } diff --git a/testutil/testdata/tx.go b/testutil/testdata/tx.go index 6de23c818b42..ff418866bf87 100644 --- a/testutil/testdata/tx.go +++ b/testutil/testdata/tx.go @@ -98,6 +98,14 @@ func (msg *TestMsg) GetSigners() []sdk.AccAddress { return signers } +func (msg *TestMsg) GetSigners() []sdk.AccAddress { + addrs := make([]sdk.AccAddress, len(msg.Signers)) + for i, in := range msg.Signers { + addr, err := sdk.AccAddressFromBech32(in) + if err != nil { + panic(err) + } + func (msg *TestMsg) ValidateBasic() error { for _, addr := range msg.Signers { if _, err := sdk.AccAddressFromBech32(addr); err != nil { diff --git a/types/address.go b/types/address.go index 5702d95fafa0..a18513743a1d 100644 --- a/types/address.go +++ b/types/address.go @@ -155,12 +155,19 @@ type Address interface { } // Ensure that different address types implement the interface +var _ Address = AccAddress{} + var ( - _ Address = AccAddress{} _ Address = ValAddress{} _ Address = ConsAddress{} ) +var ( + _ yaml.Marshaler = AccAddress{} + _ yaml.Marshaler = ValAddress{} + _ yaml.Marshaler = ConsAddress{} +) + // ---------------------------------------------------------------------------- // account // ---------------------------------------------------------------------------- @@ -301,15 +308,11 @@ func (aa AccAddress) String() string { } key := conv.UnsafeBytesToStr(aa) - - if IsAddrCacheEnabled() { - accAddrMu.Lock() - defer accAddrMu.Unlock() - - addr, ok := accAddrCache.Get(key) - if ok { - return addr.(string) - } + accAddrMu.Lock() + defer accAddrMu.Unlock() + addr, ok := accAddrCache.Get(key) + if ok { + return addr.(string) } return cacheBech32Addr(GetConfig().GetBech32AccountAddrPrefix(), aa, accAddrCache, key) } @@ -455,15 +458,11 @@ func (va ValAddress) String() string { } key := conv.UnsafeBytesToStr(va) - - if IsAddrCacheEnabled() { - valAddrMu.Lock() - defer valAddrMu.Unlock() - - addr, ok := valAddrCache.Get(key) - if ok { - return addr.(string) - } + valAddrMu.Lock() + defer valAddrMu.Unlock() + addr, ok := valAddrCache.Get(key) + if ok { + return addr.(string) } return cacheBech32Addr(GetConfig().GetBech32ValidatorAddrPrefix(), va, valAddrCache, key) } @@ -604,15 +603,11 @@ func (ca ConsAddress) String() string { } key := conv.UnsafeBytesToStr(ca) - - if IsAddrCacheEnabled() { - consAddrMu.Lock() - defer consAddrMu.Unlock() - - addr, ok := consAddrCache.Get(key) - if ok { - return addr.(string) - } + consAddrMu.Lock() + defer consAddrMu.Unlock() + addr, ok := consAddrCache.Get(key) + if ok { + return addr.(string) } return cacheBech32Addr(GetConfig().GetBech32ConsensusAddrPrefix(), ca, consAddrCache, key) } diff --git a/types/address/hash_test.go b/types/address/hash_test.go index d097d93f49ef..1a27bf2f44ed 100644 --- a/types/address/hash_test.go +++ b/types/address/hash_test.go @@ -65,11 +65,6 @@ func (suite *AddressSuite) TestComposed() { func (suite *AddressSuite) TestModule() { assert := suite.Assert() modName, key := "myModule", []byte{1, 2} - - addrLegacy := Module(modName) - assert.Equal(tmhash.SumTruncated([]byte(modName)), addrLegacy, - "when no derivation keys, we fall back to the legacy module address using sha256 of the module name") - addr := Module(modName, key) assert.Len(addr, Len, "must have correct address length") assert.NotEqual(addrLegacy, addr, diff --git a/types/address_test.go b/types/address_test.go index 014a48b7386e..7b51ce0b09ce 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -403,6 +403,66 @@ func (s *addressTestSuite) TestAddressInterface() { } } +func (s *addressTestSuite) TestVerifyAddressFormat() { + addr0 := make([]byte, 0) + addr5 := make([]byte, 5) + addr20 := make([]byte, 20) + addr32 := make([]byte, 32) + addr256 := make([]byte, 256) + + err := types.VerifyAddressFormat(addr0) + s.Require().EqualError(err, "addresses cannot be empty: unknown address") + err = types.VerifyAddressFormat(addr5) + s.Require().NoError(err) + err = types.VerifyAddressFormat(addr20) + s.Require().NoError(err) + err = types.VerifyAddressFormat(addr32) + s.Require().NoError(err) + err = types.VerifyAddressFormat(addr256) + s.Require().EqualError(err, "address max length is 255, got 256: unknown address") +} + +func (s *addressTestSuite) TestCustomAddressVerifier() { + // Create a 10 byte address + addr := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + accBech := types.AccAddress(addr).String() + valBech := types.ValAddress(addr).String() + consBech := types.ConsAddress(addr).String() + // Verify that the default logic doesn't reject this 10 byte address + // The default verifier is nil, we're only checking address length is + // between 1-255 bytes. + err := types.VerifyAddressFormat(addr) + s.Require().Nil(err) + _, err = types.AccAddressFromBech32(accBech) + s.Require().Nil(err) + _, err = types.ValAddressFromBech32(valBech) + s.Require().Nil(err) + _, err = types.ConsAddressFromBech32(consBech) + s.Require().Nil(err) + + // Set a custom address verifier only accepts 20 byte addresses + types.GetConfig().SetAddressVerifier(func(bz []byte) error { + n := len(bz) + if n == 20 { + return nil + } + return fmt.Errorf("incorrect address length %d", n) + }) + + // Verifiy that the custom logic rejects this 10 byte address + err = types.VerifyAddressFormat(addr) + s.Require().NotNil(err) + _, err = types.AccAddressFromBech32(accBech) + s.Require().NotNil(err) + _, err = types.ValAddressFromBech32(valBech) + s.Require().NotNil(err) + _, err = types.ConsAddressFromBech32(consBech) + s.Require().NotNil(err) + + // Reinitialize the global config to default address verifier (nil) + types.GetConfig().SetAddressVerifier(nil) +} + func (s *addressTestSuite) TestBech32ifyAddressBytes() { type args struct { prefix string diff --git a/types/coin_test.go b/types/coin_test.go index 84e128b32ecc..04a7d50189e6 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -876,7 +876,7 @@ func (s *coinTestSuite) TestCoins_Validate() { false, }, { - "duplicate denomination (1)", + "duplicate denomination", sdk.Coins{ {"gas", math.OneInt()}, {"gas", math.OneInt()}, @@ -929,8 +929,13 @@ func (s *coinTestSuite) TestMinMax() { {"zero-one", sdk.Coins{}, sdk.Coins{{testDenom1, one}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}}}, {"two-zero", sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{}, sdk.Coins{{testDenom2, two}}}, {"disjoint", sdk.Coins{{testDenom1, one}}, sdk.Coins{{testDenom2, two}}, sdk.Coins{}, sdk.Coins{{testDenom1, one}, {testDenom2, two}}}, - {"overlap", sdk.Coins{{testDenom1, one}, {testDenom2, two}}, sdk.Coins{{testDenom1, two}, {testDenom2, one}}, - sdk.Coins{{testDenom1, one}, {testDenom2, one}}, sdk.Coins{{testDenom1, two}, {testDenom2, two}}}, + { + "overlap", + sdk.Coins{{testDenom1, one}, {testDenom2, two}}, + sdk.Coins{{testDenom1, two}, {testDenom2, one}}, + sdk.Coins{{testDenom1, one}, {testDenom2, one}}, + sdk.Coins{{testDenom1, two}, {testDenom2, two}}, + }, } for _, tc := range cases { @@ -1334,7 +1339,6 @@ func (s *coinTestSuite) TestCoinsIsAnyNil() { s.Require().True(sdk.Coins{twoAtom, nilAtom, fiveAtom, threeEth}.IsAnyNil()) s.Require().True(sdk.Coins{nilAtom, twoAtom, fiveAtom, threeEth}.IsAnyNil()) s.Require().False(sdk.Coins{twoAtom, fiveAtom, threeEth}.IsAnyNil()) - } func (s *coinTestSuite) TestMarshalJSONCoins() { diff --git a/types/context.go b/types/context.go index 3f5778c638f1..73dbb1c5f8fb 100644 --- a/types/context.go +++ b/types/context.go @@ -67,32 +67,25 @@ type Context struct { type Request = Context // Read-only accessors -func (c Context) Context() context.Context { return c.baseCtx } -func (c Context) MultiStore() storetypes.MultiStore { return c.ms } -func (c Context) BlockHeight() int64 { return c.header.Height } -func (c Context) BlockTime() time.Time { return c.headerInfo.Time } // Deprecated: use HeaderInfo().Time -func (c Context) ChainID() string { return c.chainID } -func (c Context) TxBytes() []byte { return c.txBytes } -func (c Context) Logger() log.Logger { return c.logger } -func (c Context) VoteInfos() []abci.VoteInfo { return c.voteInfo } -func (c Context) GasMeter() storetypes.GasMeter { return c.gasMeter } -func (c Context) BlockGasMeter() storetypes.GasMeter { return c.blockGasMeter } -func (c Context) IsCheckTx() bool { return c.checkTx } // Deprecated: use core/transaction service instead -func (c Context) IsReCheckTx() bool { return c.recheckTx } // Deprecated: use core/transaction service instead -func (c Context) IsSigverifyTx() bool { return c.sigverifyTx } -func (c Context) ExecMode() ExecMode { return c.execMode } // Deprecated: use core/transaction service instead -func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } -func (c Context) EventManager() EventManagerI { return c.eventManager } -func (c Context) Priority() int64 { return c.priority } -func (c Context) KVGasConfig() storetypes.GasConfig { return c.kvGasConfig } -func (c Context) TransientKVGasConfig() storetypes.GasConfig { return c.transientKVGasConfig } -func (c Context) StreamingManager() storetypes.StreamingManager { return c.streamingManager } -func (c Context) CometInfo() comet.Info { return c.cometInfo } -func (c Context) HeaderInfo() header.Info { return c.headerInfo } - -// BlockHeader returns the header by value. -func (c Context) BlockHeader() cmtproto.Header { - return c.header +func (c Context) Context() context.Context { return c.ctx } +func (c Context) MultiStore() MultiStore { return c.ms } +func (c Context) BlockHeight() int64 { return c.header.Height } +func (c Context) BlockTime() time.Time { return c.header.Time } +func (c Context) ChainID() string { return c.chainID } +func (c Context) TxBytes() []byte { return c.txBytes } +func (c Context) Logger() log.Logger { return c.logger } +func (c Context) VoteInfos() []abci.VoteInfo { return c.voteInfo } +func (c Context) GasMeter() GasMeter { return c.gasMeter } +func (c Context) BlockGasMeter() GasMeter { return c.blockGasMeter } +func (c Context) IsCheckTx() bool { return c.checkTx } +func (c Context) IsReCheckTx() bool { return c.recheckTx } +func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } +func (c Context) EventManager() *EventManager { return c.eventManager } + +// clone the header before returning +func (c Context) BlockHeader() tmproto.Header { + msg := proto.Clone(&c.header).(*tmproto.Header) + return *msg } // HeaderHash returns a copy of the header hash obtained during abci.RequestBeginBlock diff --git a/types/module/module.go b/types/module/module.go index e0647fc12901..f37621a23103 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -300,18 +300,13 @@ type Manager struct { OrderMigrations []string } -// RegisterInterfaces registers all module interface types -func (m *Manager) RegisterInterfaces(registrar registry.InterfaceRegistrar) { - for name, b := range m.Modules { - if _, ok := b.(interface { - RegisterInterfaces(cdctypes.InterfaceRegistry) - }); ok { - panic(fmt.Sprintf("%s uses a deprecated interface registration api, implement appmodule.HasRegisterInterfaces instead", name)) - } - - if mod, ok := b.(appmodule.HasRegisterInterfaces); ok { - mod.RegisterInterfaces(registrar) - } +// NewManager creates a new Manager object +func NewManager(modules ...AppModule) *Manager { + moduleMap := make(map[string]AppModule) + modulesStr := make([]string, 0, len(modules)) + for _, module := range modules { + moduleMap[module.Name()] = module + modulesStr = append(modulesStr, module.Name()) } } @@ -632,7 +627,7 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM app if modules == nil { modules = DefaultMigrationsOrder(m.ModuleNames()) } - var modules = m.OrderMigrations + modules := m.OrderMigrations if modules == nil { modules = DefaultMigrationsOrder(m.ModuleNames()) } diff --git a/types/module/module_test.go b/types/module/module_test.go index fb2b5f746540..a088ae8a4df8 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -183,28 +183,10 @@ func TestManager_InitGenesis(t *testing.T) { genesisData = map[string]json.RawMessage{ "module1": json.RawMessage(`{"key": "value"}`), "module2": json.RawMessage(`{"key": "value"}`), - "module3": json.RawMessage(`{"key": "value"}`), } - - mockAppModuleABCI1 := mock.NewMockAppModuleWithAllExtensionsABCI(mockCtrl) - mockAppModuleABCI2 := mock.NewMockAppModuleWithAllExtensionsABCI(mockCtrl) - mockAppModuleABCI1.EXPECT().Name().Times(4).Return("module1") - mockAppModuleABCI2.EXPECT().Name().Times(2).Return("module2") - mmABCI := module.NewManager(mockAppModuleABCI1, mockAppModuleABCI2) - // errors because more than one module returns validator set updates - mockAppModuleABCI1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module1"])).Times(1).Return([]module.ValidatorUpdate{{}}, nil) - mockAppModuleABCI2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module2"])).Times(1).Return([]module.ValidatorUpdate{{}}, nil) - _, err = mmABCI.InitGenesis(ctx, genesisData) - require.ErrorContains(t, err, "validator InitGenesis updates already set by a previous module") - - // happy path - - mm2 := module.NewManager(mockAppModuleABCI1, mockAppModule2, module.CoreAppModuleAdaptor("module3", mockAppModule3)) - mockAppModuleABCI1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module1"])).Times(1).Return([]module.ValidatorUpdate{{}}, nil) - mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module2"])).Times(1) - mockAppModule3.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Any()).Times(1).Return(nil) - _, err = mm2.InitGenesis(ctx, genesisData) - require.NoError(t, err) + mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}}) + mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{{}}) + require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) }) } func TestManager_ExportGenesis(t *testing.T) { @@ -227,29 +209,8 @@ func TestManager_ExportGenesis(t *testing.T) { want := map[string]json.RawMessage{ "module1": json.RawMessage(`{"key1": "value1"}`), "module2": json.RawMessage(`{"key2": "value2"}`), - "mockCoreAppModule": json.RawMessage(`{ - "someField": "someKey" -}`), } - - res, err := mm.ExportGenesis(ctx) - require.NoError(t, err) - require.Equal(t, want, res) - - res, err = mm.ExportGenesisForModules(ctx, []string{}) - require.NoError(t, err) - require.Equal(t, want, res) - - res, err = mm.ExportGenesisForModules(ctx, []string{"module1"}) - require.NoError(t, err) - require.Equal(t, map[string]json.RawMessage{"module1": json.RawMessage(`{"key1": "value1"}`)}, res) - - res, err = mm.ExportGenesisForModules(ctx, []string{"module2"}) - require.NoError(t, err) - require.NotEqual(t, map[string]json.RawMessage{"module1": json.RawMessage(`{"key1": "value1"}`)}, res) - - _, err = mm.ExportGenesisForModules(ctx, []string{"module1", "modulefoo"}) - require.Error(t, err) + require.Equal(t, want, mm.ExportGenesis(ctx, cdc)) } func TestManager_EndBlock(t *testing.T) { diff --git a/types/query/filtered_pagination.go b/types/query/filtered_pagination.go index ff4cb18b7411..b6fd499ee1fa 100644 --- a/types/query/filtered_pagination.go +++ b/types/query/filtered_pagination.go @@ -20,10 +20,9 @@ func FilteredPaginate( pageRequest *PageRequest, onResult func(key, value []byte, accumulate bool) (bool, error), ) (*PageResponse, error) { - pageRequest = initPageRequestDefaults(pageRequest) - - if pageRequest.Offset > 0 && pageRequest.Key != nil { - return nil, errors.New("invalid request, either offset or key is expected, got both") + // if the PageRequest is nil, use default PageRequest + if pageRequest == nil { + pageRequest = &PageRequest{} } var ( diff --git a/types/query/pagination.go b/types/query/pagination.go index 9c37f867b1b8..ff38a95a38a3 100644 --- a/types/query/pagination.go +++ b/types/query/pagination.go @@ -59,10 +59,9 @@ func Paginate( pageRequest *PageRequest, onResult func(key, value []byte) error, ) (*PageResponse, error) { - pageRequest = initPageRequestDefaults(pageRequest) - - if pageRequest.Offset > 0 && pageRequest.Key != nil { - return nil, errors.New("invalid request, either offset or key is expected, got both") + // if the PageRequest is nil, use default PageRequest + if pageRequest == nil { + pageRequest = &PageRequest{} } iterator := getIterator(prefixStore, pageRequest.Key, pageRequest.Reverse) diff --git a/types/simulation/rand_util.go b/types/simulation/rand_util.go index 2dd39ead89bd..dbbaa943872c 100644 --- a/types/simulation/rand_util.go +++ b/types/simulation/rand_util.go @@ -54,7 +54,7 @@ func RandPositiveInt(r *rand.Rand, max math.Int) (math.Int, error) { // RandomAmount generates a random amount // Note: The range of RandomAmount includes max, and is, in fact, biased to return max as well as 0. -func RandomAmount(r *rand.Rand, max math.Int) math.Int { +func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { randInt := big.NewInt(0) switch r.Intn(10) { @@ -71,7 +71,7 @@ func RandomAmount(r *rand.Rand, max math.Int) math.Int { // RandomDecAmount generates a random decimal amount // Note: The range of RandomDecAmount includes max, and is, in fact, biased to return max as well as 0. -func RandomDecAmount(r *rand.Rand, max math.LegacyDec) math.LegacyDec { +func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { randInt := big.NewInt(0) switch r.Intn(10) { diff --git a/types/simulation/types.go b/types/simulation/types.go index cf0fbe1b1816..2d6851394dfb 100644 --- a/types/simulation/types.go +++ b/types/simulation/types.go @@ -112,7 +112,10 @@ func NewOperationMsg(msg sdk.Msg, ok bool, comment string) OperationMsg { if moduleName == "" { moduleName = msgType } - return NewOperationMsgBasic(moduleName, msgType, comment, ok) + + bz := cdc.MustMarshalJSON(msg) + + return NewOperationMsgBasic(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), comment, ok, bz) } // NoOpMsg - create a no-operation message diff --git a/types/tx/types.go b/types/tx/types.go index 723d67944bbc..25edbbac5b92 100644 --- a/types/tx/types.go +++ b/types/tx/types.go @@ -138,7 +138,7 @@ func (t *Tx) GetFee() sdk.Coins { return t.AuthInfo.Fee.Amount } -func (t *Tx) FeePayer(cdc codec.Codec) []byte { +func (t *Tx) FeePayer() sdk.AccAddress { feePayer := t.AuthInfo.Fee.Payer if feePayer != "" { return sdk.MustAccAddressFromBech32(feePayer) diff --git a/types/utils_test.go b/types/utils_test.go index 4c74dfd438d3..68d615442bd8 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -23,6 +23,53 @@ func (s *utilsTestSuite) SetupSuite() { s.T().Parallel() } +func (s *utilsTestSuite) TestSortJSON() { + cases := []struct { + unsortedJSON string + want string + wantErr bool + }{ + // simple case + { + unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, + want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false, + }, + // failing case (invalid JSON): + { + unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, + want: "", + wantErr: true, + }, + // genesis.json + { + unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"stake","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"stake"},"candidates":null,"bonds":null}}}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"stake"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"stake","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + wantErr: false, + }, + // from the TXSpec: + { + unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, + want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, + wantErr: false, + }, + } + + for tcIndex, tc := range cases { + tc := tc + got, err := sdk.SortJSON([]byte(tc.unsortedJSON)) + if tc.wantErr { + s.Require().NotNil(err, "tc #%d", tcIndex) + s.Require().Panics(func() { sdk.MustSortJSON([]byte(tc.unsortedJSON)) }) + } else { + s.Require().Nil(err, "tc #%d, err=%s", tcIndex, err) + s.Require().NotPanics(func() { sdk.MustSortJSON([]byte(tc.unsortedJSON)) }) + s.Require().Equal(got, sdk.MustSortJSON([]byte(tc.unsortedJSON))) + } + + s.Require().Equal(string(got), tc.want) + } +} + func (s *utilsTestSuite) TestTimeFormatAndParse() { cases := []struct { RFC3339NanoStr string diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index 40ac85955d1b..7dca1f3a0575 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -41,7 +41,12 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { } if options.SignModeHandler == nil { - return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + } + + sigGasConsumer := options.SigGasConsumer + if sigGasConsumer == nil { + sigGasConsumer = DefaultSigVerificationGasConsumer } anteDecorators := []sdk.AnteDecorator{ diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 94c2e4c18698..5412972ce15e 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -643,8 +643,7 @@ func TestAnteHandlerFees(t *testing.T) { } for _, tc := range testCases { - t.Run(fmt.Sprintf("Case %s", tc.desc), func(t *testing.T) { - suite := SetupTestSuite(t, false) + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() args := tc.malleate(suite) args.feeAmount = feeAmount diff --git a/x/auth/ante/basic_test.go b/x/auth/ante/basic_test.go index 1a5687b92f62..73e0f70b45e9 100644 --- a/x/auth/ante/basic_test.go +++ b/x/auth/ante/basic_test.go @@ -179,8 +179,8 @@ func TestConsumeGasForTxSize(t *testing.T) { consumedSimGas := suite.ctx.GasMeter().GasConsumed() - beforeSimGas // require that antehandler passes and does not underestimate decorator cost - require.Nil(t, err, "ConsumeTxSizeGasDecorator returned error: %v", err) - require.True(t, consumedSimGas >= expectedGas, "Simulate mode underestimates gas on AnteDecorator. Simulated cost: %d, expected cost: %d", consumedSimGas, expectedGas) + suite.Require().Nil(err, "ConsumeTxSizeGasDecorator returned error: %v", err) + suite.Require().True(consumedSimGas >= expectedGas, "Simulate mode underestimates gas on AnteDecorator. Simulated cost: %d, expected cost: %d", consumedSimGas, expectedGas) }) } } diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index e163d98d5148..4c8de37218cc 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -109,9 +109,9 @@ func (dfd *DeductFeeDecorator) checkDeductFee(ctx context.Context, feeTx sdk.Fee // this works only when feegrant is enabled. if feeGranter != nil { if dfd.feegrantKeeper == nil { - return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") - } else if !bytes.Equal(feeGranter, feePayer) { - err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, feeTx.GetMsgs()) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled") + } else if !feeGranter.Equals(feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()) if err != nil { granterAddr, acErr := dfd.accountKeeper.AddressCodec().BytesToString(feeGranter) if acErr != nil { diff --git a/x/auth/ante/setup.go b/x/auth/ante/setup.go index f61f585e1391..00a866a5b88b 100644 --- a/x/auth/ante/setup.go +++ b/x/auth/ante/setup.go @@ -9,8 +9,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" ) +var _ GasTx = (*legacytx.StdTx)(nil) // assert StdTx implements GasTx + // GasTx defines a Tx with a GetGas() method which is needed to use SetUpContextDecorator type GasTx interface { sdk.Tx diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index ee91d83c0146..a4e1ac1a5181 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -581,11 +581,6 @@ func ConsumeMultisignatureVerificationGas( meter gas.Meter, sig *signing.MultiSignatureData, pubKey multisig.PubKey, params types.Params, accSeq uint64, ) error { - // if BitArray is nil, it means tx has been built for simulation. - if sig.BitArray == nil { - return multisignatureSimulationVerificationGas(meter, sig, pubKey, params, accSeq) - } - size := sig.BitArray.Count() sigIndex := 0 diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 07fd7802ce50..c7e8b0340f4a 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -232,7 +232,7 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { return } - closeFunc, err := setOutputFile(cmd) + fp, err := os.OpenFile(outputDoc, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { return err } @@ -301,10 +301,19 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error { txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) } - // reads tx from args[0] - scanner, err := authclient.ReadTxsFromInput(txCfg, file) - if err != nil { - return err + infile := os.Stdin + if args[0] != "-" { + infile, err = os.Open(args[0]) + defer func() { + err2 := infile.Close() + if err == nil { + err = err2 + } + }() + + if err != nil { + return fmt.Errorf("couldn't open %s: %w", args[0], err) + } } k, err := clientCtx.Keyring.Key(name) diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 3cc0a7b50937..4a992d7eb79a 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -483,8 +483,13 @@ func signTx(cmd *cobra.Command, clientCtx client.Context, txFactory tx.Factory, } } - err = authclient.SignTxWithSignerAddress( - txFactory, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline, overwrite) + outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) + if outputDoc == "" { + cmd.Printf("%s\n", json) + return nil + } + + fp, err := os.OpenFile(outputDoc, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { return err } diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 4c35286d7427..41efdb88cebe 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -184,3 +184,23 @@ func TestBatchScanner_Scan(t *testing.T) { }) } } + +func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder) { + msgs := []sdk.Msg{testdata.NewTestMsg(addr)} + tx := legacytx.NewStdTx(msgs, legacytx.StdFee{}, []legacytx.StdSignature{}, "") + + defaultEncoderBytes, err := expected(tx) + require.NoError(t, err) + encoderBytes, err := actual(tx) + require.NoError(t, err) + require.Equal(t, defaultEncoderBytes, encoderBytes) +} + +func makeCodec() *codec.LegacyAmino { + cdc := codec.NewLegacyAmino() + sdk.RegisterLegacyAminoCodec(cdc) + cryptocodec.RegisterCrypto(cdc) + authtypes.RegisterLegacyAminoCodec(cdc) + cdc.RegisterConcrete(testdata.TestMsg{}, "cosmos-sdk/Test", nil) + return cdc +} diff --git a/x/auth/keeper/grpc_query.go b/x/auth/keeper/grpc_query.go index a1a2c0dcd6a6..a67bcb44c7c5 100644 --- a/x/auth/keeper/grpc_query.go +++ b/x/auth/keeper/grpc_query.go @@ -28,12 +28,9 @@ func (ak accountKeeper) Accounts(c context.Context, req *types.QueryAccountsRequ accID := req.AccountId - address, err := s.k.Accounts.Indexes.Number.MatchExact(ctx, accID) - if err != nil { - return nil, status.Errorf(codes.NotFound, "account address not found with account number %d", accID) - } - - addr, err := s.k.addressCodec.BytesToString(address) + accounts = append(accounts, any) + return nil + }) if err != nil { return nil, err } @@ -68,7 +65,8 @@ func (ak accountKeeper) Account(c context.Context, req *types.QueryAccountReques return nil, status.Error(codes.InvalidArgument, "Address cannot be empty") } - addr, err := s.k.addressCodec.StringToBytes(req.Address) + ctx := sdk.UnwrapSDKContext(c) + addr, err := sdk.AccAddressFromBech32(req.Address) if err != nil { return nil, err } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index 4d2051d247b8..fa8c7d0ac37d 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -136,6 +136,11 @@ func NewAccountKeeper( env appmodule.Environment, cdc codec.BinaryCodec, proto func() sdk.AccountI, accountsModKeeper types.AccountsModKeeper, maccPerms map[string][]string, ac address.Codec, bech32Prefix, authority string, ) AccountKeeper { + // set KeyTable if it has not already been set + if !paramstore.HasKeyTable() { + paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) + } + permAddrs := make(map[string]types.PermissionsForAddress) for name, perms := range maccPerms { permAddrs[name] = types.NewPermissionsForAddress(name, perms) diff --git a/x/auth/tx/encoder.go b/x/auth/tx/encoder.go index f40e75962686..9e057fe6505d 100644 --- a/x/auth/tx/encoder.go +++ b/x/auth/tx/encoder.go @@ -39,13 +39,7 @@ func DefaultJSONTxEncoder(cdc codec.Codec) sdk.TxEncoder { if err != nil { return nil, err } - // 3) Umarshal the bytes to a "v1" (gogoproto) Tx - v1Tx := &sdktx.Tx{} - err = gogoproto.Unmarshal(bz, v1Tx) - if err != nil { - return nil, err - } - // 4) Marshal the "v1" (gogoproto) to Amino ProtoJSON - return cdc.MarshalJSON(v1Tx) + + return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx) } } diff --git a/x/auth/tx/query.go b/x/auth/tx/query.go index 54af403316fb..9091a4443164 100644 --- a/x/auth/tx/query.go +++ b/x/auth/tx/query.go @@ -73,6 +73,8 @@ func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, erro return nil, err } + // TODO: this may not always need to be proven + // https://github.com/cosmos/cosmos-sdk/issues/6807 resTx, err := node.Tx(context.Background(), hash, true) if err != nil { return nil, err diff --git a/x/auth/tx/service.go b/x/auth/tx/service.go index a65ce07a849a..0354f68d9aa6 100644 --- a/x/auth/tx/service.go +++ b/x/auth/tx/service.go @@ -3,9 +3,10 @@ package tx import ( "context" "fmt" + "strings" + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "strings" gogogrpc "github.com/gogo/protobuf/grpc" "github.com/golang/protobuf/proto" // nolint: staticcheck @@ -216,7 +217,6 @@ func (s txServer) GetBlockWithTxs(ctx context.Context, req *txtypes.GetBlockWith Total: blockTxsLn, }, }, nil - } func (s txServer) BroadcastTx(ctx context.Context, req *txtypes.BroadcastTxRequest) (*txtypes.BroadcastTxResponse, error) { diff --git a/x/auth/tx/testutil/suite.go b/x/auth/tx/testutil/suite.go index af7da0f1f96e..b5ecf544dff6 100644 --- a/x/auth/tx/testutil/suite.go +++ b/x/auth/tx/testutil/suite.go @@ -168,10 +168,10 @@ func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() { s.Require().NoError(err) msigData = multisig.NewMultisig(2) multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{ - SignMode: defaultSignMode, Signature: mSigBz1, + SignMode: signModeHandler.DefaultMode(), Signature: mSigBz1, }, 0) multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{ - SignMode: defaultSignMode, Signature: mSigBz2, + SignMode: signModeHandler.DefaultMode(), Signature: mSigBz2, }, 0) // set signature diff --git a/x/authz/authorization_grant.go b/x/authz/authorization_grant.go index 80740638cde0..fbd212c962dd 100644 --- a/x/authz/authorization_grant.go +++ b/x/authz/authorization_grant.go @@ -34,7 +34,7 @@ func NewGrant( /*blockTime time.Time, */ a Authorization, expiration time.Time) }, nil } -var _ gogoprotoany.UnpackInterfacesMessage = &Grant{} +var _ cdctypes.UnpackInterfacesMessage = &Grant{} // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (g Grant) UnpackInterfaces(unpacker gogoprotoany.AnyUnpacker) error { diff --git a/x/authz/authorization_grant_test.go b/x/authz/authorization_grant_test.go index 9f9f00108c73..a5259c674da2 100644 --- a/x/authz/authorization_grant_test.go +++ b/x/authz/authorization_grant_test.go @@ -20,7 +20,7 @@ func expecError(r *require.Assertions, expected string, received error) { func TestNewGrant(t *testing.T) { // ba := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))) a := NewGenericAuthorization("some-type") - var tcs = []struct { + tcs := []struct { title string a Authorization blockTime time.Time @@ -40,5 +40,4 @@ func TestNewGrant(t *testing.T) { expecError(require.New(t), tc.err, err) }) } - } diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index 370069052f47..36c334538244 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -261,8 +261,41 @@ func getExpireTime(cmd *cobra.Command) (*time.Time, error) { if err != nil { return nil, err } - if exp == 0 { - return nil, nil + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func NewCmdExecAuthorization() *cobra.Command { + cmd := &cobra.Command{ + Use: "exec [msg_tx_json_file] --from [grantee]", + Short: "execute tx on behalf of granter account", + Long: strings.TrimSpace( + fmt.Sprintf(`execute tx on behalf of granter account: +Example: + $ %s tx %s exec tx.json --from grantee + $ %s tx bank send --from --chain-id --generate-only > tx.json && %s tx %s exec tx.json --from grantee + `, version.AppName, authz.ModuleName, version.AppName, version.AppName, authz.ModuleName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + grantee := clientCtx.GetFromAddress() + + if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline { + return errors.New("cannot broadcast tx during offline mode") + } + + theTx, err := authclient.ReadTxFromFile(clientCtx, args[0]) + if err != nil { + return err + } + msg := authz.NewMsgExec(grantee, theTx.GetMsgs()) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, } e := time.Unix(exp, 0) return &e, nil diff --git a/x/authz/generic_authorization.go b/x/authz/generic_authorization.go index d543a6b282a6..7c9b445952ee 100644 --- a/x/authz/generic_authorization.go +++ b/x/authz/generic_authorization.go @@ -4,9 +4,7 @@ import ( "context" "errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/authz" -) +var _ Authorization = &GenericAuthorization{} // NewGenericAuthorization creates a new GenericAuthorization object. func NewGenericAuthorization(msgTypeURL string) *GenericAuthorization { diff --git a/x/authz/keeper/grpc_query.go b/x/authz/keeper/grpc_query.go index f2d9d438c181..b870219777b9 100644 --- a/x/authz/keeper/grpc_query.go +++ b/x/authz/keeper/grpc_query.go @@ -119,11 +119,9 @@ func (k Keeper) GranterGrants(c context.Context, req *authz.QueryGranterGrantsRe Authorization: any, Expiration: auth.Expiration, }, nil - }, func() *authz.Grant { return &authz.Grant{} }) - if err != nil { return nil, err } diff --git a/x/authz/keeper/keeper_test.go b/x/authz/keeper/keeper_test.go index dcfd710fc264..66beb1c5a711 100644 --- a/x/authz/keeper/keeper_test.go +++ b/x/authz/keeper/keeper_test.go @@ -152,28 +152,11 @@ func (s *TestSuite) TestKeeper() { err = s.authzKeeper.DeleteAllGrants(ctx, granterAddr) require.Error(err) - s.T().Log("verify granting same authorization overwrite existing authorization") - err = s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, sendAutz, &expire) - require.NoError(err) - - authorizations, err = s.authzKeeper.GetAuthorizations(ctx, granteeAddr, granterAddr) - require.NoError(err) - require.Len(authorizations, 1) - - sendAutz = &banktypes.SendAuthorization{SpendLimit: coins1000} - err = s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, sendAutz, &expire) - require.NoError(err) - authorizations, err = s.authzKeeper.GetAuthorizations(ctx, granteeAddr, granterAddr) - require.NoError(err) - require.Len(authorizations, 1) - authorization := authorizations[0] - sendAuth := authorization.(*banktypes.SendAuthorization) - require.Equal(sendAuth.SpendLimit, sendAutz.SpendLimit) - require.Equal(sendAuth.MsgTypeURL(), sendAutz.MsgTypeURL()) - - s.T().Log("verify removing non existing authorization returns error") - err = s.authzKeeper.DeleteGrant(ctx, granterAddr, granteeAddr, "abcd") - s.Require().Error(err) + s.T().Log("verify revoke executes with correct information") + err = app.AuthzKeeper.DeleteGrant(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().NoError(err) + authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType) + s.Require().Nil(authorization) } func (s *TestSuite) TestKeeperIter() { @@ -188,13 +171,10 @@ func (s *TestSuite) TestKeeperIter() { err := s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, sendAuthz, &e) s.Require().NoError(err) - err = s.authzKeeper.SaveGrant(ctx, granteeAddr, granter2Addr, sendAuthz, &e) - s.Require().NoError(err) - - _ = s.authzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) (bool, error) { - s.Require().Equal(granteeAddr, grantee) - s.Require().Contains([]sdk.AccAddress{granterAddr, granter2Addr}, granter) - return true, nil + app.AuthzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { + s.Require().Equal(granter, granterAddr) + s.Require().Equal(grantee, granteeAddr) + return true }) } diff --git a/x/authz/keeper/keys.go b/x/authz/keeper/keys.go index 68750e493903..9605f8730066 100644 --- a/x/authz/keeper/keys.go +++ b/x/authz/keeper/keys.go @@ -37,6 +37,13 @@ func grantStoreKey(grantee, granter sdk.AccAddress, msgType string) []byte { grantee = address.MustLengthPrefix(grantee) key := sdk.AppendLengthPrefixedBytes(GrantKey, granter, grantee, m) + l := 1 + len(grantee) + len(granter) + len(m) + key := make([]byte, l) + copy(key, GrantKey) + copy(key[1:], granter) + copy(key[1+len(granter):], grantee) + copy(key[l-len(m):], m) + // fmt.Println(">>>> len", l, key) return key } diff --git a/x/authz/msgs_test.go b/x/authz/msgs_test.go index 44e292a1cfa8..d7f48773e282 100644 --- a/x/authz/msgs_test.go +++ b/x/authz/msgs_test.go @@ -51,6 +51,7 @@ func TestMsgExecAuthorized(t *testing.T) { } } } + func TestMsgRevokeAuthorization(t *testing.T) { tests := []struct { title string diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 1dc8d7b0069d..212dd35b13e1 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -86,26 +86,15 @@ func (k BaseKeeper) SpendableBalances(ctx context.Context, req *types.QuerySpend return nil, status.Error(codes.InvalidArgument, "empty request") } - addr, err := k.ak.AddressCodec().StringToBytes(req.Address) - if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "invalid address: %s", err.Error()) - } - - zeroAmt := math.ZeroInt() - allLocked := k.LockedCoins(ctx, addr) - - balances, pageRes, err := query.CollectionPaginate(ctx, k.Balances, req.Pagination, func(key collections.Pair[sdk.AccAddress, string], balanceAmt math.Int) (sdk.Coin, error) { - denom := key.K2() - coin := sdk.NewCoin(denom, zeroAmt) - lockedAmt := allLocked.AmountOf(denom) - switch { - case !lockedAmt.IsPositive(): - coin.Amount = balanceAmt - case lockedAmt.LT(balanceAmt): - coin.Amount = balanceAmt.Sub(lockedAmt) + pageRes, err := query.Paginate(accountStore, req.Pagination, func(_, value []byte) error { + var result sdk.Coin + err := k.cdc.Unmarshal(value, &result) + if err != nil { + return err } - return coin, nil - }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr)) + balances = append(balances, result) + return nil + }) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) } diff --git a/x/bank/keeper/invariants.go b/x/bank/keeper/invariants.go index 51dfa157b809..41b0bcc1cb20 100644 --- a/x/bank/keeper/invariants.go +++ b/x/bank/keeper/invariants.go @@ -56,7 +56,7 @@ func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant { func TotalSupply(k Keeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { expectedTotal := sdk.Coins{} - supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.PaginationMaxLimit}) + supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit}) if err != nil { return sdk.FormatInvariant(types.ModuleName, "query supply", fmt.Sprintf("error querying total supply %v", err)), false diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 28708c854cb2..9d12290cefaa 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -88,8 +88,9 @@ func NewBaseKeeper( blockedAddrs map[string]bool, authority string, ) BaseKeeper { - if _, err := ak.AddressCodec().StringToBytes(authority); err != nil { - panic(fmt.Errorf("invalid bank authority address: %w", err)) + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } return BaseKeeper{ diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 97c50b7f4ed7..2df506837740 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -1971,16 +1971,16 @@ func (suite *KeeperTestSuite) TestBalanceTrackingEvents() { }) } -func (suite *KeeperTestSuite) getTestMetadata() []banktypes.Metadata { - return []banktypes.Metadata{ +func (suite *IntegrationTestSuite) getTestMetadata() []types.Metadata { + return []types.Metadata{ { Name: "Cosmos Hub Atom", Symbol: "ATOM", Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*banktypes.DenomUnit{ - {Denom: "uatom", Exponent: uint32(0), Aliases: []string{"microatom"}}, - {Denom: "matom", Exponent: uint32(3), Aliases: []string{"milliatom"}}, - {Denom: "atom", Exponent: uint32(6), Aliases: nil}, + DenomUnits: []*types.DenomUnit{ + {"uatom", uint32(0), []string{"microatom"}}, + {"matom", uint32(3), []string{"milliatom"}}, + {"atom", uint32(6), nil}, }, Base: "uatom", Display: "atom", diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index 387608ad68e5..9691dbc83c9a 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -76,10 +76,6 @@ func NewBaseSendKeeper( blockedAddrs map[string]bool, authority string, ) BaseSendKeeper { - if _, err := ak.AddressCodec().StringToBytes(authority); err != nil { - panic(fmt.Errorf("invalid bank authority address: %w", err)) - } - return BaseSendKeeper{ Environment: env, BaseViewKeeper: NewBaseViewKeeper(env, cdc, ak), diff --git a/x/bank/types/genesis_test.go b/x/bank/types/genesis_test.go index f7412df117fa..655eb5c480eb 100644 --- a/x/bank/types/genesis_test.go +++ b/x/bank/types/genesis_test.go @@ -146,7 +146,8 @@ func TestGenesisStateValidate(t *testing.T) { } for _, tc := range testCases { - t.Run(tc.name, func(tt *testing.T) { + tc := tc + t.Run(tc.name, func(t *testing.T) { err := tc.genesisState.Validate() if tc.expErr { diff --git a/x/bank/types/msgs_test.go b/x/bank/types/msgs_test.go index 3a85e5d367da..754c9f23a2b4 100644 --- a/x/bank/types/msgs_test.go +++ b/x/bank/types/msgs_test.go @@ -12,16 +12,82 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func TestMsgSendRoute(t *testing.T) { + addr1 := sdk.AccAddress([]byte("from")) + addr2 := sdk.AccAddress([]byte("to")) + coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10)) + msg := NewMsgSend(addr1, addr2, coins) + + require.Equal(t, msg.Route(), RouterKey) + require.Equal(t, msg.Type(), "send") +} + +func TestMsgSendValidation(t *testing.T) { + addr1 := sdk.AccAddress([]byte("from________________")) + addr2 := sdk.AccAddress([]byte("to__________________")) + addrEmpty := sdk.AccAddress([]byte("")) + addrLong := sdk.AccAddress([]byte("Purposefully long address")) + + atom123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) + atom0 := sdk.NewCoins(sdk.NewInt64Coin("atom", 0)) + atom123eth123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 123)) + atom123eth0 := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 0)} + + cases := []struct { + expectedErr string // empty means no error expected + msg *MsgSend + }{ + {"", NewMsgSend(addr1, addr2, atom123)}, // valid send + {"", NewMsgSend(addr1, addr2, atom123eth123)}, // valid send with multiple coins + {"", NewMsgSend(addrLong, addr2, atom123)}, // valid send with long addr sender + {"", NewMsgSend(addr1, addrLong, atom123)}, // valid send with long addr recipient + {": invalid coins", NewMsgSend(addr1, addr2, atom0)}, // non positive coin + {"123atom,0eth: invalid coins", NewMsgSend(addr1, addr2, atom123eth0)}, // non positive coin in multicoins + {"Invalid sender address (empty address string is not allowed): invalid address", NewMsgSend(addrEmpty, addr2, atom123)}, + {"Invalid recipient address (empty address string is not allowed): invalid address", NewMsgSend(addr1, addrEmpty, atom123)}, + } + + for _, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expectedErr == "" { + require.Nil(t, err) + } else { + require.EqualError(t, err, tc.expectedErr) + } + } +} + func TestMsgSendGetSignBytes(t *testing.T) { coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10)) - msg := NewMsgSend("cosmos1d9h8qat57ljhcm", "cosmos1da6hgur4wsmpnjyg", coins) - res, err := codec.NewProtoCodec(types.NewInterfaceRegistry()).MarshalAminoJSON(msg) - require.NoError(t, err) + msg := NewMsgSend(addr1, addr2, coins) + res := msg.GetSignBytes() expected := `{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"10","denom":"atom"}],"from_address":"cosmos1d9h8qat57ljhcm","to_address":"cosmos1da6hgur4wsmpnjyg"}}` require.Equal(t, expected, string(res)) } +func TestMsgSendGetSigners(t *testing.T) { + msg := NewMsgSend(sdk.AccAddress([]byte("input111111111111111")), sdk.AccAddress{}, sdk.NewCoins()) + res := msg.GetSigners() + // TODO: fix this ! + require.Equal(t, fmt.Sprintf("%v", res), "[696E707574313131313131313131313131313131]") +} + +func TestMsgMultiSendRoute(t *testing.T) { + // Construct a MsgSend + addr1 := sdk.AccAddress([]byte("input")) + addr2 := sdk.AccAddress([]byte("output")) + coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10)) + msg := MsgMultiSend{ + Inputs: []Input{NewInput(addr1, coins)}, + Outputs: []Output{NewOutput(addr2, coins)}, + } + + // TODO some failures for bad result + require.Equal(t, msg.Route(), RouterKey) + require.Equal(t, msg.Type(), "multisend") +} + func TestInputValidation(t *testing.T) { ac := testutil.CodecOptions{}.GetAddressCodec() addr1, err := ac.BytesToString([]byte("_______alice________")) @@ -114,6 +180,69 @@ func TestOutputValidation(t *testing.T) { } } +func TestMsgMultiSendValidation(t *testing.T) { + addr1 := sdk.AccAddress([]byte("_______alice________")) + addr2 := sdk.AccAddress([]byte("________bob_________")) + atom123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) + atom124 := sdk.NewCoins(sdk.NewInt64Coin("atom", 124)) + eth123 := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) + atom123eth123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 123)) + + input1 := NewInput(addr1, atom123) + input2 := NewInput(addr1, eth123) + output1 := NewOutput(addr2, atom123) + output2 := NewOutput(addr2, atom124) + outputMulti := NewOutput(addr2, atom123eth123) + + var emptyAddr sdk.AccAddress + + cases := []struct { + valid bool + tx MsgMultiSend + }{ + {false, MsgMultiSend{}}, // no input or output + {false, MsgMultiSend{Inputs: []Input{input1}}}, // just input + {false, MsgMultiSend{Outputs: []Output{output1}}}, // just output + {false, MsgMultiSend{ + Inputs: []Input{NewInput(emptyAddr, atom123)}, // invalid input + Outputs: []Output{output1}, + }}, + { + false, MsgMultiSend{ + Inputs: []Input{input1}, + Outputs: []Output{{emptyAddr.String(), atom123}}, + }, // invalid output + }, + { + false, MsgMultiSend{ + Inputs: []Input{input1}, + Outputs: []Output{output2}, + }, // amounts dont match + }, + { + true, MsgMultiSend{ + Inputs: []Input{input1}, + Outputs: []Output{output1}, + }, + }, + { + true, MsgMultiSend{ + Inputs: []Input{input1, input2}, + Outputs: []Output{outputMulti}, + }, + }, + } + + for i, tc := range cases { + err := tc.tx.ValidateBasic() + if tc.valid { + require.Nil(t, err, "%d: %+v", i, err) + } else { + require.NotNil(t, err, "%d", i) + } + } +} + func TestMsgMultiSendGetSignBytes(t *testing.T) { ac := testutil.CodecOptions{}.GetAddressCodec() addr1, err := ac.BytesToString([]byte("input")) @@ -122,7 +251,7 @@ func TestMsgMultiSendGetSignBytes(t *testing.T) { require.NoError(t, err) coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10)) - msg := &MsgMultiSend{ + msg := MsgMultiSend{ Inputs: []Input{NewInput(addr1, coins)}, Outputs: []Output{NewOutput(addr2, coins)}, } @@ -133,13 +262,25 @@ func TestMsgMultiSendGetSignBytes(t *testing.T) { require.Equal(t, expected, string(res)) } -func TestNewMsgSetSendEnabled(t *testing.T) { - // Punt. Just setting one to all non-default values and making sure they're as expected. - msg := NewMsgSetSendEnabled("milton", []*SendEnabled{{"barrycoin", true}}, []string{"billcoin"}) - assert.Equal(t, "milton", msg.Authority, "msg.Authority") - if assert.Len(t, msg.SendEnabled, 1, "msg.SendEnabled length") { - assert.Equal(t, "barrycoin", msg.SendEnabled[0].Denom, "msg.SendEnabled[0].Denom") - assert.True(t, msg.SendEnabled[0].Enabled, "msg.SendEnabled[0].Enabled") +func TestMsgMultiSendGetSigners(t *testing.T) { + msg := MsgMultiSend{ + Inputs: []Input{ + NewInput(sdk.AccAddress([]byte("input111111111111111")), nil), + NewInput(sdk.AccAddress([]byte("input222222222222222")), nil), + NewInput(sdk.AccAddress([]byte("input333333333333333")), nil), + }, + } + + res := msg.GetSigners() + // TODO: fix this ! + require.Equal(t, "[696E707574313131313131313131313131313131 696E707574323232323232323232323232323232 696E707574333333333333333333333333333333]", fmt.Sprintf("%v", res)) +} + +func TestMsgSendSigners(t *testing.T) { + signers := []sdk.AccAddress{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, } if assert.Len(t, msg.UseDefaultFor, 1, "msg.UseDefault") { assert.Equal(t, "billcoin", msg.UseDefaultFor[0], "msg.UseDefault[0]") diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index 405cdcae390d..a9df99338ab0 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -12,10 +12,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// TODO: Revisit this once we have proper gas fee framework. -// Ref: https://github.com/cosmos/cosmos-sdk/issues/9054 -// Ref: https://github.com/cosmos/cosmos-sdk/discussions/9072 -const gasCostPerIteration = uint64(10) +var _ authz.Authorization = &SendAuthorization{} // NewSendAuthorization creates a new SendAuthorization object. func NewSendAuthorization(spendLimit sdk.Coins, allowed []sdk.AccAddress, addressCodec address.Codec) *SendAuthorization { diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index d75e5552fcb8..0a7d9111746b 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -40,9 +40,37 @@ func NewTxCmd() *cobra.Command { return distTxCmd } -// NewWithdrawAllRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. -// This command is more powerful than AutoCLI generated command as it allows sending batch of messages. -func NewWithdrawAllRewardsCmd() *cobra.Command { +type newGenerateOrBroadcastFunc func(client.Context, *pflag.FlagSet, ...sdk.Msg) error + +func newSplitAndApply( + genOrBroadcastFn newGenerateOrBroadcastFunc, clientCtx client.Context, + fs *pflag.FlagSet, msgs []sdk.Msg, chunkSize int, +) error { + if chunkSize == 0 { + return genOrBroadcastFn(clientCtx, fs, msgs...) + } + + // split messages into slices of length chunkSize + totalMessages := len(msgs) + for i := 0; i < len(msgs); i += chunkSize { + + sliceEnd := i + chunkSize + if sliceEnd > totalMessages { + sliceEnd = totalMessages + } + + msgChunk := msgs[i:sliceEnd] + if err := genOrBroadcastFn(clientCtx, fs, msgChunk...); err != nil { + return err + } + } + + return nil +} + +func NewWithdrawRewardsCmd() *cobra.Command { + bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix() + cmd := &cobra.Command{ Use: "withdraw-all-rewards", Short: "Withdraw all delegations rewards for a delegator", diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 123b161c0b58..6cfa3e96216d 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -13,9 +13,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// AllocateTokens performs reward and fee distribution to all validators based -// on the F1 fee distribution specification. -func (k Keeper) AllocateTokens(ctx context.Context, totalPreviousPower int64, bondedVotes []comet.VoteInfo) error { +// AllocateTokens handles distribution of the collected fees +// bondedVotes is a list of (validator address, validator voted on last block flag) for all +// validators in the bonded set. +func (k Keeper) AllocateTokens( + ctx sdk.Context, sumPreviousPrecommitPower, totalPreviousPower int64, + previousProposer sdk.ConsAddress, bondedVotes []abci.VoteInfo, +) { + logger := k.Logger(ctx) + // fetch and clear the collected fees for distribution, since this is // called in BeginBlock, collected fees will be from the previous block // (and distributed to the previous proposer) diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 39f32d9e7e4e..1ca8f42a5cd9 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -47,9 +47,9 @@ func (k Keeper) initializeDelegation(ctx context.Context, val sdk.ValAddress, de } // calculate the rewards accrued by a delegation between two periods -func (k Keeper) calculateDelegationRewardsBetween(ctx context.Context, val sdk.ValidatorI, - startingPeriod, endingPeriod uint64, stake math.LegacyDec, -) (sdk.DecCoins, error) { +func (k Keeper) calculateDelegationRewardsBetween(ctx sdk.Context, val stakingtypes.ValidatorI, + startingPeriod, endingPeriod uint64, stake sdk.Dec, +) (rewards sdk.DecCoins) { // sanity check if startingPeriod > endingPeriod { return sdk.DecCoins{}, errors.New("startingPeriod cannot be greater than endingPeriod") diff --git a/x/distribution/keeper/grpc_query.go b/x/distribution/keeper/grpc_query.go index 5337ec58c342..39934537e348 100644 --- a/x/distribution/keeper/grpc_query.go +++ b/x/distribution/keeper/grpc_query.go @@ -180,16 +180,18 @@ func (k Querier) ValidatorSlashes(ctx context.Context, req *types.QueryValidator return nil, status.Errorf(codes.InvalidArgument, "invalid validator address") } - events, pageRes, err := query.CollectionFilteredPaginate(ctx, k.ValidatorSlashEvents, req.Pagination, func(key collections.Triple[sdk.ValAddress, uint64, uint64], ev types.ValidatorSlashEvent) (include bool, err error) { - if ev.ValidatorPeriod < req.StartingHeight || ev.ValidatorPeriod > req.EndingHeight { + pageRes, err := query.FilteredPaginate(slashesStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + var result types.ValidatorSlashEvent + err := k.cdc.Unmarshal(value, &result) + if err != nil { + return false, err + } + + if result.ValidatorPeriod < req.StartingHeight || result.ValidatorPeriod > req.EndingHeight { return false, nil } return true, nil - }, func(_ collections.Triple[sdk.ValAddress, uint64, uint64], value types.ValidatorSlashEvent) (types.ValidatorSlashEvent, error) { - return value, nil - }, - query.WithCollectionPaginationTriplePrefix[sdk.ValAddress, uint64, uint64](valAddr), - ) + }) if err != nil { return nil, err } diff --git a/x/distribution/keeper/store.go b/x/distribution/keeper/store.go index 6b333918dfd4..1cafec4e93e9 100644 --- a/x/distribution/keeper/store.go +++ b/x/distribution/keeper/store.go @@ -203,17 +203,21 @@ func (k Keeper) GetValidatorHistoricalReferenceCount(ctx sdk.Context) (count uin } // iterate over slash events between heights, inclusive -func (k Keeper) IterateValidatorSlashEventsBetween(ctx context.Context, val sdk.ValAddress, startingHeight, endingHeight uint64, +func (k Keeper) IterateValidatorSlashEventsBetween(ctx sdk.Context, val sdk.ValAddress, startingHeight uint64, endingHeight uint64, handler func(height uint64, event types.ValidatorSlashEvent) (stop bool), -) error { - rng := new(collections.Range[collections.Triple[sdk.ValAddress, uint64, uint64]]). - StartInclusive(collections.Join3(val, startingHeight, uint64(0))). - EndExclusive(collections.Join3(val, endingHeight+1, uint64(math.MaxUint64))) - - err := k.ValidatorSlashEvents.Walk(ctx, rng, func(k collections.Triple[sdk.ValAddress, uint64, uint64], ev types.ValidatorSlashEvent) (stop bool, err error) { - height := k.K2() - if handler(height, ev) { - return true, nil +) { + store := ctx.KVStore(k.storeKey) + iter := store.Iterator( + types.GetValidatorSlashEventKeyPrefix(val, startingHeight), + types.GetValidatorSlashEventKeyPrefix(val, endingHeight+1), + ) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + var event types.ValidatorSlashEvent + k.cdc.MustUnmarshal(iter.Value(), &event) + _, height := types.GetValidatorSlashEventAddressHeight(iter.Key()) + if handler(height, event) { + break } return false, nil }) diff --git a/x/distribution/types/query.go b/x/distribution/types/query.go index 973b038b7e11..13423038b245 100644 --- a/x/distribution/types/query.go +++ b/x/distribution/types/query.go @@ -15,7 +15,9 @@ type QueryDelegatorTotalRewardsResponse struct { } // NewQueryDelegatorTotalRewardsResponse constructs a QueryDelegatorTotalRewardsResponse -func NewQueryDelegatorTotalRewardsResponse(rewards []DelegationDelegatorReward, total sdk.DecCoins) QueryDelegatorTotalRewardsResponse { +func NewQueryDelegatorTotalRewardsResponse(rewards []DelegationDelegatorReward, + total sdk.DecCoins, +) QueryDelegatorTotalRewardsResponse { return QueryDelegatorTotalRewardsResponse{Rewards: rewards, Total: total} } @@ -32,6 +34,9 @@ func (res QueryDelegatorTotalRewardsResponse) String() string { } // NewDelegationDelegatorReward constructs a DelegationDelegatorReward. -func NewDelegationDelegatorReward(valAddr string, reward sdk.DecCoins) DelegationDelegatorReward { - return DelegationDelegatorReward{ValidatorAddress: valAddr, Reward: reward} +//nolint:interfacer +func NewDelegationDelegatorReward(valAddr sdk.ValAddress, + reward sdk.DecCoins, +) DelegationDelegatorReward { + return DelegationDelegatorReward{ValidatorAddress: valAddr.String(), Reward: reward} } diff --git a/x/evidence/keeper/grpc_query.go b/x/evidence/keeper/grpc_query.go index 854dbbd33846..ba168b296687 100644 --- a/x/evidence/keeper/grpc_query.go +++ b/x/evidence/keeper/grpc_query.go @@ -64,9 +64,31 @@ func (k Querier) AllEvidence(ctx context.Context, req *types.QueryAllEvidenceReq if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") } - - evidences, pageRes, err := query.CollectionPaginate(ctx, k.k.Evidences, req.Pagination, func(_ []byte, value exported.Evidence) (*codectypes.Any, error) { - return codectypes.NewAnyWithValue(value) + ctx := sdk.UnwrapSDKContext(c) + + k.GetAllEvidence(ctx) + + var evidence []*codectypes.Any + store := ctx.KVStore(k.storeKey) + evidenceStore := prefix.NewStore(store, types.KeyPrefixEvidence) + + pageRes, err := query.Paginate(evidenceStore, req.Pagination, func(key []byte, value []byte) error { + result, err := k.UnmarshalEvidence(value) + if err != nil { + return err + } + + msg, ok := result.(proto.Message) + if !ok { + return status.Errorf(codes.Internal, "can't protomarshal %T", msg) + } + + evidenceAny, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return err + } + evidence = append(evidence, evidenceAny) + return nil }) if err != nil { return nil, err diff --git a/x/evidence/keeper/keeper.go b/x/evidence/keeper/keeper.go index 954fc18c5e18..a52c50fed9f0 100644 --- a/x/evidence/keeper/keeper.go +++ b/x/evidence/keeper/keeper.go @@ -41,16 +41,11 @@ func NewKeeper( cdc codec.BinaryCodec, env appmodule.Environment, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ck types.ConsensusKeeper, ac, consensusAddressCodec address.Codec, ) *Keeper { - sb := collections.NewSchemaBuilder(env.KVStoreService) - k := &Keeper{ - Environment: env, - cdc: cdc, - stakingKeeper: stakingKeeper, - slashingKeeper: slashingKeeper, - consensusKeeper: ck, - addressCodec: ac, - consensusAddressCodec: consensusAddressCodec, - Evidences: collections.NewMap(sb, types.KeyPrefixEvidence, "evidences", collections.BytesKey, codec.CollInterfaceValue[exported.Evidence](cdc)), + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + stakingKeeper: stakingKeeper, + slashingKeeper: slashingKeeper, } schema, err := sb.Build() if err != nil { diff --git a/x/feegrant/client/cli/tx.go b/x/feegrant/client/cli/tx.go index 84fec4ce42fc..37331c2fd491 100644 --- a/x/feegrant/client/cli/tx.go +++ b/x/feegrant/client/cli/tx.go @@ -65,7 +65,7 @@ Examples: ), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - + cmd.Flags().Set(flags.FlagFrom, args[0]) clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/feegrant/filtered_fee.go b/x/feegrant/filtered_fee.go index 3005ec96466d..43902bb08788 100644 --- a/x/feegrant/filtered_fee.go +++ b/x/feegrant/filtered_fee.go @@ -24,8 +24,8 @@ const ( ) var ( - _ FeeAllowanceI = (*AllowedMsgAllowance)(nil) - _ gogoprotoany.UnpackInterfacesMessage = (*AllowedMsgAllowance)(nil) + _ FeeAllowanceI = (*AllowedMsgAllowance)(nil) + _ types.UnpackInterfacesMessage = (*AllowedMsgAllowance)(nil) ) // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces diff --git a/x/feegrant/grant.go b/x/feegrant/grant.go index a483475c6b41..9825b4398885 100644 --- a/x/feegrant/grant.go +++ b/x/feegrant/grant.go @@ -10,7 +10,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -var _ gogoprotoany.UnpackInterfacesMessage = &Grant{} +var _ types.UnpackInterfacesMessage = &Grant{} // NewGrant creates a new FeeAllowanceGrant. func NewGrant(granter, grantee string, feeAllowance FeeAllowanceI) (Grant, error) { diff --git a/x/feegrant/keeper/grpc_query.go b/x/feegrant/keeper/grpc_query.go index dbccec5a1129..9cec2a25b2d9 100644 --- a/x/feegrant/keeper/grpc_query.go +++ b/x/feegrant/keeper/grpc_query.go @@ -91,25 +91,9 @@ func (q Keeper) AllowancesByGranter(c context.Context, req *feegrant.QueryAllowa return nil, status.Error(codes.InvalidArgument, "invalid request") } - granterAddr, err := q.authKeeper.AddressCodec().StringToBytes(req.Granter) - if err != nil { - return nil, err - } - - var grants []*feegrant.Grant - _, pageRes, err := query.CollectionFilteredPaginate(c, q.FeeAllowance, req.Pagination, - func(key collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (include bool, err error) { - if !sdk.AccAddress(granterAddr).Equals(key.K2()) { - return false, nil - } - - grants = append(grants, &grant) - return true, nil - }, - func(_ collections.Pair[sdk.AccAddress, sdk.AccAddress], grant feegrant.Grant) (*feegrant.Grant, error) { - return &grant, nil - }, - ) + grants = append(grants, &grant) + return nil + }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -151,7 +135,6 @@ func (q Keeper) AllowancesByGranter(c context.Context, req *feegrant.QueryAllowa return true, nil }) - if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/feegrant/keeper/grpc_query_test.go b/x/feegrant/keeper/grpc_query_test.go index 64845f59d0b9..d7a828733064 100644 --- a/x/feegrant/keeper/grpc_query_test.go +++ b/x/feegrant/keeper/grpc_query_test.go @@ -6,11 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -const ( - invalidGrantee = "invalid-grantee" - invalidGranter = "invalid-granter" -) - func (suite *KeeperTestSuite) TestFeeAllowance() { testCases := []struct { name string diff --git a/x/feegrant/keeper/keeper.go b/x/feegrant/keeper/keeper.go index 30e47ae36086..b0dfc90f8ccb 100644 --- a/x/feegrant/keeper/keeper.go +++ b/x/feegrant/keeper/keeper.go @@ -59,22 +59,12 @@ func NewKeeper(env appmodule.Environment, cdc codec.BinaryCodec, ak feegrant.Acc } // GrantAllowance creates a new grant -func (k Keeper) GrantAllowance(ctx context.Context, granter, grantee sdk.AccAddress, feeAllowance feegrant.FeeAllowanceI) error { - // Checking for duplicate entry - if f, _ := k.GetAllowance(ctx, granter, grantee); f != nil { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "fee allowance already exists") - } - - exp, err := feeAllowance.ExpiresAt() - if err != nil { - return err - } - - // expiration shouldn't be in the past. - - now := k.HeaderService.HeaderInfo(ctx).Time - if exp != nil && exp.Before(now) { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "expiration is before current block time") +func (k Keeper) GrantAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress, feeAllowance feegrant.FeeAllowanceI) error { + // create the account if it is not in account state + granteeAcc := k.authKeeper.GetAccount(ctx, grantee) + if granteeAcc == nil { + granteeAcc = k.authKeeper.NewAccountWithAddress(ctx, grantee) + k.authKeeper.SetAccount(ctx, granteeAcc) } // if expiry is not nil, add the new key to pruning queue. diff --git a/x/feegrant/keeper/keeper_test.go b/x/feegrant/keeper/keeper_test.go index af5cde5dc663..58ecbd4dbbdc 100644 --- a/x/feegrant/keeper/keeper_test.go +++ b/x/feegrant/keeper/keeper_test.go @@ -295,12 +295,10 @@ func (suite *KeeperTestSuite) TestUseGrantedFee() { suite.Error(err) suite.Contains(err.Error(), "fee allowance expired") - // verify: feegrant is not revoked - // The expired feegrant is not automatically revoked when attempting to use it. - // This is because the transaction using an expired feegrant would fail and be rolled back. - // Expired feegrants are typically cleaned up by the ABCI EndBlocker, not by failed usage attempts. - _, err = suite.feegrantKeeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2]) - suite.Require().NoError(err) + // verify: feegrant is revoked + _, err = suite.keeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2]) + suite.Error(err) + suite.Contains(err.Error(), "fee-grant not found") } func (suite *KeeperTestSuite) TestIterateGrants() { @@ -326,102 +324,4 @@ func (suite *KeeperTestSuite) TestIterateGrants() { suite.Require().Contains([]string{suite.encodedAddrs[0], suite.encodedAddrs[2]}, grant.Granter) return true }) - suite.Require().NoError(err) -} - -func (suite *KeeperTestSuite) TestPruneGrants() { - eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) - now := suite.ctx.HeaderInfo().Time - oneDay := now.AddDate(0, 0, 1) - oneYearExpiry := now.AddDate(1, 0, 0) - - testCases := []struct { - name string - ctx sdk.Context - granter sdk.AccAddress - grantee sdk.AccAddress - allowance feegrant.FeeAllowanceI - expErrMsg string - }{ - { - name: "grant pruned from state after a block: error", - ctx: suite.ctx, - granter: suite.addrs[0], - grantee: suite.addrs[1], - expErrMsg: "not found", - allowance: &feegrant.BasicAllowance{ - SpendLimit: suite.atom, - Expiration: &now, - }, - }, - { - name: "grant not pruned from state before expiration: no error", - ctx: suite.ctx, - granter: suite.addrs[2], - grantee: suite.addrs[1], - allowance: &feegrant.BasicAllowance{ - SpendLimit: eth, - Expiration: &oneDay, - }, - }, - { - name: "grant pruned from state after a day: error", - ctx: suite.ctx.WithHeaderInfo(header.Info{Time: now.AddDate(0, 0, 1)}), - granter: suite.addrs[1], - grantee: suite.addrs[0], - expErrMsg: "not found", - allowance: &feegrant.BasicAllowance{ - SpendLimit: eth, - Expiration: &oneDay, - }, - }, - { - name: "grant not pruned from state after a day: no error", - ctx: suite.ctx.WithHeaderInfo(header.Info{Time: now.AddDate(0, 0, 1)}), - granter: suite.addrs[1], - grantee: suite.addrs[0], - allowance: &feegrant.BasicAllowance{ - SpendLimit: eth, - Expiration: &oneYearExpiry, - }, - }, - { - name: "grant pruned from state after a year: error", - ctx: suite.ctx.WithHeaderInfo(header.Info{Time: now.AddDate(1, 0, 0)}), - granter: suite.addrs[1], - grantee: suite.addrs[2], - expErrMsg: "not found", - allowance: &feegrant.BasicAllowance{ - SpendLimit: eth, - Expiration: &oneYearExpiry, - }, - }, - { - name: "no expiry: no error", - ctx: suite.ctx.WithHeaderInfo(header.Info{Time: now.AddDate(1, 0, 0)}), - granter: suite.addrs[1], - grantee: suite.addrs[2], - allowance: &feegrant.BasicAllowance{ - SpendLimit: eth, - }, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - err := suite.feegrantKeeper.GrantAllowance(suite.ctx, tc.granter, tc.grantee, tc.allowance) - suite.NoError(err) - err = suite.feegrantKeeper.RemoveExpiredAllowances(tc.ctx, 5) - suite.NoError(err) - - grant, err := suite.feegrantKeeper.GetAllowance(tc.ctx, tc.granter, tc.grantee) - if tc.expErrMsg != "" { - suite.Error(err) - suite.Contains(err.Error(), tc.expErrMsg) - } else { - suite.NoError(err) - suite.NotNil(grant) - } - }) - } } diff --git a/x/feegrant/keeper/msg_server_test.go b/x/feegrant/keeper/msg_server_test.go index 2e4e8f405c80..416306169fb1 100644 --- a/x/feegrant/keeper/msg_server_test.go +++ b/x/feegrant/keeper/msg_server_test.go @@ -309,67 +309,3 @@ func (suite *KeeperTestSuite) TestRevokeAllowance() { }) } } - -func (suite *KeeperTestSuite) TestPruneAllowances() { - ctx := suite.ctx.WithHeaderInfo(header.Info{Time: time.Now()}) - oneYear := ctx.HeaderInfo().Time.AddDate(1, 0, 0) - - // We create 76 allowances, all expiring in one year - count := 0 - for i := 0; i < len(suite.encodedAddrs); i++ { - for j := 0; j < len(suite.encodedAddrs); j++ { - if count == 76 { - break - } - if suite.encodedAddrs[i] == suite.encodedAddrs[j] { - continue - } - - any, err := codectypes.NewAnyWithValue(&feegrant.BasicAllowance{ - SpendLimit: suite.atom, - Expiration: &oneYear, - }) - suite.Require().NoError(err) - req := &feegrant.MsgGrantAllowance{ - Granter: suite.encodedAddrs[i], - Grantee: suite.encodedAddrs[j], - Allowance: any, - } - - _, err = suite.msgSrvr.GrantAllowance(ctx, req) - if err != nil { - // do not fail, just try with another pair - continue - } - - count++ - } - } - - // we have 76 allowances - count = 0 - err := suite.feegrantKeeper.FeeAllowance.Walk(ctx, nil, func(key collections.Pair[types.AccAddress, types.AccAddress], value feegrant.Grant) (stop bool, err error) { - count++ - return false, nil - }) - suite.Require().NoError(err) - suite.Require().Equal(76, count) - - // after a year and one day passes, they are all expired - oneYearAndADay := ctx.HeaderInfo().Time.AddDate(1, 0, 1) - ctx = suite.ctx.WithHeaderInfo(header.Info{Time: oneYearAndADay}) - - // we prune them, but currently only 75 will be pruned - _, err = suite.msgSrvr.PruneAllowances(ctx, &feegrant.MsgPruneAllowances{}) - suite.Require().NoError(err) - - // we have 1 allowance left - count = 0 - err = suite.feegrantKeeper.FeeAllowance.Walk(ctx, nil, func(key collections.Pair[types.AccAddress, types.AccAddress], value feegrant.Grant) (stop bool, err error) { - count++ - - return false, nil - }) - suite.Require().NoError(err) - suite.Require().Equal(1, count) -} diff --git a/x/feegrant/key.go b/x/feegrant/key.go index 24c39dbfef00..27254fcf45d9 100644 --- a/x/feegrant/key.go +++ b/x/feegrant/key.go @@ -14,10 +14,8 @@ const ( StoreKey = ModuleName ) -var ( - // FeeAllowanceKeyPrefix is the set of the kvstore for fee allowance data - // - 0x00: allowance - FeeAllowanceKeyPrefix = collections.NewPrefix(0) +// FeeAllowanceKeyPrefix is the set of the kvstore for fee allowance data +var FeeAllowanceKeyPrefix = []byte{0x00} // FeeAllowanceKey is the canonical key to store a grant from granter to grantee // We store by grantee first to allow searching by everyone who granted to you diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 8d7e7491a626..9fd931b6d871 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -220,8 +220,8 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o func makeOutputFilepath(rootDir, nodeID string) (string, error) { writePath := filepath.Join(rootDir, "config", "gentx") - if err := os.MkdirAll(writePath, 0o700); err != nil { - return "", fmt.Errorf("could not create directory %q: %w", writePath, err) + if err := tmos.EnsureDir(writePath, 0o700); err != nil { + return "", err } return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 7e4808b0ce15..3d36f86bfb3f 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -93,7 +93,7 @@ func DeliverGenTxs( ctx context.Context, genTxs []json.RawMessage, stakingKeeper types.StakingKeeper, deliverTx TxHandler, txEncodingConfig client.TxEncodingConfig, -) ([]module.ValidatorUpdate, error) { +) ([]abci.ValidatorUpdate, error) { for _, genTx := range genTxs { tx, err := txEncodingConfig.TxJSONDecoder()(genTx) if err != nil { diff --git a/x/genutil/module.go b/x/genutil/module.go index ba33eab26b1f..8c7df15845d3 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -82,15 +82,18 @@ func (am AppModule) InitGenesis(ctx context.Context, data json.RawMessage) ([]mo return InitGenesis(ctx, am.stakingKeeper, am.deliverTx, genesisState, am.txEncodingConfig) } -// DecodeGenesisJSON returns the genesis transactions for the genutil module. -// It is an alternative to InitGenesis and used in server/v2 applications. -func (am AppModule) DecodeGenesisJSON(data json.RawMessage) ([]json.RawMessage, error) { - var genesisState types.GenesisState - if err := am.cdc.UnmarshalJSON(data, &genesisState); err != nil { - return nil, err - } - - return genesisState.GenTxs, nil +// NewAppModule creates a new AppModule object +func NewAppModule(accountKeeper types.AccountKeeper, + stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, + txEncodingConfig client.TxEncodingConfig, +) module.AppModule { + return module.NewGenesisOnlyAppModule(AppModule{ + AppModuleBasic: AppModuleBasic{}, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, + deliverTx: deliverTx, + txEncodingConfig: txEncodingConfig, + }) } // ExportGenesis returns the exported genesis state as raw bytes for the genutil module. diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index a4c77593a01a..b52116abc069 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -65,8 +65,8 @@ func SetGenesisStateInAppState( // for the application. // // NOTE: The pubkey input is this machines pubkey. -func GenesisStateFromAppGenesis(genesis *AppGenesis) (genesisState map[string]json.RawMessage, err error) { - if err = json.Unmarshal(genesis.AppState, &genesisState); err != nil { +func GenesisStateFromGenDoc(genDoc tmtypes.GenesisDoc) (genesisState map[string]json.RawMessage, err error) { + if err = json.Unmarshal(genDoc.AppState, &genesisState); err != nil { return genesisState, err } return genesisState, nil diff --git a/x/genutil/utils.go b/x/genutil/utils.go index b20b7bfa6ec8..5a0eaf43917e 100644 --- a/x/genutil/utils.go +++ b/x/genutil/utils.go @@ -37,11 +37,14 @@ func ExportGenesisFile(genesis *types.AppGenesis, genFile string) error { func ExportGenesisFileWithTime( genFile, chainID string, validators []cmttypes.GenesisValidator, appState json.RawMessage, genTime time.Time, ) error { - appGenesis := types.NewAppGenesisWithVersion(chainID, appState) - appGenesis.GenesisTime = genTime - appGenesis.Consensus.Validators = validators + genDoc := tmtypes.GenesisDoc{ + GenesisTime: genTime, + ChainID: chainID, + Validators: validators, + AppState: appState, + } - if err := appGenesis.ValidateAndComplete(); err != nil { + if err := genDoc.ValidateAndComplete(); err != nil { return err } @@ -71,13 +74,13 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic, keyT nodeID = string(nodeKey.ID()) pvKeyFile := config.PrivValidatorKeyFile() - if err := os.MkdirAll(filepath.Dir(pvKeyFile), 0o777); err != nil { - return "", nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvKeyFile), err) + if err := tmos.EnsureDir(filepath.Dir(pvKeyFile), 0o777); err != nil { + return "", nil, err } pvStateFile := config.PrivValidatorStateFile() - if err := os.MkdirAll(filepath.Dir(pvStateFile), 0o777); err != nil { - return "", nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvStateFile), err) + if err := tmos.EnsureDir(filepath.Dir(pvStateFile), 0o777); err != nil { + return "", nil, err } var ( diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index 32e1131fb09b..82d966d7bf81 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -157,9 +157,52 @@ func QueryVoteByTxQuery(clientCtx client.Context, params QueryVoteParams) ([]byt vote = convertVote(voteWeightedMsg) } - if voteWeightedMsg, ok := msg.(*v1.MsgVoteWeighted); ok { - vote = &v1.Vote{ - Voter: voteWeightedMsg.Voter, + return nil, fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID) +} + +// QueryDepositByTxQuery will query for a single deposit via a direct txs tags +// query. +func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositParams) ([]byte, error) { + // initial deposit was submitted with proposal, so must be queried separately + initialDeposit, err := queryInitialDepositByTxQuery(clientCtx, params.ProposalID) + if err != nil { + return nil, err + } + + if !initialDeposit.Amount.IsZero() { + bz, err := clientCtx.Codec.MarshalJSON(&initialDeposit) + if err != nil { + return nil, err + } + + return bz, nil + } + + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())), + }, + // Query proto Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeposit{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())), + }, + ) + if err != nil { + return nil, err + } + + for _, info := range searchResult.Txs { + for _, msg := range info.GetTx().GetMsgs() { + // there should only be a single deposit under the given conditions + if depMsg, ok := msg.(*types.MsgDeposit); ok { + deposit := types.Deposit{ + Depositor: depMsg.Depositor, ProposalId: params.ProposalID, Options: voteWeightedMsg.Options, } @@ -187,6 +230,30 @@ func convertVote(v *v1beta1.MsgVoteWeighted) *v1.Vote { Option: v1.VoteOption(o.Option), Weight: o.Weight.String(), } + allTxs = append(allTxs, res.Txs...) + } + + return &sdk.SearchTxsResult{Txs: allTxs}, nil +} + +// queryInitialDepositByTxQuery will query for a initial deposit of a governance proposal by +// ID. +func queryInitialDepositByTxQuery(clientCtx client.Context, proposalID uint64) (types.Deposit, error) { + searchResult, err := combineEvents( + clientCtx, defaultPage, + // Query legacy Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + // Query proto Msgs event action + []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSubmitProposal{})), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + }, + ) + if err != nil { + return types.Deposit{}, err } return &v1.Vote{ Voter: v.Voter, diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index 3f555f37d90c..1f630ce1e4cb 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -137,9 +137,9 @@ func TestGetPaginatedVotes(t *testing.T) { acc1Msgs[:1], acc2Msgs[:1], }, - votes: []v1.Vote{ - v1.NewVote(0, acc1Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""), - v1.NewVote(0, acc2Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""), + votes: []types.Vote{ + types.NewVote(0, acc1, types.NewNonSplitVoteOption(types.OptionYes)), + types.NewVote(0, acc2, types.NewNonSplitVoteOption(types.OptionYes)), }, }, { @@ -194,7 +194,8 @@ func TestGetPaginatedVotes(t *testing.T) { }, } { t.Run(tc.description, func(t *testing.T) { - marshaled := make([][]byte, len(tc.msgs)) + marshalled := make([]tmtypes.Tx, len(tc.msgs)) + cli := TxSearchMock{txs: marshalled, txConfig: encCfg.TxConfig} clientCtx := client.Context{}. WithLegacyAmino(encCfg.Amino). WithTxConfig(encCfg.TxConfig) diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 3b8da3aa8605..8a5d468638c1 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -32,21 +32,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -var ( - _, _, addr = testdata.KeyTestPubAddr() - govAcct = authtypes.NewModuleAddress(types.ModuleName) - poolAcct = authtypes.NewModuleAddress(protocolModuleName) - govAcctStr = "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" - TestProposal = getTestProposal() -) - -// mintModuleName duplicates the mint module's name to avoid a cyclic dependency with x/mint. -// It should be synced with the mint module's name if it is ever changed. -// See: https://github.com/cosmos/cosmos-sdk/blob/0e34478eb7420b69869ed50f129fc274a97a9b06/x/mint/types/keys.go#L13 -const ( - mintModuleName = "mint" - protocolModuleName = "protocolpool" -) +var TestProposal = types.NewTextProposal("Test", "description") // getTestProposal creates and returns a test proposal message. func getTestProposal() []sdk.Msg { diff --git a/x/gov/keeper/grpc_query.go b/x/gov/keeper/grpc_query.go index c863e84ee37e..12d163502854 100644 --- a/x/gov/keeper/grpc_query.go +++ b/x/gov/keeper/grpc_query.go @@ -149,8 +149,7 @@ func (q queryServer) Proposals(ctx context.Context, req *v1.QueryProposalsReques }, func(_ uint64, value v1.Proposal) (*v1.Proposal, error) { return &value, nil }) - - if err != nil && !errors.IsOf(err, collections.ErrInvalidIterator) { + if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -196,9 +195,22 @@ func (q queryServer) Votes(ctx context.Context, req *v1.QueryVotesRequest) (*v1. return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } - votes, pageRes, err := query.CollectionPaginate(ctx, q.k.Votes, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], value v1.Vote) (vote *v1.Vote, err error) { - return &value, nil - }, query.WithCollectionPaginationPairPrefix[uint64, sdk.AccAddress](req.ProposalId)) + var votes types.Votes + ctx := sdk.UnwrapSDKContext(c) + + store := ctx.KVStore(q.storeKey) + votesStore := prefix.NewStore(store, types.VotesKey(req.ProposalId)) + + pageRes, err := query.Paginate(votesStore, req.Pagination, func(key []byte, value []byte) error { + var vote types.Vote + if err := q.cdc.Unmarshal(value, &vote); err != nil { + return err + } + populateLegacyOption(&vote) + + votes = append(votes, vote) + return nil + }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -284,10 +296,21 @@ func (q queryServer) Deposits(ctx context.Context, req *v1.QueryDepositsRequest) return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } - var deposits []*v1.Deposit - deposits, pageRes, err := query.CollectionPaginate(ctx, q.k.Deposits, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], deposit v1.Deposit) (*v1.Deposit, error) { - return &deposit, nil - }, query.WithCollectionPaginationPairPrefix[uint64, sdk.AccAddress](req.ProposalId)) + var deposits types.Deposits + ctx := sdk.UnwrapSDKContext(c) + + store := ctx.KVStore(q.storeKey) + depositStore := prefix.NewStore(store, types.DepositsKey(req.ProposalId)) + + pageRes, err := query.Paginate(depositStore, req.Pagination, func(key []byte, value []byte) error { + var deposit types.Deposit + if err := q.cdc.Unmarshal(value, &deposit); err != nil { + return err + } + + deposits = append(deposits, deposit) + return nil + }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/gov/keeper/hooks_test.go b/x/gov/keeper/hooks_test.go index c6861a488f57..054027038e44 100644 --- a/x/gov/keeper/hooks_test.go +++ b/x/gov/keeper/hooks_test.go @@ -42,12 +42,12 @@ func (h *MockGovHooksReceiver) AfterProposalVote(ctx context.Context, proposalID return nil } -func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error { +func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { h.AfterProposalFailedMinDepositValid = true return nil } -func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error { +func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) { h.AfterProposalVotingPeriodEndedValid = true return nil } diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 264f9fc0722a..5e2f1d5d1be7 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -80,10 +80,9 @@ func (k Keeper) GetAuthority() string { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc codec.Codec, env appmodule.Environment, authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, sk types.StakingKeeper, pk types.PoolKeeper, - config Config, authority string, -) *Keeper { + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace types.ParamSubspace, + authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, rtr types.Router, +) Keeper { // ensure governance module account is set if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) diff --git a/x/gov/types/hooks.go b/x/gov/types/hooks.go index 7749e83b4cce..ebd5db365dc0 100644 --- a/x/gov/types/hooks.go +++ b/x/gov/types/hooks.go @@ -41,16 +41,14 @@ func (h MultiGovHooks) AfterProposalVote(ctx context.Context, proposalID uint64, return errs } -func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error { - var errs error +func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) { for i := range h { errs = errors.Join(errs, h[i].AfterProposalFailedMinDeposit(ctx, proposalID)) } return errs } -func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error { - var errs error +func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) { for i := range h { errs = errors.Join(errs, h[i].AfterProposalVotingPeriodEnded(ctx, proposalID)) } diff --git a/x/gov/types/v1beta1/tally.go b/x/gov/types/v1beta1/tally.go index b4db63037360..4a8a27324008 100644 --- a/x/gov/types/v1beta1/tally.go +++ b/x/gov/types/v1beta1/tally.go @@ -16,8 +16,8 @@ type ValidatorGovInfo struct { } // NewValidatorGovInfo creates a ValidatorGovInfo instance -func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens math.Int, delegatorShares, - delegatorDeductions math.LegacyDec, options WeightedVoteOptions, +func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens sdk.Int, delegatorShares, + delegatorDeductions sdk.Dec, options WeightedVoteOptions, ) ValidatorGovInfo { return ValidatorGovInfo{ Address: address, diff --git a/x/mint/module.go b/x/mint/module.go index 52c6324b4a11..4cdad57dc56c 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -77,10 +77,8 @@ func (AppModule) RegisterInterfaces(registrar registry.InterfaceRegistrar) { } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the mint module. -func (AppModule) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwruntime.ServeMux) { - if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { - panic(err) - } +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) } // RegisterServices registers module services. diff --git a/x/mint/types/codec.go b/x/mint/types/codec.go index 1e10558c9ea3..338ccaa95cc9 100644 --- a/x/mint/types/codec.go +++ b/x/mint/types/codec.go @@ -4,9 +4,7 @@ import ( "cosmossdk.io/core/registry" coretransaction "cosmossdk.io/core/transaction" - "github.com/cosmos/cosmos-sdk/codec/legacy" - "github.com/cosmos/cosmos-sdk/types/msgservice" -) +var amino = codec.NewLegacyAmino() // RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec func RegisterLegacyAminoCodec(registrar registry.AminoRegistrar) { diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 7e18a3e1b173..d267eb7fd351 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -28,14 +28,14 @@ func TestNextInflation(t *testing.T) { // 100% bonded, starting at 20% inflation and being reduced // (1 - (1/0.67))*(0.13/8667) { - math.LegacyOneDec(), math.LegacyNewDecWithPrec(5, 2), - math.LegacyOneDec().Sub(math.LegacyOneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr), + sdk.OneDec(), sdk.NewDecWithPrec(20, 2), + sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr), }, // 50% bonded, starting at 10% inflation and being increased { - math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(2, 2), - math.LegacyOneDec().Sub(math.LegacyNewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr), + sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(10, 2), + sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr), }, // test 0% minimum stop (testing with 100% bonded) diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 23f80eaaa734..c6959425f749 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -10,8 +10,24 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// NewParams returns Params instance with the given values. -func NewParams(mintDenom string, inflationRateChange, inflationMax, inflationMin, goalBonded math.LegacyDec, blocksPerYear uint64, maxSupply math.Int) Params { +// Parameter store keys +var ( + KeyMintDenom = []byte("MintDenom") + KeyInflationRateChange = []byte("InflationRateChange") + KeyInflationMax = []byte("InflationMax") + KeyInflationMin = []byte("InflationMin") + KeyGoalBonded = []byte("GoalBonded") + KeyBlocksPerYear = []byte("BlocksPerYear") +) + +// ParamTable for minting module. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +func NewParams( + mintDenom string, inflationRateChange, inflationMax, inflationMin, goalBonded sdk.Dec, blocksPerYear uint64, +) Params { return Params{ MintDenom: mintDenom, InflationRateChange: inflationRateChange, @@ -69,6 +85,24 @@ func (p Params) Validate() error { return nil } +// String implements the Stringer interface. +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +// Implements params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMintDenom, &p.MintDenom, validateMintDenom), + paramtypes.NewParamSetPair(KeyInflationRateChange, &p.InflationRateChange, validateInflationRateChange), + paramtypes.NewParamSetPair(KeyInflationMax, &p.InflationMax, validateInflationMax), + paramtypes.NewParamSetPair(KeyInflationMin, &p.InflationMin, validateInflationMin), + paramtypes.NewParamSetPair(KeyGoalBonded, &p.GoalBonded, validateGoalBonded), + paramtypes.NewParamSetPair(KeyBlocksPerYear, &p.BlocksPerYear, validateBlocksPerYear), + } +} + func validateMintDenom(v string) error { if strings.TrimSpace(v) == "" { return errors.New("mint denom cannot be blank") diff --git a/x/simulation/event_stats.go b/x/simulation/event_stats.go index d34b716e561e..731f79457aec 100644 --- a/x/simulation/event_stats.go +++ b/x/simulation/event_stats.go @@ -48,7 +48,7 @@ func (es EventStats) ExportJSON(path string) { panic(err) } - err = os.WriteFile(path, bz, 0o600) + err = ioutil.WriteFile(path, bz, 0o600) if err != nil { panic(err) } diff --git a/x/simulation/mock_cometbft.go b/x/simulation/mock_cometbft.go index 691494c64fe7..2eaf129a5c81 100644 --- a/x/simulation/mock_cometbft.go +++ b/x/simulation/mock_cometbft.go @@ -86,7 +86,6 @@ func updateValidators( updates []abci.ValidatorUpdate, event func(route, op, evResult string), ) map[string]mockValidator { - tb.Helper() for _, update := range updates { str := fmt.Sprintf("%X", update.PubKeyBytes) @@ -121,11 +120,8 @@ func RandomRequestFinalizeBlock( validators mockValidators, pastTimes []time.Time, pastVoteInfos [][]abci.VoteInfo, - event func(route, op, evResult string), - blockHeight int64, - time time.Time, - proposer []byte, -) *abci.FinalizeBlockRequest { + event func(route, op, evResult string), header tmproto.Header, +) abci.RequestBeginBlock { if len(validators) == 0 { return &abci.FinalizeBlockRequest{ Height: blockHeight, diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 6899f42d1916..6a0272a723df 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -37,7 +37,6 @@ func initChain( config simulation.Config, cdc codec.JSONCodec, ) (mockValidators, time.Time, []simulation.Account, string) { - appState, accounts, chainID, genesisTimestamp := appStateFn(r, accounts, config) consensusParams := randomConsensusParams(r, appState, cdc) req := abci.RequestInitChain{ @@ -294,10 +293,9 @@ type blockSimFn func( // parameters being passed every time, to minimize memory overhead. func createBlockSimulator(tb testing.TB, printProgress bool, w io.Writer, params Params, event func(route, op, evResult string), ops WeightedOperations, - operationQueue OperationQueue, timeOperationQueue *[]simtypes.FutureOperation, - logWriter LogWriter, config simtypes.Config, + operationQueue OperationQueue, timeOperationQueue []simulation.FutureOperation, + logWriter LogWriter, config simulation.Config, ) blockSimFn { - tb.Helper() lastBlockSizeState := 0 // state for [4 * uniform distribution] blocksize := 0 selectOp := ops.getSelectOpFn() @@ -360,12 +358,12 @@ Comment: %s`, } } -func runQueuedOperations(tb testing.TB, queueOps map[int][]simtypes.Operation, - blockTime time.Time, height int, r *rand.Rand, app *baseapp.BaseApp, - ctx sdk.Context, accounts []simtypes.Account, logWriter LogWriter, +// nolint: errcheck +func runQueuedOperations(queueOps map[int][]simulation.Operation, + height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, + ctx sdk.Context, accounts []simulation.Account, logWriter LogWriter, event func(route, op, evResult string), lean bool, chainID string, -) (numOpsRan int, allFutureOps []simtypes.FutureOperation) { - tb.Helper() +) (numOpsRan int) { queuedOp, ok := queueOps[height] if !ok { return 0, nil @@ -402,9 +400,7 @@ func runQueuedTimeOperations(tb testing.TB, queueOps *[]simtypes.FutureOperation app *baseapp.BaseApp, ctx sdk.Context, accounts []simtypes.Account, logWriter LogWriter, event func(route, op, evResult string), lean bool, chainID string, -) (numOpsRan int, allFutureOps []simtypes.FutureOperation) { - tb.Helper() - // Keep all future operations +) (numOpsRan int) { numOpsRan = 0 for len(*queueOps) > 0 && currentTime.After((*queueOps)[0].BlockTime) { if qOp := (*queueOps)[0]; qOp.Op != nil { diff --git a/x/simulation/util.go b/x/simulation/util.go index d21f8d8ee206..e47aa779b771 100644 --- a/x/simulation/util.go +++ b/x/simulation/util.go @@ -119,5 +119,5 @@ func GenAndDeliverTx(txCtx OperationInput, fees sdk.Coins) (simtypes.OperationMs return simtypes.NoOpMsg(txCtx.ModuleName, sdk.MsgTypeURL(txCtx.Msg), "unable to deliver tx"), nil, err } - return simtypes.NewOperationMsg(txCtx.Msg, true, ""), nil, nil + return simtypes.NewOperationMsg(txCtx.Msg, true, "", txCtx.Cdc), nil, nil } diff --git a/x/slashing/keeper/grpc_query_test.go b/x/slashing/keeper/grpc_query_test.go index 84acf9a32e13..88f0b40ea68a 100644 --- a/x/slashing/keeper/grpc_query_test.go +++ b/x/slashing/keeper/grpc_query_test.go @@ -80,9 +80,9 @@ func (s *KeeperTestSuite) TestGRPCSigningInfos() { require.NoError(err) // verify all values are returned without pagination infoResp, err := queryClient.SigningInfos(gocontext.Background(), - &slashingtypes.QuerySigningInfosRequest{Pagination: nil}) - require.NoError(err) - require.Equal(signingInfos, infoResp.Info) + &types.QuerySigningInfosRequest{Pagination: nil}) + suite.NoError(err) + suite.Equal(signingInfos, infoResp.Info) infoResp, err = queryClient.SigningInfos(gocontext.Background(), &slashingtypes.QuerySigningInfosRequest{Pagination: &query.PageRequest{Limit: 1, CountTotal: true}}) diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 95e464b422da..ef57b3eed97b 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -91,29 +91,85 @@ func (s *KeeperTestSuite) TestPubkey() { require.Equal(pubKey, expectedPubKey) } -func (s *KeeperTestSuite) TestJailAndSlash() { - slashFractionDoubleSign, err := s.slashingKeeper.SlashFractionDoubleSign(s.ctx) - s.Require().NoError(err) - - s.stakingKeeper.EXPECT().SlashWithInfractionReason(s.ctx, - consAddr, - s.ctx.BlockHeight(), - sdk.TokensToConsensusPower(sdkmath.NewInt(1), sdk.DefaultPowerReduction), - slashFractionDoubleSign, - st.Infraction_INFRACTION_UNSPECIFIED, - ).Return(sdkmath.NewInt(0), nil) - - err = s.slashingKeeper.Slash( - s.ctx, - consAddr, - slashFractionDoubleSign, - sdk.TokensToConsensusPower(sdkmath.NewInt(1), sdk.DefaultPowerReduction), - s.ctx.BlockHeight(), - ) - s.Require().NoError(err) - s.stakingKeeper.EXPECT().Jail(s.ctx, consAddr).Return(nil) - s.Require().NoError(s.slashingKeeper.Jail(s.ctx, consAddr)) -} +// Test a validator dipping in and out of the validator set +// Ensure that missed blocks are tracked correctly and that +// the start height of the signing info is reset correctly +func TestValidatorDippingInAndOut(t *testing.T) { + // initial setup + // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) + + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 1 + app.StakingKeeper.SetParams(ctx, params) + power := int64(100) + + pks := simapp.CreateTestPubKeys(3) + simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) + + addr, val := pks[0].Address(), pks[0] + consAddr := sdk.ConsAddress(addr) + tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) + valAddr := sdk.ValAddress(addr) + + tstaking.CreateValidatorWithValPower(valAddr, val, power, true) + staking.EndBlocker(ctx, app.StakingKeeper) + + // 100 first blocks OK + height := int64(0) + for ; height < int64(100); height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // kick first validator out of validator set + tstaking.CreateValidatorWithValPower(sdk.ValAddress(pks[1].Address()), pks[1], 101, true) + validatorUpdates := staking.EndBlocker(ctx, app.StakingKeeper) + require.Equal(t, 2, len(validatorUpdates)) + tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, false) + + // 600 more blocks happened + height = 700 + ctx = ctx.WithBlockHeight(height) + + // validator added back in + tstaking.DelegateWithPower(sdk.AccAddress(pks[2].Address()), sdk.ValAddress(pks[0].Address()), 50) + + validatorUpdates = staking.EndBlocker(ctx, app.StakingKeeper) + require.Equal(t, 2, len(validatorUpdates)) + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + newPower := int64(150) + + // validator misses a block + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + height++ + + // shouldn't be jailed/kicked yet + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + + // validator misses 500 more blocks, 501 total + latest := height + for ; height < latest+500; height++ { + ctx = ctx.WithBlockHeight(height) + app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // should now be jailed & kicked + staking.EndBlocker(ctx, app.StakingKeeper) + tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) + + // check all the signing information + signInfo, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(t, found) + require.Equal(t, int64(0), signInfo.MissedBlocksCounter) + require.Equal(t, int64(0), signInfo.IndexOffset) + // array should be cleared + for offset := int64(0); offset < app.SlashingKeeper.SignedBlocksWindow(ctx); offset++ { + missed := app.SlashingKeeper.GetValidatorMissedBlockBitArray(ctx, consAddr, offset) + require.False(t, missed) + } func (s *KeeperTestSuite) TestJailAndSlashWithInfractionReason() { slashFractionDoubleSign, err := s.slashingKeeper.SlashFractionDoubleSign(s.ctx) diff --git a/x/slashing/keeper/signing_info.go b/x/slashing/keeper/signing_info.go index 8270df52e217..fd9ed4d2604c 100644 --- a/x/slashing/keeper/signing_info.go +++ b/x/slashing/keeper/signing_info.go @@ -38,13 +38,19 @@ func (k Keeper) JailUntil(ctx context.Context, consAddr sdk.ConsAddress, jailTim return k.ValidatorSigningInfo.Set(ctx, consAddr, signInfo) } -// Tombstone attempts to tombstone a validator. -func (k Keeper) Tombstone(ctx context.Context, consAddr sdk.ConsAddress) error { - signInfo, err := k.ValidatorSigningInfo.Get(ctx, consAddr) - if err != nil { - addr, err := k.sk.ConsensusAddressCodec().BytesToString(consAddr) - if err != nil { - return types.ErrNoSigningInfoFound.Wrapf("could not convert consensus address to string. Error: %s", err.Error()) +// IterateValidatorSigningInfos iterates over the stored ValidatorSigningInfo +func (k Keeper) IterateValidatorSigningInfos(ctx sdk.Context, + handler func(address sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, types.ValidatorSigningInfoKeyPrefix) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + address := types.ValidatorSigningInfoAddress(iter.Key()) + var info types.ValidatorSigningInfo + k.cdc.MustUnmarshal(iter.Value(), &info) + if handler(address, info) { + break } return types.ErrNoSigningInfoFound.Wrap(fmt.Sprintf("cannot tombstone validator with consensus address %s that does not have any signing information", addr)) } @@ -67,12 +73,25 @@ func (k Keeper) IsTombstoned(ctx context.Context, consAddr sdk.ConsAddress) bool return signInfo.Tombstoned } -// getMissedBlockBitmapChunk gets the bitmap chunk at the given chunk index for -// a validator's missed block signing window. -func (k Keeper) getMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddress, chunkIndex int64) ([]byte, error) { - chunk, err := k.ValidatorMissedBlockBitmap.Get(ctx, collections.Join(addr.Bytes(), uint64(chunkIndex))) - if err != nil && !errors.Is(err, collections.ErrNotFound) { - return nil, err +// IterateValidatorMissedBlockBitArray iterates over the signed blocks window +// and performs a callback function +func (k Keeper) IterateValidatorMissedBlockBitArray(ctx sdk.Context, + address sdk.ConsAddress, handler func(index int64, missed bool) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + index := int64(0) + // Array may be sparse + for ; index < k.SignedBlocksWindow(ctx); index++ { + var missed gogotypes.BoolValue + bz := store.Get(types.ValidatorMissedBlockBitArrayKey(address, index)) + if bz == nil { + continue + } + + k.cdc.MustUnmarshal(bz, &missed) + if handler(index, missed.Value) { + break + } } return chunk, nil } diff --git a/x/staking/client/cli/tx_test.go b/x/staking/client/cli/tx_test.go index c63bf53ee2b4..81148baa5479 100644 --- a/x/staking/client/cli/tx_test.go +++ b/x/staking/client/cli/tx_test.go @@ -107,9 +107,11 @@ func (s *CLITestSuite) TestPrepareConfigForTxCreateValidator() { expectedCfg cli.TxCreateValidatorConfig }{ { - name: "all defaults", - fsModify: func(fs *pflag.FlagSet) {}, - expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.01", "1"), + name: "all defaults", + fsModify: func(fs *pflag.FlagSet) { + return + }, + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.01", "1"), }, { name: "Custom amount", @@ -123,14 +125,14 @@ func (s *CLITestSuite) TestPrepareConfigForTxCreateValidator() { fsModify: func(fs *pflag.FlagSet) { require.NoError(fs.Set(cli.FlagCommissionRate, "0.54")) }, - expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.54", "0.2", "0.01", "1"), + expectedCfg: mkTxValCfg(defaultAmount, "0.54", "0.2", "0.01", "1"), }, { name: "Custom commission max rate", fsModify: func(fs *pflag.FlagSet) { require.NoError(fs.Set(cli.FlagCommissionMaxRate, "0.89")) }, - expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.89", "0.01", "1"), + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.89", "0.01", "1"), }, { name: "Custom commission max change rate", diff --git a/x/staking/keeper/alias_functions.go b/x/staking/keeper/alias_functions.go index 0940fccfd219..1e8f5a25965a 100644 --- a/x/staking/keeper/alias_functions.go +++ b/x/staking/keeper/alias_functions.go @@ -99,14 +99,20 @@ func (k Keeper) Delegation(ctx context.Context, addrDel sdk.AccAddress, addrVal return k.Delegations.Get(ctx, collections.Join(addrDel, addrVal)) } -// IterateDelegations iterates through all of the delegations from a delegator -func (k Keeper) IterateDelegations(ctx context.Context, delAddr sdk.AccAddress, - fn func(index int64, del sdk.DelegationI) (stop bool), -) error { - var i int64 - rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delAddr) - return k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { - stop = fn(i, del) +// iterate through all of the delegations from a delegator +func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, + fn func(index int64, del types.DelegationI) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := types.GetDelegationsKey(delAddr) + + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) // smallest to largest + defer iterator.Close() + + for i := int64(0); iterator.Valid(); iterator.Next() { + del := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) + + stop := fn(i, del) if stop { return true, nil } diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 77e20723c476..7d08967aea4e 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -63,11 +63,9 @@ func (s *KeeperTestSuite) TestDelegation() { addrDels, valAddrs := createValAddrs(3) - s.accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes() - // construct the validators - amts := []math.Int{math.NewInt(9), math.NewInt(8), math.NewInt(7)} - var validators [3]stakingtypes.Validator + amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)} + var validators [3]types.Validator for i, amt := range amts { validators[i] = testutil.NewValidator(s.T(), valAddrs[i], PKs[i]) validators[i], _ = validators[i].AddTokensFromDel(amt) @@ -606,7 +604,7 @@ func (s *KeeperTestSuite) TestUndelegateSelfDelegationBelowMinSelfDelegation() { delTokens := keeper.TokensFromConsensusPower(ctx, 10) // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), valAddrs[0], PKs[0]) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) validator.MinSelfDelegation = delTokens validator, issuedShares := validator.AddTokensFromDel(delTokens) @@ -654,8 +652,8 @@ func (s *KeeperTestSuite) TestUndelegateFromUnbondingValidator() { addrDels, addrVals := createValAddrs(2) // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0]) - require.NoError(keeper.SetValidatorByConsAddr(ctx, validator)) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) validator, issuedShares := validator.AddTokensFromDel(delTokens) require.Equal(delTokens, issuedShares.RoundInt()) @@ -815,8 +813,8 @@ func (s *KeeperTestSuite) TestUnbondingAllDelegationFromValidator() { addrDels, addrVals := createValAddrs(2) // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0]) - require.NoError(keeper.SetValidatorByConsAddr(ctx, validator)) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) valTokens := keeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) @@ -1063,8 +1061,8 @@ func (s *KeeperTestSuite) TestRedelegateSelfDelegation() { addrDels, addrVals := createValAddrs(2) // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0]) - require.NoError(keeper.SetValidatorByConsAddr(ctx, validator)) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) valTokens := keeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) @@ -1113,9 +1111,14 @@ func (s *KeeperTestSuite) TestRedelegateFromUnbondingValidator() { addrDels, addrVals := createValAddrs(2) + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + require.NoError(t, simapp.FundModuleAccount(app.BankKeeper, ctx, notBondedPool.GetName(), startCoins)) + app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) + // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), addrVals[0], PKs[0]) - require.NoError(keeper.SetValidatorByConsAddr(ctx, validator)) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) valTokens := keeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) @@ -1156,18 +1159,16 @@ func (s *KeeperTestSuite) TestRedelegateFromUnbondingValidator() { require.Equal(amount, delTokens) // end block - s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, gomock.Any()) - s.applyValidatorSetUpdates(ctx, keeper, 1) + applyValidatorSetUpdates(t, ctx, app.StakingKeeper, 1) - validator, err = keeper.GetValidator(ctx, addrVals[0]) - require.NoError(err) - require.Equal(blockHeight, validator.UnbondingHeight) - params, err := keeper.Params.Get(ctx) - require.NoError(err) - require.True(blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) + validator, found := app.StakingKeeper.GetValidator(ctx, addrVals[0]) + require.True(t, found) + require.Equal(t, blockHeight, validator.UnbondingHeight) + params := app.StakingKeeper.GetParams(ctx) + require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingTime)) // change the context - header = ctx.HeaderInfo() + header = ctx.BlockHeader() blockHeight2 := int64(20) header.Height = blockHeight2 blockTime2 := time.Unix(444, 0) @@ -1194,9 +1195,14 @@ func (s *KeeperTestSuite) TestRedelegateFromUnbondedValidator() { addrDels, valAddrs := createValAddrs(2) + // add bonded tokens to pool for delegations + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + require.NoError(t, simapp.FundModuleAccount(app.BankKeeper, ctx, notBondedPool.GetName(), startCoins)) + app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) + // create a validator with a self-delegation - validator := testutil.NewValidator(s.T(), valAddrs[0], PKs[0]) - require.NoError(keeper.SetValidatorByConsAddr(ctx, validator)) + validator := teststaking.NewValidator(t, addrVals[0], PKs[0]) + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) valTokens := keeper.TokensFromConsensusPower(ctx, 10) validator, issuedShares := validator.AddTokensFromDel(valTokens) diff --git a/x/staking/keeper/grpc_query.go b/x/staking/keeper/grpc_query.go index e55671f34c9e..017240f533a3 100644 --- a/x/staking/keeper/grpc_query.go +++ b/x/staking/keeper/grpc_query.go @@ -166,26 +166,6 @@ func (k Querier) ValidatorDelegations(ctx context.Context, req *types.QueryValid }, nil } -func (k Querier) getValidatorDelegationsLegacy(ctx context.Context, req *types.QueryValidatorDelegationsRequest) ([]*types.Delegation, *query.PageResponse, error) { - store := runtime.KVStoreAdapter(k.KVStoreService.OpenKVStore(ctx)) - - valStore := prefix.NewStore(store, types.DelegationKey) - return query.GenericFilteredPaginate(k.cdc, valStore, req.Pagination, func(key []byte, delegation *types.Delegation) (*types.Delegation, error) { - _, err := k.validatorAddressCodec.StringToBytes(req.ValidatorAddr) - if err != nil { - return nil, err - } - - if !strings.EqualFold(delegation.GetValidatorAddr(), req.ValidatorAddr) { - return nil, nil - } - - return delegation, nil - }, func() *types.Delegation { - return &types.Delegation{} - }) -} - // ValidatorUnbondingDelegations queries unbonding delegations of a validator func (k Querier) ValidatorUnbondingDelegations(ctx context.Context, req *types.QueryValidatorUnbondingDelegationsRequest) (*types.QueryValidatorUnbondingDelegationsResponse, error) { if req == nil { @@ -465,21 +445,21 @@ func (k Querier) DelegatorValidators(ctx context.Context, req *types.QueryDelega return nil, err } - _, pageRes, err := query.CollectionPaginate(ctx, k.Delegations, req.Pagination, - func(_ collections.Pair[sdk.AccAddress, sdk.ValAddress], delegation types.Delegation) (types.Delegation, error) { - valAddr, err := k.validatorAddressCodec.StringToBytes(delegation.GetValidatorAddr()) - if err != nil { - return types.Delegation{}, err - } - validator, err := k.GetValidator(ctx, valAddr) - if err != nil { - return types.Delegation{}, err - } + delStore := prefix.NewStore(store, types.GetDelegationsKey(delAddr)) + pageRes, err := query.Paginate(delStore, req.Pagination, func(key []byte, value []byte) error { + delegation, err := types.UnmarshalDelegation(k.cdc, value) + if err != nil { + return err + } - validators.Validators = append(validators.Validators, validator) - return types.Delegation{}, nil - }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, sdk.ValAddress](delAddr), - ) + validator, found := k.GetValidator(ctx, delegation.GetValidatorAddr()) + if !found { + return types.ErrNoValidatorFound + } + + validators = append(validators, validator) + return nil + }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -513,8 +493,8 @@ func (k Querier) Params(ctx context.Context, _ *types.QueryParamsRequest) (*type return &types.QueryParamsResponse{Params: params}, nil } -func queryRedelegation(ctx context.Context, k Querier, req *types.QueryRedelegationsRequest) (redels types.Redelegations, err error) { - delAddr, err := k.authKeeper.AddressCodec().StringToBytes(req.DelegatorAddr) +func queryRedelegation(ctx sdk.Context, k Querier, req *types.QueryRedelegationsRequest) (redels types.Redelegations, err error) { + delAddr, err := sdk.AccAddressFromBech32(req.DelegatorAddr) if err != nil { return nil, err } diff --git a/x/staking/keeper/grpc_query_test.go b/x/staking/keeper/grpc_query_test.go index 4edd5887136c..54ff8d23cc90 100644 --- a/x/staking/keeper/grpc_query_test.go +++ b/x/staking/keeper/grpc_query_test.go @@ -14,8 +14,66 @@ func (s *KeeperTestSuite) TestGRPCQueryValidator() { ctx, keeper, queryClient := s.ctx, s.stakingKeeper, s.queryClient require := s.Require() - validator := testutil.NewValidator(s.T(), sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0]) - require.NoError(keeper.SetValidator(ctx, validator)) + len(vals), + false, + }, + { + "empty status returns all the validators", + func() { + req = &types.QueryValidatorsRequest{Status: ""} + }, + true, + len(vals), + false, + }, + { + "invalid request", + func() { + req = &types.QueryValidatorsRequest{Status: "test"} + }, + false, + 0, + false, + }, + { + "valid request", + func() { + req = &types.QueryValidatorsRequest{ + Status: types.Bonded.String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + 1, + true, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + valsResp, err := queryClient.Validators(gocontext.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(valsResp) + suite.Equal(tc.numVals, len(valsResp.Validators)) + suite.Equal(uint64(len(vals)), valsResp.Pagination.Total) + + if tc.hasNext { + suite.NotNil(valsResp.Pagination.NextKey) + } else { + suite.Nil(valsResp.Pagination.NextKey) + } + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryValidator() { + app, ctx, queryClient, vals := suite.app, suite.ctx, suite.queryClient, suite.vals + validator, found := app.StakingKeeper.GetValidator(ctx, vals[0].GetOperator()) + suite.True(found) var req *types.QueryValidatorRequest testCases := []struct { msg string @@ -30,7 +88,87 @@ func (s *KeeperTestSuite) TestGRPCQueryValidator() { false, }, { - "with valid and not existing address", + "valid request", + func() { + req = &types.QueryValidatorRequest{ValidatorAddr: vals[0].OperatorAddress} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.Validator(gocontext.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.True(validator.Equal(&res.Validator)) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryDelegatorValidators() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs + params := app.StakingKeeper.GetParams(ctx) + delValidators := app.StakingKeeper.GetDelegatorValidators(ctx, addrs[0], params.MaxValidators) + var req *types.QueryDelegatorValidatorsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryDelegatorValidatorsRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryDelegatorValidatorsRequest{ + DelegatorAddr: addrs[0].String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.DelegatorValidators(gocontext.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.Equal(1, len(res.Validators)) + suite.NotNil(res.Pagination.NextKey) + suite.Equal(uint64(len(delValidators)), res.Pagination.Total) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryDelegatorValidator() { + queryClient, addrs, vals := suite.queryClient, suite.addrs, suite.vals + addr := addrs[1] + addrVal, addrVal1 := vals[0].OperatorAddress, vals[1].OperatorAddress + var req *types.QueryDelegatorValidatorRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", func() { req = &types.QueryValidatorRequest{ ValidatorAddr: "cosmosvaloper15jkng8hytwt22lllv6mw4k89qkqehtahd84ptu", @@ -101,6 +239,209 @@ func (s *KeeperTestSuite) TestGRPCQueryValidators() { Status: types.Bonded.String(), } }, + false, + }, + { + "valid request", + func() { + req = &types.QueryDelegationRequest{DelegatorAddr: addrAcc.String(), ValidatorAddr: addrVal} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.Delegation(gocontext.Background(), req) + if tc.expPass { + suite.Equal(delegation.ValidatorAddress, res.DelegationResponse.Delegation.ValidatorAddress) + suite.Equal(delegation.DelegatorAddress, res.DelegationResponse.Delegation.DelegatorAddress) + suite.Equal(sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), res.DelegationResponse.Balance) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryDelegatorDelegations() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + addrAcc := addrs[0] + addrVal1 := vals[0].OperatorAddress + valAddr, err := sdk.ValAddressFromBech32(addrVal1) + suite.NoError(err) + delegation, found := app.StakingKeeper.GetDelegation(ctx, addrAcc, valAddr) + suite.True(found) + var req *types.QueryDelegatorDelegationsRequest + + testCases := []struct { + msg string + malleate func() + onSuccess func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) + expErr bool + }{ + { + "empty request", + func() { + req = &types.QueryDelegatorDelegationsRequest{} + }, + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) {}, + true, + }, + { + "valid request with no delegations", + func() { + req = &types.QueryDelegatorDelegationsRequest{DelegatorAddr: addrs[4].String()} + }, + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) { + suite.Equal(uint64(0), response.Pagination.Total) + suite.Len(response.DelegationResponses, 0) + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryDelegatorDelegationsRequest{ + DelegatorAddr: addrAcc.String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + func(suite *KeeperTestSuite, response *types.QueryDelegatorDelegationsResponse) { + suite.Equal(uint64(2), response.Pagination.Total) + suite.Len(response.DelegationResponses, 1) + suite.Equal(sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), response.DelegationResponses[0].Balance) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.DelegatorDelegations(gocontext.Background(), req) + if tc.expErr { + suite.Error(err) + } else { + suite.NoError(err) + tc.onSuccess(suite, res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryValidatorDelegations() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + addrAcc := addrs[0] + addrVal1 := vals[1].OperatorAddress + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + addrVal2 := valAddrs[4] + valAddr, err := sdk.ValAddressFromBech32(addrVal1) + suite.NoError(err) + delegation, found := app.StakingKeeper.GetDelegation(ctx, addrAcc, valAddr) + suite.True(found) + + var req *types.QueryValidatorDelegationsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + expErr bool + }{ + { + "empty request", + func() { + req = &types.QueryValidatorDelegationsRequest{} + }, + false, + true, + }, + { + "invalid validator delegator pair", + func() { + req = &types.QueryValidatorDelegationsRequest{ValidatorAddr: addrVal2.String()} + }, + false, + false, + }, + { + "valid request", + func() { + req = &types.QueryValidatorDelegationsRequest{ + ValidatorAddr: addrVal1, + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.ValidatorDelegations(gocontext.Background(), req) + if tc.expPass && !tc.expErr { + suite.NoError(err) + suite.Len(res.DelegationResponses, 1) + suite.NotNil(res.Pagination.NextKey) + suite.Equal(uint64(2), res.Pagination.Total) + suite.Equal(addrVal1, res.DelegationResponses[0].Delegation.ValidatorAddress) + suite.Equal(sdk.NewCoin(sdk.DefaultBondDenom, delegation.Shares.TruncateInt()), res.DelegationResponses[0].Balance) + } else if !tc.expPass && !tc.expErr { + suite.NoError(err) + suite.Nil(res.DelegationResponses) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryUnbondingDelegation() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + addrAcc2 := addrs[1] + addrVal2 := vals[1].OperatorAddress + + unbondingTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) + valAddr, err1 := sdk.ValAddressFromBech32(addrVal2) + suite.NoError(err1) + _, err := app.StakingKeeper.Undelegate(ctx, addrAcc2, valAddr, unbondingTokens.ToDec()) + suite.NoError(err) + + unbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc2, valAddr) + suite.True(found) + var req *types.QueryUnbondingDelegationRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryUnbondingDelegationRequest{} + }, + false, + }, + { + "invalid request", + func() { + req = &types.QueryUnbondingDelegationRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryUnbondingDelegationRequest{ + DelegatorAddr: addrAcc2.String(), ValidatorAddr: addrVal2, + } + }, + true, }, } @@ -122,3 +463,343 @@ func (s *KeeperTestSuite) TestGRPCQueryValidators() { }) } } + +func (suite *KeeperTestSuite) TestGRPCQueryDelegatorUnbondingDelegations() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + addrAcc, addrAcc1 := addrs[0], addrs[1] + addrVal, addrVal2 := vals[0].OperatorAddress, vals[1].OperatorAddress + + unbondingTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) + valAddr1, err1 := sdk.ValAddressFromBech32(addrVal) + suite.NoError(err1) + _, err := app.StakingKeeper.Undelegate(ctx, addrAcc, valAddr1, unbondingTokens.ToDec()) + suite.NoError(err) + valAddr2, err1 := sdk.ValAddressFromBech32(addrVal2) + suite.NoError(err1) + _, err = app.StakingKeeper.Undelegate(ctx, addrAcc, valAddr2, unbondingTokens.ToDec()) + suite.NoError(err) + + unbond, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrAcc, valAddr1) + suite.True(found) + var req *types.QueryDelegatorUnbondingDelegationsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + expErr bool + }{ + { + "empty request", + func() { + req = &types.QueryDelegatorUnbondingDelegationsRequest{} + }, + false, + true, + }, + { + "invalid request", + func() { + req = &types.QueryDelegatorUnbondingDelegationsRequest{DelegatorAddr: addrAcc1.String()} + }, + false, + false, + }, + { + "valid request", + func() { + req = &types.QueryDelegatorUnbondingDelegationsRequest{ + DelegatorAddr: addrAcc.String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.DelegatorUnbondingDelegations(gocontext.Background(), req) + if tc.expPass && !tc.expErr { + suite.NoError(err) + suite.NotNil(res.Pagination.NextKey) + suite.Equal(uint64(2), res.Pagination.Total) + suite.Len(res.UnbondingResponses, 1) + suite.Equal(unbond, res.UnbondingResponses[0]) + } else if !tc.expPass && !tc.expErr { + suite.NoError(err) + suite.Nil(res.UnbondingResponses) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryPoolParameters() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + bondDenom := sdk.DefaultBondDenom + + // Query pool + res, err := queryClient.Pool(gocontext.Background(), &types.QueryPoolRequest{}) + suite.NoError(err) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + suite.Equal(app.BankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom).Amount, res.Pool.NotBondedTokens) + suite.Equal(app.BankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom).Amount, res.Pool.BondedTokens) + + // Query Params + resp, err := queryClient.Params(gocontext.Background(), &types.QueryParamsRequest{}) + suite.NoError(err) + suite.Equal(app.StakingKeeper.GetParams(ctx), resp.Params) +} + +func (suite *KeeperTestSuite) TestGRPCQueryHistoricalInfo() { + app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient + + hi, found := app.StakingKeeper.GetHistoricalInfo(ctx, 5) + suite.True(found) + + var req *types.QueryHistoricalInfoRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryHistoricalInfoRequest{} + }, + false, + }, + { + "invalid request with negative height", + func() { + req = &types.QueryHistoricalInfoRequest{Height: -1} + }, + false, + }, + { + "valid request with old height", + func() { + req = &types.QueryHistoricalInfoRequest{Height: 4} + }, + false, + }, + { + "valid request with current height", + func() { + req = &types.QueryHistoricalInfoRequest{Height: 5} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.HistoricalInfo(gocontext.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.NotNil(res) + suite.True(hi.Equal(res.Hist)) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryRedelegations() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + + addrAcc, addrAcc1 := addrs[0], addrs[1] + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + val1, val2, val3, val4 := vals[0], vals[1], valAddrs[3], valAddrs[4] + delAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) + _, err := app.StakingKeeper.Delegate(ctx, addrAcc1, delAmount, types.Unbonded, val1, true) + suite.NoError(err) + applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) + + rdAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 1) + _, err = app.StakingKeeper.BeginRedelegation(ctx, addrAcc1, val1.GetOperator(), val2.GetOperator(), rdAmount.ToDec()) + suite.NoError(err) + applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) + + redel, found := app.StakingKeeper.GetRedelegation(ctx, addrAcc1, val1.GetOperator(), val2.GetOperator()) + suite.True(found) + + var req *types.QueryRedelegationsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + expErr bool + }{ + { + "request redelegations for non existent addr", + func() { + req = &types.QueryRedelegationsRequest{DelegatorAddr: addrAcc.String()} + }, + false, + false, + }, + { + "request redelegations with non existent pairs", + func() { + req = &types.QueryRedelegationsRequest{ + DelegatorAddr: addrAcc.String(), SrcValidatorAddr: val3.String(), + DstValidatorAddr: val4.String(), + } + }, + false, + true, + }, + { + "request redelegations with delegatoraddr, sourceValAddr, destValAddr", + func() { + req = &types.QueryRedelegationsRequest{ + DelegatorAddr: addrAcc1.String(), SrcValidatorAddr: val1.OperatorAddress, + DstValidatorAddr: val2.OperatorAddress, Pagination: &query.PageRequest{}, + } + }, + true, + false, + }, + { + "request redelegations with delegatoraddr and sourceValAddr", + func() { + req = &types.QueryRedelegationsRequest{ + DelegatorAddr: addrAcc1.String(), SrcValidatorAddr: val1.OperatorAddress, + Pagination: &query.PageRequest{}, + } + }, + true, + false, + }, + { + "query redelegations with sourceValAddr only", + func() { + req = &types.QueryRedelegationsRequest{ + SrcValidatorAddr: val1.GetOperator().String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.Redelegations(gocontext.Background(), req) + if tc.expPass && !tc.expErr { + suite.NoError(err) + suite.Len(res.RedelegationResponses, len(redel.Entries)) + suite.Equal(redel.DelegatorAddress, res.RedelegationResponses[0].Redelegation.DelegatorAddress) + suite.Equal(redel.ValidatorSrcAddress, res.RedelegationResponses[0].Redelegation.ValidatorSrcAddress) + suite.Equal(redel.ValidatorDstAddress, res.RedelegationResponses[0].Redelegation.ValidatorDstAddress) + suite.Len(redel.Entries, len(res.RedelegationResponses[0].Entries)) + } else if !tc.expPass && !tc.expErr { + suite.NoError(err) + suite.Nil(res.RedelegationResponses) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func (suite *KeeperTestSuite) TestGRPCQueryValidatorUnbondingDelegations() { + app, ctx, queryClient, addrs, vals := suite.app, suite.ctx, suite.queryClient, suite.addrs, suite.vals + addrAcc1, _ := addrs[0], addrs[1] + val1 := vals[0] + + // undelegate + undelAmount := app.StakingKeeper.TokensFromConsensusPower(ctx, 2) + _, err := app.StakingKeeper.Undelegate(ctx, addrAcc1, val1.GetOperator(), undelAmount.ToDec()) + suite.NoError(err) + applyValidatorSetUpdates(suite.T(), ctx, app.StakingKeeper, -1) + + var req *types.QueryValidatorUnbondingDelegationsRequest + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryValidatorUnbondingDelegationsRequest{} + }, + false, + }, + { + "valid request", + func() { + req = &types.QueryValidatorUnbondingDelegationsRequest{ + ValidatorAddr: val1.GetOperator().String(), + Pagination: &query.PageRequest{Limit: 1, CountTotal: true}, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + tc.malleate() + res, err := queryClient.ValidatorUnbondingDelegations(gocontext.Background(), req) + if tc.expPass { + suite.NoError(err) + suite.Equal(uint64(1), res.Pagination.Total) + suite.Equal(1, len(res.UnbondingResponses)) + suite.Equal(res.UnbondingResponses[0].ValidatorAddress, val1.OperatorAddress) + } else { + suite.Error(err) + suite.Nil(res) + } + }) + } +} + +func createValidators(t *testing.T, ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress, []types.Validator) { + addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, app.StakingKeeper.TokensFromConsensusPower(ctx, 300)) + valAddrs := simapp.ConvertAddrsToValAddrs(addrs) + pks := simapp.CreateTestPubKeys(5) + cdc := simapp.MakeTestEncodingConfig().Marshaler + app.StakingKeeper = keeper.NewKeeper( + cdc, + app.GetKey(types.StoreKey), + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(types.ModuleName), + ) + + val1 := teststaking.NewValidator(t, valAddrs[0], pks[0]) + val2 := teststaking.NewValidator(t, valAddrs[1], pks[1]) + vals := []types.Validator{val1, val2} + + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + app.StakingKeeper.SetValidatorByConsAddr(ctx, val1) + app.StakingKeeper.SetValidatorByConsAddr(ctx, val2) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1) + app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val2) + + _, err := app.StakingKeeper.Delegate(ctx, addrs[0], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[0]), types.Unbonded, val1, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, addrs[1], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[1]), types.Unbonded, val2, true) + require.NoError(t, err) + _, err = app.StakingKeeper.Delegate(ctx, addrs[0], app.StakingKeeper.TokensFromConsensusPower(ctx, powers[2]), types.Unbonded, val2, true) + require.NoError(t, err) + applyValidatorSetUpdates(t, ctx, app.StakingKeeper, -1) + + return addrs, valAddrs, vals +} diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index 92561bc6e7f3..b64b037d69a8 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -550,54 +550,22 @@ func (s *KeeperTestSuite) TestValidatorQueueMigrationToColls() { s.Require().NoError(err) } +func TestParams(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + func (s *KeeperTestSuite) TestRedelegationQueueMigrationToColls() { s.SetupTest() - addrs, valAddrs := createValAddrs(101) - err := testutil.DiffCollectionsMigration( - s.ctx, - s.key, - 100, - func(i int64) { - date := time.Unix(i, i) - dvvTriplets := stakingtypes.DVVTriplets{ - Triplets: []stakingtypes.DVVTriplet{ - { - DelegatorAddress: s.addressToString(addrs[i]), - ValidatorSrcAddress: s.valAddressToString(valAddrs[i]), - ValidatorDstAddress: s.valAddressToString(valAddrs[i+1]), - }, - }, - } - bz, err := s.cdc.Marshal(&dvvTriplets) - s.Require().NoError(err) - s.ctx.KVStore(s.key).Set(getRedelegationTimeKey(date), bz) - }, - "58722ccde0cacda42aa81d71d7da1123b2c4a8e35d961d55f1507c3f10ffbc96", - ) - s.Require().NoError(err) - - err = testutil.DiffCollectionsMigration( - s.ctx, - s.key, - 100, - func(i int64) { - date := time.Unix(i, i) - dvvTriplets := stakingtypes.DVVTriplets{ - Triplets: []stakingtypes.DVVTriplet{ - { - DelegatorAddress: s.addressToString(addrs[i]), - ValidatorSrcAddress: s.valAddressToString(valAddrs[i]), - ValidatorDstAddress: s.valAddressToString(valAddrs[i+1]), - }, - }, - } - err := s.stakingKeeper.SetRedelegationQueueTimeSlice(s.ctx, date, dvvTriplets.Triplets) - s.Require().NoError(err) - }, - "58722ccde0cacda42aa81d71d7da1123b2c4a8e35d961d55f1507c3f10ffbc96", - ) - s.Require().NoError(err) + // check that the empty keeper loads the default + resParams := app.StakingKeeper.GetParams(ctx) + require.True(t, expParams.Equal(resParams)) + + // modify a params, save, and retrieve + expParams.MaxValidators = 777 + app.StakingKeeper.SetParams(ctx, expParams) + resParams = app.StakingKeeper.GetParams(ctx) + require.True(t, expParams.Equal(resParams)) } func TestKeeperTestSuite(t *testing.T) { diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 06943f835da2..77e0976f1edb 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -240,12 +240,12 @@ func (k Keeper) Unjail(ctx context.Context, consAddr sdk.ConsAddress) error { // the unbonding delegation had enough stake to slash // (the amount actually slashed may be less if there's // insufficient stake remaining) -func (k Keeper) SlashUnbondingDelegation(ctx context.Context, unbondingDelegation types.UnbondingDelegation, - infractionHeight int64, slashFactor math.LegacyDec, -) (totalSlashAmount math.Int, err error) { - now := k.HeaderService.HeaderInfo(ctx).Time - totalSlashAmount = math.ZeroInt() - burnedAmount := math.ZeroInt() +func (k Keeper) SlashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, + infractionHeight int64, slashFactor sdk.Dec, +) (totalSlashAmount sdk.Int) { + now := ctx.BlockHeader().Time + totalSlashAmount = sdk.ZeroInt() + burnedAmount := sdk.ZeroInt() // perform slashing on all entries within the unbonding delegation for i, entry := range unbondingDelegation.Entries { @@ -296,22 +296,12 @@ func (k Keeper) SlashUnbondingDelegation(ctx context.Context, unbondingDelegatio // (the amount actually slashed may be less if there's // insufficient stake remaining) // NOTE this is only slashing for prior infractions from the source validator -func (k Keeper) SlashRedelegation(ctx context.Context, srcValidator types.Validator, redelegation types.Redelegation, - infractionHeight int64, slashFactor math.LegacyDec, -) (totalSlashAmount math.Int, err error) { - now := k.HeaderService.HeaderInfo(ctx).Time - totalSlashAmount = math.ZeroInt() - bondedBurnedAmount, notBondedBurnedAmount := math.ZeroInt(), math.ZeroInt() - - valDstAddr, err := k.validatorAddressCodec.StringToBytes(redelegation.ValidatorDstAddress) - if err != nil { - return math.ZeroInt(), fmt.Errorf("SlashRedelegation: could not parse validator destination address: %w", err) - } - - delegatorAddress, err := k.authKeeper.AddressCodec().StringToBytes(redelegation.DelegatorAddress) - if err != nil { - return math.ZeroInt(), fmt.Errorf("SlashRedelegation: could not parse delegator address: %w", err) - } +func (k Keeper) SlashRedelegation(ctx sdk.Context, srcValidator types.Validator, redelegation types.Redelegation, + infractionHeight int64, slashFactor sdk.Dec, +) (totalSlashAmount sdk.Int) { + now := ctx.BlockHeader().Time + totalSlashAmount = sdk.ZeroInt() + bondedBurnedAmount, notBondedBurnedAmount := sdk.ZeroInt(), sdk.ZeroInt() // perform slashing on all entries within the redelegation for _, entry := range redelegation.Entries { diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index 7ce5cae9822a..6f067caca79f 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -124,15 +124,11 @@ func (k Keeper) SetNewValidatorByPowerIndex(ctx context.Context, validator types return store.Set(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx), k.validatorAddressCodec), str) } -// AddValidatorTokensAndShares updates the tokens of an existing validator, updates the validators power index key -func (k Keeper) AddValidatorTokensAndShares(ctx context.Context, validator types.Validator, - tokensToAdd math.Int, -) (valOut types.Validator, addedShares math.LegacyDec, err error) { - err = k.DeleteValidatorByPowerIndex(ctx, validator) - if err != nil { - return valOut, addedShares, err - } - +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, + tokensToAdd sdk.Int, +) (valOut types.Validator, addedShares sdk.Dec) { + k.DeleteValidatorByPowerIndex(ctx, validator) validator, addedShares = validator.AddTokensFromDel(tokensToAdd) err = k.SetValidator(ctx, validator) if err != nil { @@ -143,14 +139,11 @@ func (k Keeper) AddValidatorTokensAndShares(ctx context.Context, validator types return validator, addedShares, err } -// RemoveValidatorTokensAndShares updates the tokens of an existing validator, updates the validators power index key -func (k Keeper) RemoveValidatorTokensAndShares(ctx context.Context, validator types.Validator, - sharesToRemove math.LegacyDec, -) (valOut types.Validator, removedTokens math.Int, err error) { - err = k.DeleteValidatorByPowerIndex(ctx, validator) - if err != nil { - return valOut, removedTokens, err - } +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) RemoveValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, + sharesToRemove sdk.Dec, +) (valOut types.Validator, removedTokens sdk.Int) { + k.DeleteValidatorByPowerIndex(ctx, validator) validator, removedTokens = validator.RemoveDelShares(sharesToRemove) err = k.SetValidator(ctx, validator) if err != nil { @@ -161,14 +154,11 @@ func (k Keeper) RemoveValidatorTokensAndShares(ctx context.Context, validator ty return validator, removedTokens, err } -// RemoveValidatorTokens updates the tokens of an existing validator, updates the validators power index key -func (k Keeper) RemoveValidatorTokens(ctx context.Context, - validator types.Validator, tokensToRemove math.Int, -) (types.Validator, error) { - if err := k.DeleteValidatorByPowerIndex(ctx, validator); err != nil { - return validator, err - } - +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, + validator types.Validator, tokensToRemove sdk.Int, +) types.Validator { + k.DeleteValidatorByPowerIndex(ctx, validator) validator = validator.RemoveTokens(tokensToRemove) if err := k.SetValidator(ctx, validator); err != nil { return validator, err @@ -183,8 +173,8 @@ func (k Keeper) RemoveValidatorTokens(ctx context.Context, // UpdateValidatorCommission attempts to update a validator's commission rate. // An error is returned if the new commission rate is invalid. -func (k Keeper) UpdateValidatorCommission(ctx context.Context, - validator types.Validator, newRate math.LegacyDec, +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, + validator types.Validator, newRate sdk.Dec, ) (types.Commission, error) { commission := validator.Commission blockTime := k.HeaderService.HeaderInfo(ctx).Time diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 9780823a6e66..fdcd332adb73 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -139,7 +139,7 @@ func (s *KeeperTestSuite) TestValidatorBasics() { require := s.Require() // construct the validators - var validators [3]stakingtypes.Validator + var validators [3]types.Validator powers := []int64{9, 8, 7} for i, power := range powers { validators[i] = testutil.NewValidator(s.T(), sdk.ValAddress(PKs[i].Address().Bytes()), PKs[i]) @@ -238,13 +238,157 @@ func (s *KeeperTestSuite) TestValidatorBasics() { require.ErrorIs(err, stakingtypes.ErrNoValidatorFound) } -func (s *KeeperTestSuite) TestUpdateValidatorByPowerIndex() { - ctx, keeper := s.ctx, s.stakingKeeper - require := s.Require() +// test how the validators are sorted, tests GetBondedValidatorsByPower +func TestGetValidatorSortingUnmixed(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + // initialize some validators into the state + amts := []sdk.Int{ + sdk.NewIntFromUint64(0), + app.StakingKeeper.PowerReduction(ctx).MulRaw(100), + app.StakingKeeper.PowerReduction(ctx), + app.StakingKeeper.PowerReduction(ctx).MulRaw(400), + app.StakingKeeper.PowerReduction(ctx).MulRaw(200), + } + n := len(amts) + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = teststaking.NewValidator(t, sdk.ValAddress(addrs[i]), PKs[i]) + validators[i].Status = types.Bonded + validators[i].Tokens = amt + validators[i].DelegatorShares = sdk.NewDecFromInt(amt) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } - valPubKey := PKs[0] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - valTokens := keeper.TokensFromConsensusPower(ctx, 100) + // first make sure everything made it in to the gotValidator group + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + assert.Equal(t, n, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(100).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[2].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(1).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[3].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(0), resValidators[4].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[1].OperatorAddress, resValidators[2].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[2].OperatorAddress, resValidators[3].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[0].OperatorAddress, resValidators[4].OperatorAddress, "%v", resValidators) + + // test a basic increase in voting power + validators[3].Tokens = sdk.NewInt(500).Mul(app.StakingKeeper.PowerReduction(ctx)) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + + // test a decrease in voting power + validators[3].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // test equal voting power, different age + validators[3].Tokens = sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)) + ctx = ctx.WithBlockHeight(10) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // no change in voting power - no change in sort + ctx = ctx.WithBlockHeight(20) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[4], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) + + // change in voting power of both validators, both still in v-set, no age change + validators[3].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) + validators[4].Tokens = sdk.NewInt(300).Mul(app.StakingKeeper.PowerReduction(ctx)) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[3], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n) + ctx = ctx.WithBlockHeight(30) + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[4], true) + resValidators = app.StakingKeeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, len(resValidators), n, "%v", resValidators) + assert.True(ValEq(t, validators[3], resValidators[0])) + assert.True(ValEq(t, validators[4], resValidators[1])) +} + +func TestGetValidatorSortingMixed(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + bondedPool := app.StakingKeeper.GetBondedPool(ctx) + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + + require.NoError(t, simapp.FundModuleAccount(app.BankKeeper, ctx, bondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 501))))) + require.NoError(t, simapp.FundModuleAccount(app.BankKeeper, ctx, notBondedPool.GetName(), sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), app.StakingKeeper.TokensFromConsensusPower(ctx, 0))))) + + app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) + app.AccountKeeper.SetModuleAccount(ctx, bondedPool) + + // now 2 max resValidators + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + // initialize some validators into the state + amts := []sdk.Int{ + sdk.NewIntFromUint64(0), + app.StakingKeeper.PowerReduction(ctx).MulRaw(100), + app.StakingKeeper.PowerReduction(ctx), + app.StakingKeeper.PowerReduction(ctx).MulRaw(400), + app.StakingKeeper.PowerReduction(ctx).MulRaw(200), + } + + var validators [5]types.Validator + for i, amt := range amts { + validators[i] = teststaking.NewValidator(t, sdk.ValAddress(addrs[i]), PKs[i]) + validators[i].DelegatorShares = sdk.NewDecFromInt(amt) + validators[i].Status = types.Bonded + validators[i].Tokens = amt + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[i], true) + } + + val0, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[0])) + require.True(t, found) + val1, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[1])) + require.True(t, found) + val2, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[2])) + require.True(t, found) + val3, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[3])) + require.True(t, found) + val4, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[4])) + require.True(t, found) + require.Equal(t, types.Bonded, val0.Status) + require.Equal(t, types.Unbonding, val1.Status) + require.Equal(t, types.Unbonding, val2.Status) + require.Equal(t, types.Bonded, val3.Status) + require.Equal(t, types.Bonded, val4.Status) + + // first make sure everything made it in to the gotValidator group + resValidators := app.StakingKeeper.GetBondedValidatorsByPower(ctx) + // The validators returned should match the max validators + assert.Equal(t, 2, len(resValidators)) + assert.Equal(t, sdk.NewInt(400).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[0].BondedTokens(), "%v", resValidators) + assert.Equal(t, sdk.NewInt(200).Mul(app.StakingKeeper.PowerReduction(ctx)), resValidators[1].BondedTokens(), "%v", resValidators) + assert.Equal(t, validators[3].OperatorAddress, resValidators[0].OperatorAddress, "%v", resValidators) + assert.Equal(t, validators[4].OperatorAddress, resValidators[1].OperatorAddress, "%v", resValidators) +} + +// TODO separate out into multiple tests +func TestGetValidatorsEdgeCases(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + // set max validators to 2 + params := app.StakingKeeper.GetParams(ctx) + nMax := uint32(2) + params.MaxValidators = nMax + app.StakingKeeper.SetParams(ctx, params) // add a validator validator := testutil.NewValidator(s.T(), valAddr, PKs[0]) diff --git a/x/staking/types/authz.go b/x/staking/types/authz.go index 55194c0e28a2..eb94f73d3be1 100644 --- a/x/staking/types/authz.go +++ b/x/staking/types/authz.go @@ -136,32 +136,17 @@ func (a StakeAuthorization) Accept(ctx context.Context, msg sdk.Msg) (authz.Acce if a.MaxTokens == nil { return authz.AcceptResponse{ - Accept: true, - Delete: false, - Updated: &StakeAuthorization{ - Validators: a.GetValidators(), - AuthorizationType: a.GetAuthorizationType(), - }, + Accept: true, Delete: false, + Updated: &StakeAuthorization{Validators: a.GetValidators(), AuthorizationType: a.GetAuthorizationType()}, }, nil } - limitLeft, err := a.MaxTokens.SafeSub(amount) - if err != nil { - return authz.AcceptResponse{}, err - } - if limitLeft.IsZero() { return authz.AcceptResponse{Accept: true, Delete: true}, nil } - return authz.AcceptResponse{ - Accept: true, - Delete: false, - Updated: &StakeAuthorization{ - Validators: a.GetValidators(), - AuthorizationType: a.GetAuthorizationType(), - MaxTokens: &limitLeft, - }, + Accept: true, Delete: false, + Updated: &StakeAuthorization{Validators: a.GetValidators(), AuthorizationType: a.GetAuthorizationType(), MaxTokens: &limitLeft}, }, nil } diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 725651490d75..96a9e67183e4 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -51,6 +51,7 @@ func (d Delegation) GetDelegatorAddr() sdk.AccAddress { return delAddr } + func (d Delegation) GetValidatorAddr() sdk.ValAddress { addr, err := sdk.ValAddressFromBech32(d.ValidatorAddress) if err != nil { @@ -350,7 +351,7 @@ func NewRedelegationResponse( // NewRedelegationEntryResponse creates a new RedelegationEntryResponse instance. func NewRedelegationEntryResponse( - creationHeight int64, completionTime time.Time, sharesDst math.LegacyDec, initialBalance, balance math.Int, unbondingID uint64, + creationHeight int64, completionTime time.Time, sharesDst sdk.Dec, initialBalance, balance sdk.Int, ) RedelegationEntryResponse { return RedelegationEntryResponse{ RedelegationEntry: NewRedelegationEntry(creationHeight, completionTime, initialBalance, sharesDst, unbondingID), diff --git a/x/staking/types/hooks.go b/x/staking/types/hooks.go index 6cf0581b6e53..d6d00346cb8a 100644 --- a/x/staking/types/hooks.go +++ b/x/staking/types/hooks.go @@ -28,7 +28,7 @@ func (h MultiStakingHooks) AfterValidatorCreated(ctx context.Context, valAddr sd return nil } -func (h MultiStakingHooks) BeforeValidatorModified(ctx context.Context, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { for i := range h { if err := h[i].BeforeValidatorModified(ctx, valAddr); err != nil { return err @@ -37,7 +37,7 @@ func (h MultiStakingHooks) BeforeValidatorModified(ctx context.Context, valAddr return nil } -func (h MultiStakingHooks) AfterValidatorRemoved(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].AfterValidatorRemoved(ctx, consAddr, valAddr); err != nil { return err @@ -46,7 +46,7 @@ func (h MultiStakingHooks) AfterValidatorRemoved(ctx context.Context, consAddr s return nil } -func (h MultiStakingHooks) AfterValidatorBonded(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].AfterValidatorBonded(ctx, consAddr, valAddr); err != nil { return err @@ -55,7 +55,7 @@ func (h MultiStakingHooks) AfterValidatorBonded(ctx context.Context, consAddr sd return nil } -func (h MultiStakingHooks) AfterValidatorBeginUnbonding(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].AfterValidatorBeginUnbonding(ctx, consAddr, valAddr); err != nil { return err @@ -64,7 +64,7 @@ func (h MultiStakingHooks) AfterValidatorBeginUnbonding(ctx context.Context, con return nil } -func (h MultiStakingHooks) BeforeDelegationCreated(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil { return err @@ -73,7 +73,7 @@ func (h MultiStakingHooks) BeforeDelegationCreated(ctx context.Context, delAddr return nil } -func (h MultiStakingHooks) BeforeDelegationSharesModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].BeforeDelegationSharesModified(ctx, delAddr, valAddr); err != nil { return err @@ -82,7 +82,7 @@ func (h MultiStakingHooks) BeforeDelegationSharesModified(ctx context.Context, d return nil } -func (h MultiStakingHooks) BeforeDelegationRemoved(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { +func (h MultiStakingHooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].BeforeDelegationRemoved(ctx, delAddr, valAddr); err != nil { return err @@ -91,16 +91,7 @@ func (h MultiStakingHooks) BeforeDelegationRemoved(ctx context.Context, delAddr return nil } -func (h MultiStakingHooks) AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - for i := range h { - if err := h[i].AfterDelegationModified(ctx, delAddr, valAddr); err != nil { - return err - } - } - return nil -} - -func (h MultiStakingHooks) BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, fraction sdkmath.LegacyDec) error { +func (h MultiStakingHooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { for i := range h { if err := h[i].BeforeValidatorSlashed(ctx, valAddr, fraction); err != nil { return err @@ -109,16 +100,7 @@ func (h MultiStakingHooks) BeforeValidatorSlashed(ctx context.Context, valAddr s return nil } -func (h MultiStakingHooks) AfterUnbondingInitiated(ctx context.Context, id uint64) error { - for i := range h { - if err := h[i].AfterUnbondingInitiated(ctx, id); err != nil { - return err - } - } - return nil -} - -func (h MultiStakingHooks) AfterConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey cryptotypes.PubKey, rotationFee sdk.Coin) error { +func (h MultiStakingHooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) { for i := range h { if err := h[i].AfterConsensusPubKeyUpdate(ctx, oldPubKey, newPubKey, rotationFee); err != nil { return err diff --git a/x/staking/types/keys_test.go b/x/staking/types/keys_test.go index 9f3978f1057f..2e221993df10 100644 --- a/x/staking/types/keys_test.go +++ b/x/staking/types/keys_test.go @@ -40,8 +40,88 @@ func TestGetValidatorPowerRank(t *testing.T) { {val4, "230000010000000000149c288ede7df62742fc3b7d0962045a8cef0f79f6"}, } for i, tt := range tests { - got := hex.EncodeToString(types.GetValidatorsByPowerIndexKey(tt.validator, sdk.DefaultPowerReduction, address.NewBech32Codec("cosmosvaloper"))) + got := hex.EncodeToString(types.GetValidatorsByPowerIndexKey(tt.validator, sdk.DefaultPowerReduction)) require.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i) } } + +func TestGetREDByValDstIndexKey(t *testing.T) { + tests := []struct { + delAddr sdk.AccAddress + valSrcAddr sdk.ValAddress + valDstAddr sdk.ValAddress + wantHex string + }{ + { + sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr1), + "361463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f08609", + }, + { + sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr2), sdk.ValAddress(keysAddr3), + "36143ab62f0d93849be495e21e3e9013a517038f45bd1463d771218209d8bd03c482f69dfba57310f08609145ef3b5f25c54946d4a89fc0d09d2f126614540f2", + }, + { + sdk.AccAddress(keysAddr2), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr3), + "36143ab62f0d93849be495e21e3e9013a517038f45bd145ef3b5f25c54946d4a89fc0d09d2f126614540f21463d771218209d8bd03c482f69dfba57310f08609", + }, + } + for i, tt := range tests { + got := hex.EncodeToString(types.GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) + + require.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i) + } +} + +func TestGetREDByValSrcIndexKey(t *testing.T) { + tests := []struct { + delAddr sdk.AccAddress + valSrcAddr sdk.ValAddress + valDstAddr sdk.ValAddress + wantHex string + }{ + { + sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr1), + "351463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f08609", + }, + { + sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr2), sdk.ValAddress(keysAddr3), + "35145ef3b5f25c54946d4a89fc0d09d2f126614540f21463d771218209d8bd03c482f69dfba57310f08609143ab62f0d93849be495e21e3e9013a517038f45bd", + }, + { + sdk.AccAddress(keysAddr2), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr3), + "351463d771218209d8bd03c482f69dfba57310f08609145ef3b5f25c54946d4a89fc0d09d2f126614540f2143ab62f0d93849be495e21e3e9013a517038f45bd", + }, + } + for i, tt := range tests { + got := hex.EncodeToString(types.GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) + + require.Equal(t, tt.wantHex, got, "Keys did not match on test case %d", i) + } +} + +func TestGetValidatorQueueKey(t *testing.T) { + ts := time.Now() + height := int64(1024) + + bz := types.GetValidatorQueueKey(ts, height) + rTs, rHeight, err := types.ParseValidatorQueueKey(bz) + require.NoError(t, err) + require.Equal(t, ts.UTC(), rTs.UTC()) + require.Equal(t, rHeight, height) +} + +func TestTestGetValidatorQueueKeyOrder(t *testing.T) { + ts := time.Now().UTC() + height := int64(1000) + + endKey := types.GetValidatorQueueKey(ts, height) + + keyA := types.GetValidatorQueueKey(ts.Add(-10*time.Minute), height-10) + keyB := types.GetValidatorQueueKey(ts.Add(-5*time.Minute), height+50) + keyC := types.GetValidatorQueueKey(ts.Add(10*time.Minute), height+100) + + require.Equal(t, -1, bytes.Compare(keyA, endKey)) // keyA <= endKey + require.Equal(t, -1, bytes.Compare(keyB, endKey)) // keyB <= endKey + require.Equal(t, 1, bytes.Compare(keyC, endKey)) // keyB >= endKey +} diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index c2e442d4c55a..390f528c6a4d 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -476,6 +476,21 @@ func (v Validator) ConsPubKey() (cryptotypes.PubKey, error) { return pk, nil } +// TmConsPublicKey casts Validator.ConsensusPubkey to tmprotocrypto.PubKey. +func (v Validator) TmConsPublicKey() (tmprotocrypto.PublicKey, error) { + pk, err := v.ConsPubKey() + if err != nil { + return tmprotocrypto.PublicKey{}, err + } + + tmPk, err := cryptocodec.ToTmProtoPublicKey(pk) + if err != nil { + return tmprotocrypto.PublicKey{}, err + } + + return tmPk, nil +} + // GetConsAddr extracts Consensus key address func (v Validator) GetConsAddr() ([]byte, error) { pk, ok := v.ConsensusPubkey.GetCachedValue().(cryptotypes.PubKey) diff --git a/x/upgrade/keeper/keeper_test.go b/x/upgrade/keeper/keeper_test.go index fcfc4246b48a..5a2fd9d92a04 100644 --- a/x/upgrade/keeper/keeper_test.go +++ b/x/upgrade/keeper/keeper_test.go @@ -252,33 +252,6 @@ func (s *KeeperTestSuite) TestSetUpgradedClient() { } } -func (s *KeeperTestSuite) TestIsSkipHeight() { - var skipOne int64 = 9 - ok := s.upgradeKeeper.IsSkipHeight(11) - s.Require().False(ok) - skip := map[int64]bool{skipOne: true} - storeService := runtime.NewKVStoreService(s.key) - env := runtime.NewEnvironment(storeService, coretesting.NewNopLogger()) - ctrl := gomock.NewController(s.T()) - upgradeKeeper := keeper.NewKeeper(env, skip, s.encCfg.Codec, s.T().TempDir(), s.baseApp, s.encodedAuthority, upgradetestutil.NewMockConsensusKeeper(ctrl)) - s.Require().True(upgradeKeeper.IsSkipHeight(9)) - s.Require().False(upgradeKeeper.IsSkipHeight(10)) -} - -func (s *KeeperTestSuite) TestUpgradedConsensusState() { - cs := []byte("IBC consensus state") - s.Require().NoError(s.upgradeKeeper.SetUpgradedConsensusState(s.ctx, 10, cs)) - bz, err := s.upgradeKeeper.GetUpgradedConsensusState(s.ctx, 10) - s.Require().Equal(cs, bz) - s.Require().NoError(err) -} - -func (s *KeeperTestSuite) TestDowngradeVerified() { - s.upgradeKeeper.SetDowngradeVerified(true) - ok := s.upgradeKeeper.DowngradeVerified() - s.Require().True(ok) -} - // Test that the protocol version successfully increments after an // upgrade and is successfully set on BaseApp's appVersion. func (s *KeeperTestSuite) TestIncrementProtocolVersion() { diff --git a/x/upgrade/types/storeloader_test.go b/x/upgrade/types/storeloader_test.go index 45e0b81df9fc..2425fdd17449 100644 --- a/x/upgrade/types/storeloader_test.go +++ b/x/upgrade/types/storeloader_test.go @@ -70,7 +70,7 @@ func TestSetLoader(t *testing.T) { data, err := json.Marshal(upgradeInfo) require.NoError(t, err) - err = os.WriteFile(upgradeInfoFilePath, data, 0o600) + err = ioutil.WriteFile(upgradeInfoFilePath, data, 0o644) require.NoError(t, err) // make sure it exists before running everything