diff --git a/.golangci.yml b/.golangci.yml index 34738ccf7..a79f7d7e4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -56,6 +56,11 @@ issues: - text: "ST1016:" linters: - stylecheck + - path: "legacy" + text: "SA1019:" + linters: + - staticcheck + max-issues-per-linter: 10000 max-same-issues: 10000 diff --git a/CHANGELOG.md b/CHANGELOG.md index f84fbd1bc..17c70cb71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,8 +48,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#8363](https://github.com/cosmos/cosmos-sdk/pull/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address. * [\#8346](https://github.com/cosmos/cosmos-sdk/pull/8346) All CLI `tx` commands generate ServiceMsgs by default. Graceful Amino support has been added to ServiceMsgs to support signing legacy Msgs. * (crypto/ed25519) [\#8690] Adopt zip1215 ed2559 verification rules. -* [\#8849](https://github.com/cosmos/cosmos-sdk/pull/8849) Upgrade module no longer supports time based upgrades. +* [\#8849](https://github.com/cosmos/cosmos-sdk/pull/8849) Upgrade module no longer supports time based upgrades. * [\#8880](https://github.com/cosmos/cosmos-sdk/pull/8880) The CLI `simd migrate v0.40 ...` command has been renamed to `simd migrate v0.42`. +* [\#7477](https://github.com/cosmos/cosmos-sdk/pull/7477) Changed Bech32 Public Key serialization in the client facing functionality (CLI, MsgServer, QueryServer): + * updated the keyring display structure (it uses protobuf JSON serialization) - the output is more verbose. + * Renamed `MarshalAny` and `UnmarshalAny` to `MarshalInterface` and `UnmarshalInterface` respectively. These functions must take an interface as parameter (not a concrete type nor `Any` object). Underneath they use `Any` wrapping for correct protobuf serialization. + * CLI: removed `--text` flag from `show-node-id` command; the text format for public keys is not used any more - instead we use ProtoJSON. ### API Breaking Changes @@ -65,6 +69,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/upgrade) [\#8743](https://github.com/cosmos/cosmos-sdk/pull/8743) `UpgradeHandler` includes a new argument `VersionMap` which helps facilitate in-place migrations. * (x/auth) [\#8129](https://github.com/cosmos/cosmos-sdk/pull/8828) Updated `SigVerifiableTx.GetPubKeys` method signature to return error. * [\#8682](https://github.com/cosmos/cosmos-sdk/pull/8682) `ante.NewAnteHandler` updated to receive all positional params as `ante.HandlerOptions` struct. If required fields aren't set, throws error accordingly. +* (x/staking/types) [\#7447](https://github.com/cosmos/cosmos-sdk/issues/7447) Remove bech32 PubKey support: + * `ValidatorI` interface update: `GetConsPubKey` renamed to `TmConsPubKey` (this is to clarify the return type: consensus public key must be a tendermint key); `TmConsPubKey`, `GetConsAddr` methods return error. + * `Validator` updated according to the `ValidatorI` changes described above. + * `ToTmValidator` function: added `error` to return values. + * `Validator.ConsensusPubkey` type changed from `string` to `codectypes.Any`. + * `MsgCreateValidator.Pubkey` type changed from `string` to `codectypes.Any`. * (client) [\#8926](https://github.com/cosmos/cosmos-sdk/pull/8926) `client/tx.PrepareFactory` has been converted to a private function, as it's only used internally. * (auth/tx) [\#8926](https://github.com/cosmos/cosmos-sdk/pull/8926) The `ProtoTxProvider` interface used as a workaround for transaction simulation has been removed. @@ -79,7 +89,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements -* (x/staking) [\#8909](https://github.com/cosmos/cosmos-sdk/pull/8909) Require self delegation in `MsgCreateValidator` to be at least one consensus power. +* (x/staking) [\#8909](https://github.com/cosmos/cosmos-sdk/pull/8909) Require self delegation in `MsgCreateValidator` to be at least one consensus power. * (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata * (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts * (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method. @@ -189,6 +199,7 @@ he Cosmos Hub) should not use this release or any release in the v0.41.x series. * (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON support for IBC MsgTransfer in order to support Ledger text signing transfer transactions. * (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks. + ### Bug Fixes * (simapp) [\#8418](https://github.com/cosmos/cosmos-sdk/pull/8418) Add balance coin to supply when adding a new genesis account diff --git a/client/debug/main.go b/client/debug/main.go index 54b75e712..8a3fbe910 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -1,7 +1,6 @@ package debug import ( - "encoding/base64" "encoding/hex" "fmt" "strconv" @@ -10,13 +9,12 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/version" ) +// Cmd creates a main CLI command func Cmd() *cobra.Command { cmd := &cobra.Command{ Use: "debug", @@ -31,90 +29,31 @@ func Cmd() *cobra.Command { return cmd } -// getPubKeyFromString returns a Tendermint PubKey (PubKeyEd25519) by attempting -// to decode the pubkey string from hex, base64, and finally bech32. If all -// encodings fail, an error is returned. -func getPubKeyFromString(pkstr string) (cryptotypes.PubKey, error) { - bz, err := hex.DecodeString(pkstr) - if err == nil { - if len(bz) == ed25519.PubKeySize { - return &ed25519.PubKey{Key: bz}, nil - } - } - - bz, err = base64.StdEncoding.DecodeString(pkstr) - if err == nil { - if len(bz) == ed25519.PubKeySize { - return &ed25519.PubKey{Key: bz}, nil - } - } - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pkstr) - if err == nil { - return pk, nil - } - - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeValPub, pkstr) - if err == nil { - return pk, nil - } - - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkstr) - if err == nil { - return pk, nil - } - - return nil, fmt.Errorf("pubkey '%s' invalid; expected hex, base64, or bech32 of correct size", pkstr) +// getPubKeyFromString decodes SDK PubKey using JSON marshaler. +func getPubKeyFromString(ctx client.Context, pkstr string) (cryptotypes.PubKey, error) { + var pk cryptotypes.PubKey + err := ctx.JSONMarshaler.UnmarshalInterfaceJSON([]byte(pkstr), &pk) + return pk, err } func PubkeyCmd() *cobra.Command { return &cobra.Command{ Use: "pubkey [pubkey]", - Short: "Decode a ED25519 pubkey from hex, base64, or bech32", - Long: fmt.Sprintf(`Decode a pubkey from hex, base64, or bech32. + Short: "Decode a pubkey from proto JSON", + Long: fmt.Sprintf(`Decode a pubkey from proto JSON and display it's address. Example: -$ %s debug pubkey TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz -$ %s debug pubkey cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg - `, version.AppName, version.AppName), +$ %s debug pubkey '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}' + `, version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - - pk, err := getPubKeyFromString(args[0]) + pk, err := getPubKeyFromString(clientCtx, args[0]) if err != nil { return err } - - edPK, ok := pk.(*ed25519.PubKey) - if !ok { - return errors.Wrapf(errors.ErrInvalidType, "invalid pubkey type; expected ED25519") - } - - pubKeyJSONBytes, err := clientCtx.LegacyAmino.MarshalJSON(edPK) - if err != nil { - return err - } - accPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, edPK) - if err != nil { - return err - } - valPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, edPK) - if err != nil { - return err - } - consenusPub, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, edPK) - if err != nil { - return err - } - - cmd.Println("Address:", edPK.Address()) - cmd.Printf("Hex: %X\n", edPK.Key) - cmd.Println("JSON (base64):", string(pubKeyJSONBytes)) - cmd.Println("Bech32 Acc:", accPub) - cmd.Println("Bech32 Validator Operator:", valPub) - cmd.Println("Bech32 Validator Consensus:", consenusPub) - + cmd.Println("Address:", pk.Address()) + cmd.Println("PubKey Hex:", hex.EncodeToString(pk.Bytes())) return nil }, } @@ -125,7 +64,7 @@ func AddrCmd() *cobra.Command { Use: "addr [address]", Short: "Convert an address between hex and bech32", Long: fmt.Sprintf(`Convert an address between hex encoding and bech32. - + Example: $ %s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg `, version.AppName), @@ -152,13 +91,10 @@ $ %s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg } } - accAddr := sdk.AccAddress(addr) - valAddr := sdk.ValAddress(addr) - cmd.Println("Address:", addr) cmd.Printf("Address (hex): %X\n", addr) - cmd.Printf("Bech32 Acc: %s\n", accAddr) - cmd.Printf("Bech32 Val: %s\n", valAddr) + cmd.Printf("Bech32 Acc: %s\n", sdk.AccAddress(addr)) + cmd.Printf("Bech32 Val: %s\n", sdk.ValAddress(addr)) return nil }, } @@ -169,7 +105,7 @@ func RawBytesCmd() *cobra.Command { Use: "raw-bytes [raw-bytes]", Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex", Long: fmt.Sprintf(`Convert raw-bytes to hex. - + Example: $ %s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100] `, version.AppName), diff --git a/client/grpc/tmservice/service.go b/client/grpc/tmservice/service.go index 57668c0d7..a86f16c26 100644 --- a/client/grpc/tmservice/service.go +++ b/client/grpc/tmservice/service.go @@ -95,33 +95,7 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestVa if err != nil { return nil, err } - - validatorsRes, err := rpc.GetValidators(ctx, s.clientCtx, nil, &page, &limit) - if err != nil { - return nil, err - } - - outputValidatorsRes := &GetLatestValidatorSetResponse{ - BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*Validator, len(validatorsRes.Validators)), - Pagination: &qtypes.PageResponse{ - Total: validatorsRes.Total, - }, - } - - for i, validator := range validatorsRes.Validators { - anyPub, err := codectypes.NewAnyWithValue(validator.PubKey) - if err != nil { - return nil, err - } - outputValidatorsRes.Validators[i] = &Validator{ - Address: validator.Address.String(), - ProposerPriority: validator.ProposerPriority, - PubKey: anyPub, - VotingPower: validator.VotingPower, - } - } - return outputValidatorsRes, nil + return validatorsOutput(ctx, s.clientCtx, nil, page, limit) } func (m *GetLatestValidatorSetResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { @@ -149,32 +123,42 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValida if req.Height > chainHeight { return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length") } - - validatorsRes, err := rpc.GetValidators(ctx, s.clientCtx, &req.Height, &page, &limit) - + r, err := validatorsOutput(ctx, s.clientCtx, &req.Height, page, limit) if err != nil { return nil, err } + return &GetValidatorSetByHeightResponse{ + BlockHeight: r.BlockHeight, + Validators: r.Validators, + Pagination: r.Pagination, + }, nil +} - outputValidatorsRes := &GetValidatorSetByHeightResponse{ - BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*Validator, len(validatorsRes.Validators)), - Pagination: &qtypes.PageResponse{Total: validatorsRes.Total}, +func validatorsOutput(ctx context.Context, cctx client.Context, height *int64, page, limit int) (*GetLatestValidatorSetResponse, error) { + vs, err := rpc.GetValidators(ctx, cctx, height, &page, &limit) + if err != nil { + return nil, err } - - for i, validator := range validatorsRes.Validators { - anyPub, err := codectypes.NewAnyWithValue(validator.PubKey) + resp := GetLatestValidatorSetResponse{ + BlockHeight: vs.BlockHeight, + Validators: make([]*Validator, len(vs.Validators)), + Pagination: &qtypes.PageResponse{ + Total: vs.Total, + }, + } + for i, v := range vs.Validators { + anyPub, err := codectypes.NewAnyWithValue(v.PubKey) if err != nil { return nil, err } - outputValidatorsRes.Validators[i] = &Validator{ - Address: validator.Address.String(), - ProposerPriority: validator.ProposerPriority, + resp.Validators[i] = &Validator{ + Address: v.Address.String(), + ProposerPriority: v.ProposerPriority, PubKey: anyPub, - VotingPower: validator.VotingPower, + VotingPower: v.VotingPower, } } - return outputValidatorsRes, nil + return &resp, nil } // GetNodeInfo implements ServiceServer.GetNodeInfo diff --git a/client/keys/add.go b/client/keys/add.go index e0344decd..4176da632 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -40,7 +40,7 @@ const ( func AddKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "add ", - Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk", + Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to file", Long: `Derive a new private key and encrypt to disk. Optionally specify a BIP39 mnemonic, a BIP39 passphrase to further secure the mnemonic, and a bip32 HD path to derive a specific account. The key will be stored under the given name @@ -53,29 +53,31 @@ local keystore. Use the --pubkey flag to add arbitrary public keys to the keystore for constructing multisig transactions. -You can add a multisig key by passing the list of key names you want the public -key to be composed of to the --multisig flag and the minimum number of signatures -required through --multisig-threshold. The keys are sorted by address, unless -the flag --nosort is set. +You can create and store a multisig key by passing the list of key names stored in a keyring +and the minimum number of signatures required through --multisig-threshold. The keys are +sorted by address, unless the flag --nosort is set. +Example: + + keys add mymultisig --multisig "keyname1,keyname2,keyname3" --multisig-threshold 2 `, Args: cobra.ExactArgs(1), - RunE: runAddCmd, + RunE: runAddCmdPrepare, } - - cmd.Flags().StringSlice(flagMultisig, nil, "Construct and store a multisig public key (implies --pubkey)") - cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") - cmd.Flags().Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied") - cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk") - cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") - cmd.Flags().Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") - cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") - cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") - cmd.Flags().Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") - cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") - cmd.Flags().Uint32(flagCoinType, sdk.GetConfig().GetCoinType(), "coin type number for HD derivation") - cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") - cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation") - cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") + f := cmd.Flags() + f.StringSlice(flagMultisig, nil, "List of key names stored in keyring to construct a public legacy multisig key") + f.Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") + f.Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied") + f.String(FlagPublicKey, "", "Parse a public key in JSON format and saves key info to file.") + f.BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") + f.Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") + f.Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") + f.Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") + f.Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore") + f.String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)") + f.Uint32(flagCoinType, sdk.GetConfig().GetCoinType(), "coin type number for HD derivation") + f.Uint32(flagAccount, 0, "Account number for HD derivation") + f.Uint32(flagIndex, 0, "Address index number for HD derivation") + f.String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") cmd.SetOut(cmd.OutOrStdout()) cmd.SetErr(cmd.ErrOrStderr()) @@ -83,14 +85,14 @@ the flag --nosort is set. return cmd } -func runAddCmd(cmd *cobra.Command, args []string) error { +func runAddCmdPrepare(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - return RunAddCmd(cmd, args, clientCtx.Keyring, buf) + return RunAddCmd(clientCtx, cmd, args, buf) } /* @@ -102,13 +104,15 @@ input output - armor encrypted private key (saved to file) */ -func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *bufio.Reader) error { +func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error { + // func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *bufio.Reader) error { var err error name := args[0] interactive, _ := cmd.Flags().GetBool(flagInteractive) noBackup, _ := cmd.Flags().GetBool(flagNoBackup) showMnemonic := !noBackup + kb := ctx.Keyring keyringAlgos, _ := kb.SupportedAlgorithms() algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm) @@ -139,7 +143,6 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf multisigKeys, _ := cmd.Flags().GetStringSlice(flagMultisig) if len(multisigKeys) != 0 { var pks []cryptotypes.PubKey - multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold) if err := validateMultisigThreshold(multisigThreshold, len(multisigKeys)); err != nil { return err @@ -172,16 +175,13 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf pubKey, _ := cmd.Flags().GetString(FlagPublicKey) if pubKey != "" { - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pubKey) + var pk cryptotypes.PubKey + err = ctx.JSONMarshaler.UnmarshalInterfaceJSON([]byte(pubKey), &pk) if err != nil { return err } - - if _, err := kb.SavePubKey(name, pk, algo.Name()); err != nil { - return err - } - - return nil + _, err := kb.SavePubKey(name, pk, algo.Name()) + return err } coinType, _ := cmd.Flags().GetUint32(flagCoinType) @@ -284,11 +284,10 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic string) error { output, _ := cmd.Flags().GetString(cli.OutputFlag) - switch output { case OutputFormatText: cmd.PrintErrln() - printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput, output) + printKeyInfo(cmd.OutOrStdout(), info, keyring.MkAccKeyOutput, output) // print mnemonic unless requested not to. if showMnemonic { @@ -298,7 +297,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo fmt.Fprintln(cmd.ErrOrStderr(), mnemonic) } case OutputFormatJSON: - out, err := keyring.Bech32KeyOutput(info) + out, err := keyring.MkAccKeyOutput(info) if err != nil { return err } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 5e32f755f..a5fcc304d 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" @@ -74,8 +73,8 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { require.Equal(t, "keyname1", key1.GetName()) require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, - "terrapub1addwnpepqvpg7r26nl2pvqqern00m6s9uaax3hauu2rzg8qpjzq9hy6xve7sw0d84m6", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) + "PubKeySecp256k1{03028F0D5A9FD41600191CDEFDEA05E77A68DFBCE286241C0190805B9346667D07}", + key1.GetPubKey().String()) config.SetPurpose(44) config.SetCoinType(118) @@ -122,6 +121,6 @@ func Test_runAddCmdLedger(t *testing.T) { require.Equal(t, "keyname1", key1.GetName()) require.Equal(t, keyring.TypeLedger, key1.GetType()) require.Equal(t, - "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey())) + "PubKeySecp256k1{034FEF9CD7C4C63588D3B03FEB5281B9D232CBA34D6F3D71AEE59211FFBFE1FE87}", + key1.GetPubKey().String()) } diff --git a/client/keys/codec.go b/client/keys/codec.go index 2fb7bd943..3b1f6fc38 100644 --- a/client/keys/codec.go +++ b/client/keys/codec.go @@ -5,6 +5,8 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ) +// TODO: remove this file https://github.com/cosmos/cosmos-sdk/issues/8047 + // KeysCdc defines codec to be used with key operations var KeysCdc *codec.LegacyAmino diff --git a/client/keys/codec_test.go b/client/keys/codec_test.go index 33f6103d1..f61792e60 100644 --- a/client/keys/codec_test.go +++ b/client/keys/codec_test.go @@ -20,10 +20,10 @@ func getTestCases() testCases { return testCases{ // nolint:govet []keyring.KeyOutput{ - {"A", "B", "C", "D", "E", 0, nil}, - {"A", "B", "C", "D", "", 0, nil}, - {"", "B", "C", "D", "", 0, nil}, - {"", "", "", "", "", 0, nil}, + {"A", "B", "C", "D", "E"}, + {"A", "B", "C", "D", ""}, + {"", "B", "C", "D", ""}, + {"", "", "", "", ""}, }, make([]keyring.KeyOutput, 4), [][]byte{ diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 76f8c211f..d5f8c1df3 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -49,7 +49,7 @@ func Test_runDeleteCmd(t *testing.T) { err = cmd.ExecuteContext(ctx) require.Error(t, err) - require.Equal(t, "The specified item could not be found in the keyring", err.Error()) + require.EqualError(t, err, "blah.info: key not found") // User confirmation missing cmd.SetArgs([]string{ diff --git a/client/keys/show.go b/client/keys/show.go index b72585d9d..8c19f8797 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/ledger" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerr "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -41,12 +42,12 @@ consisting of all the keys provided by name and multisig threshold.`, Args: cobra.MinimumNArgs(1), RunE: runShowCmd, } - - cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)") - cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)") - cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)") - cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device") - cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures") + f := cmd.Flags() + f.String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)") + f.BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)") + f.BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)") + f.BoolP(FlagDevice, "d", false, "Output the address in a ledger device") + f.Int(flagMultiSigThreshold, 1, "K out of N required signatures") return cmd } @@ -81,7 +82,10 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } multikey := multisig.NewLegacyAminoPubKey(multisigThreshold, pks) - info = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) + info, err = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) + if err != nil { + return err + } } isShowAddr, _ := cmd.Flags().GetBool(FlagAddress) @@ -111,10 +115,16 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { output, _ := cmd.Flags().GetString(cli.OutputFlag) switch { - case isShowAddr: - printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut) - case isShowPubKey: - printPubKey(cmd.OutOrStdout(), info, bechKeyOut) + case isShowAddr, isShowPubKey: + ko, err := bechKeyOut(info) + if err != nil { + return err + } + out := ko.Address + if isShowPubKey { + out = ko.PubKey + } + fmt.Fprintln(cmd.OutOrStdout(), out) default: printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut, output) } @@ -144,19 +154,20 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { } func fetchKey(kb keyring.Keyring, keyref string) (keyring.Info, error) { + // firstly check if the keyref is a key name of a key registered in a keyring. info, err := kb.Key(keyref) - if err != nil { - accAddr, err := sdk.AccAddressFromBech32(keyref) - if err != nil { - return info, err - } - - info, err = kb.KeyByAddress(accAddr) - if err != nil { - return info, errors.New("key not found") - } + // if the key is not there or if we have a problem with a keyring itself then we move to a + // fallback: searching for key by address. + if err == nil || !sdkerr.IsOf(err, sdkerr.ErrIO, sdkerr.ErrKeyNotFound) { + return info, err } - return info, nil + accAddr, err := sdk.AccAddressFromBech32(keyref) + if err != nil { + return info, err + } + + info, err = kb.KeyByAddress(accAddr) + return info, sdkerr.Wrap(err, "Invalid key") } func validateMultisigThreshold(k, nKeys int) error { @@ -173,11 +184,11 @@ func validateMultisigThreshold(k, nKeys int) error { func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { switch bechPrefix { case sdk.PrefixAccount: - return keyring.Bech32KeyOutput, nil + return keyring.MkAccKeyOutput, nil case sdk.PrefixValidator: - return keyring.Bech32ValKeyOutput, nil + return keyring.MkValKeyOutput, nil case sdk.PrefixConsensus: - return keyring.Bech32ConsKeyOutput, nil + return keyring.MkConsKeyOutput, nil } return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix) diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 882a80683..9405a6f84 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -24,8 +24,8 @@ func Test_multiSigKey_Properties(t *testing.T) { 1, []cryptotypes.PubKey{tmpKey1.PubKey()}, ) - tmp := keyring.NewMultiInfo("myMultisig", pk) - + tmp, err := keyring.NewMultiInfo("myMultisig", pk) + require.NoError(t, err) require.Equal(t, "myMultisig", tmp.GetName()) require.Equal(t, keyring.TypeMulti, tmp.GetType()) require.Equal(t, "D3923267FA8A3DD367BB768FA8BDC8FF7F89DA3F", tmp.GetPubKey().Address().String()) @@ -194,28 +194,20 @@ func Test_getBechKeyOut(t *testing.T) { }{ {"empty", args{""}, nil, true}, {"wrong", args{"???"}, nil, true}, - {"acc", args{sdk.PrefixAccount}, keyring.Bech32KeyOutput, false}, - {"val", args{sdk.PrefixValidator}, keyring.Bech32ValKeyOutput, false}, - {"cons", args{sdk.PrefixConsensus}, keyring.Bech32ConsKeyOutput, false}, + {"acc", args{sdk.PrefixAccount}, keyring.MkAccKeyOutput, false}, + {"val", args{sdk.PrefixValidator}, keyring.MkValKeyOutput, false}, + {"cons", args{sdk.PrefixConsensus}, keyring.MkConsKeyOutput, false}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { got, err := getBechKeyOut(tt.args.bechPrefix) - if (err != nil) != tt.wantErr { - t.Errorf("getBechKeyOut() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if !tt.wantErr { + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) require.NotNil(t, got) } - - // TODO: Still not possible to compare functions - // Maybe in next release: https://github.com/stretchr/testify/issues/182 - //if &got != &tt.want { - // t.Errorf("getBechKeyOut() = %v, want %v", got, tt.want) - //} }) } } diff --git a/client/keys/utils.go b/client/keys/utils.go index 7490914d1..5e1daf1c4 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -52,7 +52,7 @@ func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOut } func printInfos(w io.Writer, infos []cryptokeyring.Info, output string) { - kos, err := cryptokeyring.Bech32KeysOutput(infos) + kos, err := cryptokeyring.MkAccKeysOutput(infos) if err != nil { panic(err) } @@ -78,21 +78,3 @@ func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) { } fmt.Fprintln(w, string(out)) } - -func printKeyAddress(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { - ko, err := bechKeyOut(info) - if err != nil { - panic(err) - } - - fmt.Fprintln(w, ko.Address) -} - -func printPubKey(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) { - ko, err := bechKeyOut(info) - if err != nil { - panic(err) - } - - fmt.Fprintln(w, ko.PubKey) -} diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 7fb9cf957..a6716df03 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -9,7 +9,6 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client" @@ -67,7 +66,7 @@ func ValidatorCommand() *cobra.Command { return cmd } -// Validator output in bech32 format +// Validator output type ValidatorOutput struct { Address sdk.ConsAddress `json:"address"` PubKey cryptotypes.PubKey `json:"pub_key"` @@ -135,21 +134,19 @@ func GetValidators(ctx context.Context, clientCtx client.Context, height *int64, if validatorsRes.Total < 0 { total = 0 } - - outputValidatorsRes := ResultValidatorsOutput{ + out := ResultValidatorsOutput{ BlockHeight: validatorsRes.BlockHeight, Validators: make([]ValidatorOutput, len(validatorsRes.Validators)), Total: uint64(total), } - for i := 0; i < len(validatorsRes.Validators); i++ { - outputValidatorsRes.Validators[i], err = validatorOutput(validatorsRes.Validators[i]) + out.Validators[i], err = validatorOutput(validatorsRes.Validators[i]) if err != nil { - return ResultValidatorsOutput{}, err + return out, err } } - return outputValidatorsRes, nil + return out, nil } // REST diff --git a/client/tx/factory.go b/client/tx/factory.go index b10d728d6..8510b39c0 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -38,7 +38,7 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) Factory { case flags.SignModeDirect: signMode = signing.SignMode_SIGN_MODE_DIRECT case flags.SignModeLegacyAminoJSON: - signMode = signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON + signMode = signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON //nolint:staticcheck } accNum, _ := flagSet.GetUint64(flags.FlagAccountNumber) diff --git a/codec/any_test.go b/codec/any_test.go index 16e1b7b77..ff80d8ee4 100644 --- a/codec/any_test.go +++ b/codec/any_test.go @@ -7,6 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/testdata" ) @@ -53,3 +57,80 @@ func TestMarshalAny(t *testing.T) { err = cdc.UnmarshalInterface(bz, nil) require.Error(t, err) } + +func TestMarshalProtoPubKey(t *testing.T) { + require := require.New(t) + ccfg := simapp.MakeTestEncodingConfig() + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + // **** test JSON serialization **** + + pkAny, err := codectypes.NewAnyWithValue(pk) + require.NoError(err) + bz, err := ccfg.Marshaler.MarshalJSON(pkAny) + require.NoError(err) + + var pkAny2 codectypes.Any + err = ccfg.Marshaler.UnmarshalJSON(bz, &pkAny2) + require.NoError(err) + // Before getting a cached value we need to unpack it. + // Normally this happens in types which implement UnpackInterfaces + var pkI cryptotypes.PubKey + err = ccfg.InterfaceRegistry.UnpackAny(&pkAny2, &pkI) + require.NoError(err) + var pk2 = pkAny2.GetCachedValue().(cryptotypes.PubKey) + require.True(pk2.Equals(pk)) + + // **** test binary serialization **** + + bz, err = ccfg.Marshaler.MarshalBinaryBare(pkAny) + require.NoError(err) + + var pkAny3 codectypes.Any + err = ccfg.Marshaler.UnmarshalBinaryBare(bz, &pkAny3) + require.NoError(err) + err = ccfg.InterfaceRegistry.UnpackAny(&pkAny3, &pkI) + require.NoError(err) + var pk3 = pkAny3.GetCachedValue().(cryptotypes.PubKey) + require.True(pk3.Equals(pk)) +} + +// TestMarshalProtoInterfacePubKey tests PubKey marshaling using (Un)marshalInterface +// helper functions +func TestMarshalProtoInterfacePubKey(t *testing.T) { + require := require.New(t) + ccfg := simapp.MakeTestEncodingConfig() + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + // **** test JSON serialization **** + + bz, err := ccfg.Marshaler.MarshalInterfaceJSON(pk) + require.NoError(err) + + var pk3 cryptotypes.PubKey + err = ccfg.Marshaler.UnmarshalInterfaceJSON(bz, &pk3) + require.NoError(err) + require.True(pk3.Equals(pk)) + + // ** Check unmarshal using JSONMarshaler ** + // Unpacking won't work straightforward s Any type + // Any can't implement UnpackInterfacesMessage interface. So Any is not + // automatically unpacked and we won't get a value. + var pkAny codectypes.Any + err = ccfg.Marshaler.UnmarshalJSON(bz, &pkAny) + require.NoError(err) + ifc := pkAny.GetCachedValue() + require.Nil(ifc) + + // **** test binary serialization **** + + bz, err = ccfg.Marshaler.MarshalInterface(pk) + require.NoError(err) + + var pk2 cryptotypes.PubKey + err = ccfg.Marshaler.UnmarshalInterface(bz, &pk2) + require.NoError(err) + require.True(pk2.Equals(pk)) +} diff --git a/codec/json.go b/codec/json.go index db77365e0..e01caa259 100644 --- a/codec/json.go +++ b/codec/json.go @@ -3,25 +3,29 @@ package codec import ( "bytes" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" + + "github.com/cosmos/cosmos-sdk/codec/types" ) +var defaultJM = &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: nil} + // ProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded // bytes of a message. func ProtoMarshalJSON(msg proto.Message, resolver jsonpb.AnyResolver) ([]byte, error) { // We use the OrigName because camel casing fields just doesn't make sense. // EmitDefaults is also often the more expected behavior for CLI users - jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: resolver} + jm := defaultJM + if resolver != nil { + jm = &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: resolver} + } err := types.UnpackInterfaces(msg, types.ProtoJSONPacker{JSONPBMarshaler: jm}) if err != nil { return nil, err } buf := new(bytes.Buffer) - if err := jm.Marshal(buf, msg); err != nil { return nil, err } diff --git a/codec/proto_codec.go b/codec/proto_codec.go index 38f60ba3a..7afc99c69 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -34,11 +34,15 @@ func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec { } // MarshalBinaryBare implements BinaryMarshaler.MarshalBinaryBare method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterface func (pc *ProtoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { return o.Marshal() } // MustMarshalBinaryBare implements BinaryMarshaler.MustMarshalBinaryBare method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterface func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { bz, err := pc.MarshalBinaryBare(o) if err != nil { @@ -71,6 +75,8 @@ func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { } // UnmarshalBinaryBare implements BinaryMarshaler.UnmarshalBinaryBare method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterface func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { err := ptr.Unmarshal(bz) if err != nil { @@ -84,6 +90,8 @@ func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { } // MustUnmarshalBinaryBare implements BinaryMarshaler.MustUnmarshalBinaryBare method. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterface func (pc *ProtoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { if err := pc.UnmarshalBinaryBare(bz, ptr); err != nil { panic(err) @@ -116,6 +124,8 @@ func (pc *ProtoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMars // MarshalJSON implements JSONMarshaler.MarshalJSON method, // it marshals to JSON using proto codec. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterfaceJSON func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) { m, ok := o.(ProtoMarshaler) if !ok { @@ -127,6 +137,8 @@ func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) { // MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method, // it executes MarshalJSON except it panics upon failure. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.MarshalInterfaceJSON func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte { bz, err := pc.MarshalJSON(o) if err != nil { @@ -138,6 +150,8 @@ func (pc *ProtoCodec) MustMarshalJSON(o proto.Message) []byte { // UnmarshalJSON implements JSONMarshaler.UnmarshalJSON method, // it unmarshals from JSON using proto codec. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { m, ok := ptr.(ProtoMarshaler) if !ok { @@ -155,6 +169,8 @@ func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { // MustUnmarshalJSON implements JSONMarshaler.MustUnmarshalJSON method, // it executes UnmarshalJSON except it panics upon failure. +// NOTE: this function must be used with a concrete type which +// implements proto.Message. For interface please use the codec.UnmarshalInterfaceJSON func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { if err := pc.UnmarshalJSON(bz, ptr); err != nil { panic(err) @@ -229,6 +245,7 @@ func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error { return pc.interfaceRegistry.UnpackAny(any, iface) } +// InterfaceRegistry returns InterfaceRegistry func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry { return pc.interfaceRegistry } diff --git a/codec/types/compat.go b/codec/types/compat.go index 5cd372dc7..1de782849 100644 --- a/codec/types/compat.go +++ b/codec/types/compat.go @@ -37,7 +37,7 @@ func anyCompatError(errType string, x interface{}) error { func (any Any) MarshalAmino() ([]byte, error) { ac := any.compat if ac == nil { - return nil, anyCompatError("amino binary unmarshal", any) + return nil, anyCompatError("amino binary marshal", any) } return ac.aminoBz, ac.err } diff --git a/crypto/keyring/info.go b/crypto/keyring/info.go index 24024599b..aa205eec0 100644 --- a/crypto/keyring/info.go +++ b/crypto/keyring/info.go @@ -177,6 +177,10 @@ func (i offlineInfo) GetPath() (*hd.BIP44Params, error) { return nil, fmt.Errorf("BIP44 Paths are not available for this type") } +// Deprecated: this structure is not used anymore and it's here only to allow +// decoding old multiInfo records from keyring. +// The problem with legacy.Cdc.UnmarshalBinaryLengthPrefixed - the legacy codec doesn't +// tolerate extensibility. type multisigPubKeyInfo struct { PubKey cryptotypes.PubKey `json:"pubkey"` Weight uint `json:"weight"` @@ -191,21 +195,14 @@ type multiInfo struct { } // NewMultiInfo creates a new multiInfo instance -func NewMultiInfo(name string, pub cryptotypes.PubKey) Info { - multiPK := pub.(*multisig.LegacyAminoPubKey) - - pubKeys := make([]multisigPubKeyInfo, len(multiPK.PubKeys)) - for i, pk := range multiPK.GetPubKeys() { - // TODO: Recursively check pk for total weight? - pubKeys[i] = multisigPubKeyInfo{pk, 1} +func NewMultiInfo(name string, pub cryptotypes.PubKey) (Info, error) { + if _, ok := pub.(*multisig.LegacyAminoPubKey); !ok { + return nil, fmt.Errorf("MultiInfo supports only multisig.LegacyAminoPubKey, got %T", pub) } - return &multiInfo{ - Name: name, - PubKey: pub, - Threshold: uint(multiPK.Threshold), - PubKeys: pubKeys, - } + Name: name, + PubKey: pub, + }, nil } // GetType implements Info interface diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 0634871a5..b68fc8d65 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -437,7 +437,7 @@ func (ks keystore) Delete(uid string) error { return err } - err = ks.db.Remove(string(infoKey(uid))) + err = ks.db.Remove(infoKey(uid)) if err != nil { return err } @@ -448,19 +448,20 @@ func (ks keystore) Delete(uid string) error { func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) { ik, err := ks.db.Get(addrHexKeyAsString(address)) if err != nil { - return nil, err + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) } if len(ik.Data) == 0 { - return nil, fmt.Errorf("key with address %s not found", address) + return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found")) } + return ks.key(string(ik.Data)) +} - bs, err := ks.db.Get(string(ik.Data)) - if err != nil { - return nil, err +func wrapKeyNotFound(err error, msg string) error { + if err == keyring.ErrKeyNotFound { + return sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, msg) } - - return unmarshalInfo(bs.Data) + return err } func (ks keystore) List() ([]Info, error) { @@ -529,7 +530,7 @@ func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passp return info, mnemonic, nil } -func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) { +func (ks keystore) NewAccount(name string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) { if !ks.isSupportedSigningAlgo(algo) { return nil, ErrUnsupportedSigningAlgo } @@ -549,28 +550,28 @@ func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase strin return nil, fmt.Errorf("account with address %s already exists in keyring, delete the key first if you want to recreate it", address) } - return ks.writeLocalKey(uid, privKey, algo.Name()) + return ks.writeLocalKey(name, privKey, algo.Name()) } func (ks keystore) isSupportedSigningAlgo(algo SignatureAlgo) bool { return ks.options.SupportedAlgos.Contains(algo) } -func (ks keystore) Key(uid string) (Info, error) { - key := infoKey(uid) - - bs, err := ks.db.Get(string(key)) +func (ks keystore) key(infoKey string) (Info, error) { + bs, err := ks.db.Get(infoKey) if err != nil { - return nil, err + return nil, wrapKeyNotFound(err, infoKey) } - if len(bs.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, uid) + return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, infoKey) } - return unmarshalInfo(bs.Data) } +func (ks keystore) Key(uid string) (Info, error) { + return ks.key(infoKey(uid)) +} + // SupportedAlgorithms returns the keystore Options' supported signing algorithm. // for the keyring and Ledger. func (ks keystore) SupportedAlgorithms() (SigningAlgoList, SigningAlgoList) { @@ -742,7 +743,6 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) { func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKeyType) (Info, error) { // encrypt private key using keyring pub := priv.PubKey() - info := newLocalInfo(name, pub, string(legacy.Cdc.MustMarshalBinaryBare(priv)), algo) if err := ks.writeInfo(info); err != nil { return nil, err @@ -752,18 +752,16 @@ func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKey } func (ks keystore) writeInfo(info Info) error { - // write the info by key - key := infoKey(info.GetName()) + key := infoKeyBz(info.GetName()) serializedInfo := marshalInfo(info) exists, err := ks.existsInDb(info) - if exists { - return errors.New("public key already exist in keybase") - } - if err != nil { return err } + if exists { + return errors.New("public key already exist in keybase") + } err = ks.db.Set(keyring.Item{ Key: string(key), @@ -784,6 +782,8 @@ func (ks keystore) writeInfo(info Info) error { return nil } +// existsInDb returns true if key is in DB. Error is returned only when we have error +// different thant ErrKeyNotFound func (ks keystore) existsInDb(info Info) (bool, error) { if _, err := ks.db.Get(addrHexKeyAsString(info.GetAddress())); err == nil { return true, nil // address lookup succeeds - info exists @@ -791,7 +791,7 @@ func (ks keystore) existsInDb(info Info) (bool, error) { return false, err // received unexpected error - returns error } - if _, err := ks.db.Get(string(infoKey(info.GetName()))); err == nil { + if _, err := ks.db.Get(infoKey(info.GetName())); err == nil { return true, nil // uid lookup succeeds - info exists } else if err != keyring.ErrKeyNotFound { return false, err // received unexpected error - returns @@ -812,11 +812,13 @@ func (ks keystore) writeOfflineKey(name string, pub types.PubKey, algo hd.PubKey } func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error) { - info := NewMultiInfo(name, pub) - err := ks.writeInfo(info) + info, err := NewMultiInfo(name, pub) if err != nil { return nil, err } + if err = ks.writeInfo(info); err != nil { + return nil, err + } return info, nil } diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go index 5cdac5069..34f94548f 100644 --- a/crypto/keyring/keyring_ledger_test.go +++ b/crypto/keyring/keyring_ledger_test.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/types" - sdk "github.com/cosmos/cosmos-sdk/types" ) func TestInMemoryCreateLedger(t *testing.T) { @@ -28,9 +27,8 @@ func TestInMemoryCreateLedger(t *testing.T) { // The mock is available, check that the address is correct pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + expectedPkStr := "PubKeySecp256k1{03602C0CB4D8C0081FEE794BDE96E7B95FA16F2B5283B764AC070584327B2C7202}" + require.Equal(t, expectedPkStr, pubKey.String()) // Check that restoring the key gets the same results restoredKey, err := kb.Key("some_account") @@ -39,9 +37,7 @@ func TestInMemoryCreateLedger(t *testing.T) { require.Equal(t, "some_account", restoredKey.GetName()) require.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + require.Equal(t, expectedPkStr, pubKey.String()) path, err := restoredKey.GetPath() require.NoError(t, err) @@ -106,9 +102,8 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { // The mock is available, check that the address is correct require.Equal(t, "some_account", ledger.GetName()) pubKey := ledger.GetPubKey() - pk, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + expectedPkStr := "PubKeySecp256k1{03602C0CB4D8C0081FEE794BDE96E7B95FA16F2B5283B764AC070584327B2C7202}" + require.Equal(t, expectedPkStr, pubKey.String()) // Check that restoring the key gets the same results restoredKey, err := keyring.Key("some_account") @@ -117,9 +112,7 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { require.Equal(t, "some_account", restoredKey.GetName()) require.Equal(t, TypeLedger, restoredKey.GetType()) pubKey = restoredKey.GetPubKey() - pk, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk) + require.Equal(t, expectedPkStr, pubKey.String()) path, err := restoredKey.GetPath() require.NoError(t, err) diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index c9f387e78..2f8e928e7 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -367,7 +367,7 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { // try export non existing key _, err = kb.ExportPrivKeyArmor("john3", "wrongpassword") - require.Equal(t, "The specified item could not be found in the keyring", err.Error()) + require.EqualError(t, err, "john3.info: key not found") } func TestInMemoryLanguage(t *testing.T) { diff --git a/crypto/keyring/legacy.go b/crypto/keyring/legacy.go index 94bff8232..00ca8bfcc 100644 --- a/crypto/keyring/legacy.go +++ b/crypto/keyring/legacy.go @@ -85,7 +85,7 @@ func (kb dbKeybase) List() ([]Info, error) { // Get returns the public information about one key. func (kb dbKeybase) Get(name string) (Info, error) { - bs, err := kb.db.Get(infoKey(name)) + bs, err := kb.db.Get(infoKeyBz(name)) if err != nil { return nil, err } @@ -129,7 +129,7 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (type } func (kb dbKeybase) Export(name string) (armor string, err error) { - bz, err := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKeyBz(name)) if err != nil { return "", err } @@ -144,7 +144,7 @@ func (kb dbKeybase) Export(name string) (armor string, err error) { // ExportPubKey returns public keys in ASCII armored format. It retrieves a Info // object by its name and return the public key in a portable format. func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { - bz, err := kb.db.Get(infoKey(name)) + bz, err := kb.db.Get(infoKeyBz(name)) if err != nil { return "", err } @@ -182,7 +182,8 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string, // Close the underlying storage. func (kb dbKeybase) Close() error { return kb.db.Close() } -func infoKey(name string) []byte { return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) } +func infoKey(name string) string { return fmt.Sprintf("%s.%s", name, infoSuffix) } +func infoKeyBz(name string) []byte { return []byte(infoKey(name)) } // KeybaseOption overrides options for the db. type KeybaseOption func(*kbOptions) diff --git a/crypto/keyring/output.go b/crypto/keyring/output.go index 5f76789ca..91588e313 100644 --- a/crypto/keyring/output.go +++ b/crypto/keyring/output.go @@ -1,106 +1,78 @@ package keyring import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" ) +// TODO: Move this file to client/keys +// Use protobuf interface marshaler rather then generic JSON + // KeyOutput defines a structure wrapping around an Info object used for output // functionality. type KeyOutput struct { - Name string `json:"name" yaml:"name"` - Type string `json:"type" yaml:"type"` - Address string `json:"address" yaml:"address"` - PubKey string `json:"pubkey" yaml:"pubkey"` - Mnemonic string `json:"mnemonic,omitempty" yaml:"mnemonic"` - Threshold uint `json:"threshold,omitempty" yaml:"threshold"` - PubKeys []multisigPubKeyOutput `json:"pubkeys,omitempty" yaml:"pubkeys"` + Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` + Address string `json:"address" yaml:"address"` + PubKey string `json:"pubkey" yaml:"pubkey"` + Mnemonic string `json:"mnemonic,omitempty" yaml:"mnemonic"` } // NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys -func NewKeyOutput(name, keyType, address, pubkey string) KeyOutput { +func NewKeyOutput(name string, keyType KeyType, a sdk.Address, pk cryptotypes.PubKey) (KeyOutput, error) { // nolint:interfacer + apk, err := codectypes.NewAnyWithValue(pk) + if err != nil { + return KeyOutput{}, err + } + bz, err := codec.ProtoMarshalJSON(apk, nil) + if err != nil { + return KeyOutput{}, err + } return KeyOutput{ Name: name, - Type: keyType, - Address: address, - PubKey: pubkey, - } + Type: keyType.String(), + Address: a.String(), + PubKey: string(bz), + }, nil } -type multisigPubKeyOutput struct { - Address string `json:"address" yaml:"address"` - PubKey string `json:"pubkey" yaml:"pubkey"` - Weight uint `json:"weight" yaml:"weight"` +// MkConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes. +func MkConsKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.ConsAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) } -// Bech32KeysOutput returns a slice of KeyOutput objects, each with the "acc" +// MkValKeyOutput create a KeyOutput in with "val" Bech32 prefixes. +func MkValKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.ValAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) +} + +// MkAccKeyOutput create a KeyOutput in with "acc" Bech32 prefixes. If the +// public key is a multisig public key, then the threshold and constituent +// public keys will be added. +func MkAccKeyOutput(keyInfo Info) (KeyOutput, error) { + pk := keyInfo.GetPubKey() + addr := sdk.AccAddress(pk.Address()) + return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk) +} + +// MkAccKeysOutput returns a slice of KeyOutput objects, each with the "acc" // Bech32 prefixes, given a slice of Info objects. It returns an error if any -// call to Bech32KeyOutput fails. -func Bech32KeysOutput(infos []Info) ([]KeyOutput, error) { +// call to MkKeyOutput fails. +func MkAccKeysOutput(infos []Info) ([]KeyOutput, error) { kos := make([]KeyOutput, len(infos)) + var err error for i, info := range infos { - ko, err := Bech32KeyOutput(info) + kos[i], err = MkAccKeyOutput(info) if err != nil { return nil, err } - kos[i] = ko } return kos, nil } - -// Bech32ConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes. -func Bech32ConsKeyOutput(keyInfo Info) (KeyOutput, error) { - consAddr := sdk.ConsAddress(keyInfo.GetPubKey().Address().Bytes()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, keyInfo.GetPubKey()) - if err != nil { - return KeyOutput{}, err - } - - return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), consAddr.String(), bechPubKey), nil -} - -// Bech32ValKeyOutput create a KeyOutput in with "val" Bech32 prefixes. -func Bech32ValKeyOutput(keyInfo Info) (KeyOutput, error) { - valAddr := sdk.ValAddress(keyInfo.GetPubKey().Address().Bytes()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeValPub, keyInfo.GetPubKey()) - if err != nil { - return KeyOutput{}, err - } - - return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), valAddr.String(), bechPubKey), nil -} - -// Bech32KeyOutput create a KeyOutput in with "acc" Bech32 prefixes. If the -// public key is a multisig public key, then the threshold and constituent -// public keys will be added. -func Bech32KeyOutput(keyInfo Info) (KeyOutput, error) { - accAddr := sdk.AccAddress(keyInfo.GetPubKey().Address().Bytes()) - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, keyInfo.GetPubKey()) - if err != nil { - return KeyOutput{}, err - } - - ko := NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), accAddr.String(), bechPubKey) - - if mInfo, ok := keyInfo.(*multiInfo); ok { - pubKeys := make([]multisigPubKeyOutput, len(mInfo.PubKeys)) - - for i, pk := range mInfo.PubKeys { - accAddr := sdk.AccAddress(pk.PubKey.Address().Bytes()) - - bechPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk.PubKey) - if err != nil { - return KeyOutput{}, err - } - - pubKeys[i] = multisigPubKeyOutput{accAddr.String(), bechPubKey, pk.Weight} - } - - ko.Threshold = mInfo.Threshold - ko.PubKeys = pubKeys - } - - return ko, nil -} diff --git a/crypto/keyring/output_test.go b/crypto/keyring/output_test.go index c43b36bf7..8f28e8cd1 100644 --- a/crypto/keyring/output_test.go +++ b/crypto/keyring/output_test.go @@ -1,6 +1,7 @@ package keyring import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -12,20 +13,18 @@ import ( ) func TestBech32KeysOutput(t *testing.T) { - tmpKey := secp256k1.GenPrivKey().PubKey() - bechTmpKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, tmpKey) - tmpAddr := sdk.AccAddress(tmpKey.Address().Bytes()) + sk := secp256k1.PrivKey{Key: []byte{154, 49, 3, 117, 55, 232, 249, 20, 205, 216, 102, 7, 136, 72, 177, 2, 131, 202, 234, 81, 31, 208, 46, 244, 179, 192, 167, 163, 142, 117, 246, 13}} + tmpKey := sk.PubKey() + multisigPk := kmultisig.NewLegacyAminoPubKey(1, []types.PubKey{tmpKey}) - multisigPks := kmultisig.NewLegacyAminoPubKey(1, []types.PubKey{tmpKey}) - multiInfo := NewMultiInfo("multisig", multisigPks) - accAddr := sdk.AccAddress(multiInfo.GetPubKey().Address().Bytes()) - bechPubKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, multiInfo.GetPubKey()) - - expectedOutput := NewKeyOutput(multiInfo.GetName(), multiInfo.GetType().String(), accAddr.String(), bechPubKey) - expectedOutput.Threshold = 1 - expectedOutput.PubKeys = []multisigPubKeyOutput{{tmpAddr.String(), bechTmpKey, 1}} - - outputs, err := Bech32KeysOutput([]Info{multiInfo}) + info, err := NewMultiInfo("multisig", multisigPk) require.NoError(t, err) - require.Equal(t, expectedOutput, outputs[0]) + accAddr := sdk.AccAddress(info.GetPubKey().Address()) + expectedOutput, err := NewKeyOutput(info.GetName(), info.GetType(), accAddr, multisigPk) + require.NoError(t, err) + + out, err := MkAccKeyOutput(info) + require.NoError(t, err) + require.Equal(t, expectedOutput, out) + require.Equal(t, `{Name:multisig Type:multi Address:cosmos1nf8lf6n4wa43rzmdzwe6hkrnw5guekhqt595cw PubKey:{"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":1,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}]} Mnemonic:}`, fmt.Sprintf("%+v", out)) } diff --git a/crypto/keyring/types_test.go b/crypto/keyring/types_test.go index b04aa4547..daf75b5d8 100644 --- a/crypto/keyring/types_test.go +++ b/crypto/keyring/types_test.go @@ -2,6 +2,7 @@ package keyring import ( "encoding/hex" + "fmt" "testing" "github.com/stretchr/testify/require" @@ -13,7 +14,9 @@ import ( func Test_writeReadLedgerInfo(t *testing.T) { tmpKey := make([]byte, secp256k1.PubKeySize) - bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") + hexPK := "035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A" + bz, err := hex.DecodeString(hexPK) + require.NoError(t, err) copy(tmpKey[:], bz) lInfo := newLedgerInfo("some_name", &secp256k1.PubKey{Key: tmpKey}, *hd.NewFundraiserParams(5, sdk.CoinType, 1), hd.Secp256k1Type) @@ -23,8 +26,8 @@ func Test_writeReadLedgerInfo(t *testing.T) { require.NoError(t, err) require.Equal(t, "m/44'/118'/5'/0/1", path.String()) require.Equal(t, - "cosmospub1addwnpepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5wmxv8p", - sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey())) + fmt.Sprintf("PubKeySecp256k1{%s}", hexPK), + lInfo.GetPubKey().String()) // Serialize and restore serialized := marshalInfo(lInfo) diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index 0c87260ec..4ade041c4 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -180,6 +180,7 @@ func (pubKey *PubKey) VerifySignature(msg []byte, sig []byte) bool { return ed25519consensus.Verify(pubKey.Key, msg, sig) } +// String returns Hex representation of a pubkey with it's type func (pubKey *PubKey) String() string { return fmt.Sprintf("PubKeyEd25519{%X}", pubKey.Key) } diff --git a/crypto/keys/ed25519/ed25519_test.go b/crypto/keys/ed25519/ed25519_test.go index 27cef37f9..44b003fbe 100644 --- a/crypto/keys/ed25519/ed25519_test.go +++ b/crypto/keys/ed25519/ed25519_test.go @@ -11,7 +11,9 @@ import ( tmed25519 "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/codec" - ed25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -234,3 +236,21 @@ func TestMarshalAmino_BackwardsCompatibility(t *testing.T) { }) } } + +func TestMarshalJSON(t *testing.T) { + require := require.New(t) + privKey := ed25519.GenPrivKey() + pk := privKey.PubKey() + + registry := types.NewInterfaceRegistry() + cryptocodec.RegisterInterfaces(registry) + cdc := codec.NewProtoCodec(registry) + + bz, err := cdc.MarshalInterfaceJSON(pk) + require.NoError(err) + + var pk2 cryptotypes.PubKey + err = cdc.UnmarshalInterfaceJSON(bz, &pk2) + require.NoError(err) + require.True(pk2.Equals(pk)) +} diff --git a/crypto/keys/multisig/multisig.go b/crypto/keys/multisig/multisig.go index b3d8d8fab..c0dfbb779 100644 --- a/crypto/keys/multisig/multisig.go +++ b/crypto/keys/multisig/multisig.go @@ -18,18 +18,18 @@ var _ types.UnpackInterfacesMessage = &LegacyAminoPubKey{} // Multisig can be constructed with multiple same keys - it will increase the power of // the owner of that key (he will still need to add multiple signatures in the right order). // Panics if len(pubKeys) < k or 0 >= k. -func NewLegacyAminoPubKey(k int, pubKeys []cryptotypes.PubKey) *LegacyAminoPubKey { - if k <= 0 { +func NewLegacyAminoPubKey(threshold int, pubKeys []cryptotypes.PubKey) *LegacyAminoPubKey { + if threshold <= 0 { panic("threshold k of n multisignature: k <= 0") } - if len(pubKeys) < k { + if len(pubKeys) < threshold { panic("threshold k of n multisignature: len(pubKeys) < k") } anyPubKeys, err := packPubKeys(pubKeys) if err != nil { panic(err) } - return &LegacyAminoPubKey{Threshold: uint32(k), PubKeys: anyPubKeys} + return &LegacyAminoPubKey{Threshold: uint32(threshold), PubKeys: anyPubKeys} } // Address implements cryptotypes.PubKey Address method diff --git a/crypto/keys/multisig/multisig_test.go b/crypto/keys/multisig/multisig_test.go index 197a433a7..03b4f7eb6 100644 --- a/crypto/keys/multisig/multisig_test.go +++ b/crypto/keys/multisig/multisig_test.go @@ -1,6 +1,7 @@ package multisig_test import ( + "strings" "testing" "github.com/stretchr/testify/require" @@ -9,10 +10,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keyring" kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" ) @@ -27,8 +31,7 @@ func TestNewMultiSig(t *testing.T) { } func TestAddress(t *testing.T) { - msg := []byte{1, 2, 3, 4} - pubKeys, _ := generatePubKeysAndSignatures(5, msg) + pubKeys := generatePubKeys(5) multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubKeys) require.Len(t, multisigKey.Address().Bytes(), 20) @@ -110,7 +113,7 @@ func TestVerifyMultisignature(t *testing.T) { }, { "wrong size for sig bit array", func(require *require.Assertions) { - pubKeys, _ := generatePubKeysAndSignatures(3, msg) + pubKeys := generatePubKeys(3) pk = kmultisig.NewLegacyAminoPubKey(3, pubKeys) sig = multisig.NewMultisig(1) }, @@ -201,7 +204,7 @@ func TestVerifyMultisignature(t *testing.T) { }, { "unable to verify signature", func(require *require.Assertions) { - pubKeys, _ := generatePubKeysAndSignatures(2, msg) + pubKeys := generatePubKeys(2) _, sigs := generatePubKeysAndSignatures(2, msg) pk = kmultisig.NewLegacyAminoPubKey(2, pubKeys) sig = multisig.NewMultisig(2) @@ -270,8 +273,7 @@ func TestMultiSigMigration(t *testing.T) { } func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) { - msg := []byte{1, 2, 3, 4} - pubkeys, _ := generatePubKeysAndSignatures(5, msg) + pubkeys := generatePubKeys(5) multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubkeys) ab, err := legacy.Cdc.MarshalBinaryLengthPrefixed(multisigKey) @@ -285,6 +287,14 @@ func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) { require.Equal(t, multisigKey.Equals(&pubKey), true) } +func generatePubKeys(n int) []cryptotypes.PubKey { + pks := make([]cryptotypes.PubKey, n) + for i := 0; i < n; i++ { + pks[i] = secp256k1.GenPrivKey().PubKey() + } + return pks +} + func generatePubKeysAndSignatures(n int, msg []byte) (pubKeys []cryptotypes.PubKey, signatures []signing.SignatureData) { pubKeys = make([]cryptotypes.PubKey, n) signatures = make([]signing.SignatureData, n) @@ -332,25 +342,40 @@ func reorderPubKey(pk *kmultisig.LegacyAminoPubKey) (other *kmultisig.LegacyAmin return } +func TestDisplay(t *testing.T) { + require := require.New(t) + pubKeys := generatePubKeys(3) + msig := kmultisig.NewLegacyAminoPubKey(2, pubKeys) + + // LegacyAminoPubKey wraps PubKeys into Amino (for serialization) and Any String method doesn't work. + require.PanicsWithValue("reflect.Value.Interface: cannot return value obtained from unexported field or method", + func() { require.Empty(msig.String()) }, + ) + ccfg := simapp.MakeTestEncodingConfig() + bz, err := ccfg.Marshaler.MarshalInterfaceJSON(msig) + require.NoError(err) + expectedPrefix := `{"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey"` + require.True(strings.HasPrefix(string(bz), expectedPrefix)) + // Example output: + // {"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":2,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AymUY3J2HKIyy9cbpGKcBFUTuDQsRH9NO/orKF/0WQ76"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AkvnCDzSYF+tQV/FoI217V7CDIRPzjJj7zBE2nw7x3xT"},{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A0yiqgcM5EB1i0h79+sQp+C0jLPFnT3+dFmdZmGa+H1s"}]} +} + func TestAminoBinary(t *testing.T) { - pubKey1 := secp256k1.GenPrivKey().PubKey() - pubKey2 := secp256k1.GenPrivKey().PubKey() - multisigKey := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubKey1, pubKey2}) + pubkeys := generatePubKeys(2) + msig := kmultisig.NewLegacyAminoPubKey(2, pubkeys) // Do a round-trip key->bytes->key. - bz, err := legacy.Cdc.MarshalBinaryBare(multisigKey) + bz, err := legacy.Cdc.MarshalBinaryBare(msig) require.NoError(t, err) - var newMultisigKey cryptotypes.PubKey - err = legacy.Cdc.UnmarshalBinaryBare(bz, &newMultisigKey) + var newMsig cryptotypes.PubKey + err = legacy.Cdc.UnmarshalBinaryBare(bz, &newMsig) require.NoError(t, err) - require.Equal(t, multisigKey.Threshold, newMultisigKey.(*kmultisig.LegacyAminoPubKey).Threshold) + require.Equal(t, msig.Threshold, newMsig.(*kmultisig.LegacyAminoPubKey).Threshold) } func TestAminoMarshalJSON(t *testing.T) { - pubKey1 := secp256k1.GenPrivKey().PubKey() - pubKey2 := secp256k1.GenPrivKey().PubKey() - multisigKey := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubKey1, pubKey2}) - + pubkeys := generatePubKeys(2) + multisigKey := kmultisig.NewLegacyAminoPubKey(2, pubkeys) bz, err := legacy.Cdc.MarshalJSON(multisigKey) require.NoError(t, err) @@ -401,5 +426,33 @@ func TestAminoUnmarshalJSON(t *testing.T) { var pk cryptotypes.PubKey err := cdc.UnmarshalJSON([]byte(pkJSON), &pk) require.NoError(t, err) - require.Equal(t, uint32(3), pk.(*kmultisig.LegacyAminoPubKey).Threshold) + lpk := pk.(*kmultisig.LegacyAminoPubKey) + require.Equal(t, uint32(3), lpk.Threshold) +} + +func TestProtoMarshalJSON(t *testing.T) { + require := require.New(t) + pubkeys := generatePubKeys(3) + msig := kmultisig.NewLegacyAminoPubKey(2, pubkeys) + + registry := types.NewInterfaceRegistry() + cryptocodec.RegisterInterfaces(registry) + cdc := codec.NewProtoCodec(registry) + + bz, err := cdc.MarshalInterfaceJSON(msig) + require.NoError(err) + + var pk2 cryptotypes.PubKey + err = cdc.UnmarshalInterfaceJSON(bz, &pk2) + require.NoError(err) + require.True(pk2.Equals(msig)) + + // Test that we can correctly unmarshal key from keyring output + + info, err := keyring.NewMultiInfo("my multisig", msig) + require.NoError(err) + ko, err := keyring.MkAccKeyOutput(info) + require.NoError(err) + require.Equal(ko.Address, sdk.AccAddress(pk2.Address()).String()) + require.Equal(ko.PubKey, string(bz)) } diff --git a/crypto/keys/secp256r1/privkey_internal_test.go b/crypto/keys/secp256r1/privkey_internal_test.go index ae48b47e3..d00040f7a 100644 --- a/crypto/keys/secp256r1/privkey_internal_test.go +++ b/crypto/keys/secp256r1/privkey_internal_test.go @@ -3,13 +3,13 @@ package secp256r1 import ( "testing" + proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - proto "github.com/gogo/protobuf/proto" - "github.com/stretchr/testify/suite" ) var _ cryptotypes.PrivKey = &PrivKey{} diff --git a/crypto/ledger/ledger_test.go b/crypto/ledger/ledger_test.go index ec1b8dbed..6583484ff 100644 --- a/crypto/ledger/ledger_test.go +++ b/crypto/ledger/ledger_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" ) func TestErrorHandling(t *testing.T) { @@ -25,17 +26,16 @@ func TestPublicKeyUnsafe(t *testing.T) { path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) priv, err := NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) - require.NotNil(t, priv) + checkDefaultPubKey(t, priv) +} +func checkDefaultPubKey(t *testing.T, priv types.LedgerPrivKey) { + require.NotNil(t, priv) + expectedPkStr := "PubKeySecp256k1{034FEF9CD7C4C63588D3B03FEB5281B9D232CBA34D6F3D71AEE59211FFBFE1FE87}" require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", - pubKeyAddr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - + require.Equal(t, expectedPkStr, priv.PubKey().String()) addr := sdk.AccAddress(priv.PubKey().Address()).String() require.Equal(t, "cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h", addr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) @@ -73,7 +73,7 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { require.NoError(t, tmp.ValidateKey()) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) + pubKeyAddr, err := legacybech32.MarshalPubKey(legacybech32.AccPK, priv.PubKey()) require.NoError(t, err) require.Equal(t, expectedAnswers[i], pubKeyAddr, @@ -102,20 +102,8 @@ func TestPublicKeySafe(t *testing.T) { require.NoError(t, err) require.NotNil(t, priv) - require.Nil(t, ShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())) - - require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", - fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), - "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", - pubKeyAddr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) - - require.Equal(t, "cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h", - addr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + checkDefaultPubKey(t, priv) addr2 := sdk.AccAddress(priv.PubKey().Address()).String() require.Equal(t, addr, addr2) @@ -153,8 +141,8 @@ func TestPublicKeyHDPath(t *testing.T) { privKeys := make([]types.LedgerPrivKey, numIters) // Check with device - for i := uint32(0); i < 10; i++ { - path := *hd.NewFundraiserParams(0, sdk.CoinType, i) + for i := 0; i < len(expectedAddrs); i++ { + path := *hd.NewFundraiserParams(0, sdk.CoinType, uint32(i)) t.Logf("Checking keys at %s\n", path) priv, addr, err := NewPrivKeySecp256k1(path, "cosmos") @@ -173,7 +161,7 @@ func TestPublicKeyHDPath(t *testing.T) { require.NoError(t, tmp.ValidateKey()) (&tmp).AssertIsPrivKeyInner() - pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) + pubKeyAddr, err := legacybech32.MarshalPubKey(legacybech32.AccPK, priv.PubKey()) require.NoError(t, err) require.Equal(t, expectedPubKeys[i], pubKeyAddr, diff --git a/server/rosetta/converter.go b/server/rosetta/converter.go index 43c946001..2c7282e48 100644 --- a/server/rosetta/converter.go +++ b/server/rosetta/converter.go @@ -118,7 +118,7 @@ func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sd txDecode: cfg.TxDecoder(), txEncode: cfg.TxEncoder(), bytesToSign: func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) { - bytesToSign, err := cfg.SignModeHandler().GetSignBytes(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) + bytesToSign, err := cfg.SignModeHandler().GetSignBytes(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) //nolint:staticcheck if err != nil { return nil, err } @@ -662,7 +662,7 @@ func (c converter) SignedTx(txBytes []byte, signatures []*rosettatypes.Signature signedSigs[i] = signing.SignatureV2{ PubKey: notSignedSigs[i].PubKey, Data: &signing.SingleSignatureData{ - SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, //nolint:staticcheck Signature: signature.Bytes, }, Sequence: notSignedSigs[i].Sequence, diff --git a/server/tm_cmds.go b/server/tm_cmds.go index 854d4597f..969d5ae8d 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -4,17 +4,15 @@ package server import ( "fmt" - "strings" "github.com/spf13/cobra" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" tversion "github.com/tendermint/tendermint/version" yaml "gopkg.in/yaml.v2" - "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/client" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -32,7 +30,6 @@ func ShowNodeIDCmd() *cobra.Command { if err != nil { return err } - fmt.Println(nodeKey.ID()) return nil }, @@ -49,31 +46,24 @@ func ShowValidatorCmd() *cobra.Command { cfg := serverCtx.Config privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) - valPubKey, err := privValidator.GetPubKey() + pk, err := privValidator.GetPubKey() if err != nil { return err } - - output, _ := cmd.Flags().GetString(cli.OutputFlag) - if strings.ToLower(output) == "json" { - return printlnJSON(valPubKey) - } - - pubkey, err := cryptocodec.FromTmPubKeyInterface(valPubKey) + sdkPK, err := cryptocodec.FromTmPubKeyInterface(pk) if err != nil { return err } - pubkeyBech32, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubkey) + clientCtx := client.GetClientContextFromCmd(cmd) + bz, err := clientCtx.JSONMarshaler.MarshalInterfaceJSON(sdkPK) if err != nil { return err } - - fmt.Println(pubkeyBech32) + fmt.Println(string(bz)) return nil }, } - cmd.Flags().StringP(cli.OutputFlag, "o", "text", "Output format (text|json)") return &cmd } @@ -88,18 +78,11 @@ func ShowAddressCmd() *cobra.Command { privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) valConsAddr := (sdk.ConsAddress)(privValidator.GetAddress()) - - output, _ := cmd.Flags().GetString(cli.OutputFlag) - if strings.ToLower(output) == "json" { - return printlnJSON(valConsAddr) - } - fmt.Println(valConsAddr.String()) return nil }, } - cmd.Flags().StringP(cli.OutputFlag, "o", "text", "Output format (text|json)") return cmd } @@ -133,19 +116,6 @@ against which this app has been compiled. } } -func printlnJSON(v interface{}) error { - cdc := codec.NewLegacyAmino() - cryptocodec.RegisterCrypto(cdc) - - marshalled, err := cdc.MarshalJSON(v) - if err != nil { - return err - } - - fmt.Println(string(marshalled)) - return nil -} - // UnsafeResetAllCmd - extension of the tendermint command, resets initialization func UnsafeResetAllCmd() *cobra.Command { return &cobra.Command{ diff --git a/types/address.go b/types/address.go index a730e5120..09f610d03 100644 --- a/types/address.go +++ b/types/address.go @@ -11,7 +11,6 @@ import ( yaml "gopkg.in/yaml.v2" - "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/internal/conv" "github.com/cosmos/cosmos-sdk/types/address" @@ -623,86 +622,12 @@ func (ca ConsAddress) Format(s fmt.State, verb rune) { // auxiliary // ---------------------------------------------------------------------------- -// Bech32PubKeyType defines a string type alias for a Bech32 public key type. -type Bech32PubKeyType string - -// Bech32 conversion constants -const ( - Bech32PubKeyTypeAccPub Bech32PubKeyType = "accpub" - Bech32PubKeyTypeValPub Bech32PubKeyType = "valpub" - Bech32PubKeyTypeConsPub Bech32PubKeyType = "conspub" -) - -// Bech32ifyPubKey returns a Bech32 encoded string containing the appropriate -// prefix based on the key type provided for a given PublicKey. -// TODO: Remove Bech32ifyPubKey and all usages (cosmos/cosmos-sdk/issues/#7357) -func Bech32ifyPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) (string, error) { - var bech32Prefix string - - switch pkt { - case Bech32PubKeyTypeAccPub: - bech32Prefix = GetConfig().GetBech32AccountPubPrefix() - - case Bech32PubKeyTypeValPub: - bech32Prefix = GetConfig().GetBech32ValidatorPubPrefix() - - case Bech32PubKeyTypeConsPub: - bech32Prefix = GetConfig().GetBech32ConsensusPubPrefix() - - } - - return bech32.ConvertAndEncode(bech32Prefix, legacy.Cdc.MustMarshalBinaryBare(pubkey)) -} - -// MustBech32ifyPubKey calls Bech32ifyPubKey except it panics on error. -func MustBech32ifyPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) string { - res, err := Bech32ifyPubKey(pkt, pubkey) - if err != nil { - panic(err) - } - - return res -} - -// GetPubKeyFromBech32 returns a PublicKey from a bech32-encoded PublicKey with -// a given key type. -func GetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) (cryptotypes.PubKey, error) { - var bech32Prefix string - - switch pkt { - case Bech32PubKeyTypeAccPub: - bech32Prefix = GetConfig().GetBech32AccountPubPrefix() - - case Bech32PubKeyTypeValPub: - bech32Prefix = GetConfig().GetBech32ValidatorPubPrefix() - - case Bech32PubKeyTypeConsPub: - bech32Prefix = GetConfig().GetBech32ConsensusPubPrefix() - - } - - bz, err := GetFromBech32(pubkeyStr, bech32Prefix) - if err != nil { - return nil, err - } - - return legacy.PubKeyFromBytes(bz) -} - -// MustGetPubKeyFromBech32 calls GetPubKeyFromBech32 except it panics on error. -func MustGetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) cryptotypes.PubKey { - res, err := GetPubKeyFromBech32(pkt, pubkeyStr) - if err != nil { - panic(err) - } - - return res -} +var errBech32EmptyAddress = errors.New("decoding Bech32 address failed: must provide a non empty address") // GetFromBech32 decodes a bytestring from a Bech32 encoded string. func GetFromBech32(bech32str, prefix string) ([]byte, error) { if len(bech32str) == 0 { - return nil, errors.New("decoding Bech32 address failed: must provide an address") + return nil, errBech32EmptyAddress } hrp, bz, err := bech32.DecodeAndConvert(bech32str) diff --git a/types/address_test.go b/types/address_test.go index b9bc0c3c5..e69026ab7 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" ) type addressTestSuite struct { @@ -68,48 +69,6 @@ func (s *addressTestSuite) TestEmptyAddresses() { s.Require().Error(err) } -func (s *addressTestSuite) TestRandBech32PubkeyConsistency() { - pubBz := make([]byte, ed25519.PubKeySize) - pub := &ed25519.PubKey{Key: pubBz} - - for i := 0; i < 1000; i++ { - rand.Read(pub.Key) - - mustBech32AccPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) - bech32AccPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32AccPub, mustBech32AccPub) - - mustBech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) - bech32ValPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32ValPub, mustBech32ValPub) - - mustBech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) - bech32ConsPub, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) - s.Require().Nil(err) - s.Require().Equal(bech32ConsPub, mustBech32ConsPub) - - mustAccPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) - accPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeAccPub, bech32AccPub) - s.Require().Nil(err) - s.Require().Equal(accPub, mustAccPub) - - mustValPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) - valPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeValPub, bech32ValPub) - s.Require().Nil(err) - s.Require().Equal(valPub, mustValPub) - - mustConsPub := types.MustGetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) - consPub, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, bech32ConsPub) - s.Require().Nil(err) - s.Require().Equal(consPub, mustConsPub) - - s.Require().Equal(valPub, accPub) - s.Require().Equal(valPub, consPub) - } -} - func (s *addressTestSuite) TestYAMLMarshalers() { addr := secp256k1.GenPrivKey().PubKey().Address() @@ -277,7 +236,7 @@ func (s *addressTestSuite) TestConfiguredPrefix() { acc.String(), prefix+types.PrefixAccount), acc.String()) - bech32Pub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeAccPub, pub) + bech32Pub := legacybech32.MustMarshalPubKey(legacybech32.AccPK, pub) s.Require().True(strings.HasPrefix( bech32Pub, prefix+types.PrefixPublic)) @@ -291,7 +250,7 @@ func (s *addressTestSuite) TestConfiguredPrefix() { val.String(), prefix+types.PrefixValidator+types.PrefixAddress)) - bech32ValPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeValPub, pub) + bech32ValPub := legacybech32.MustMarshalPubKey(legacybech32.ValPK, pub) s.Require().True(strings.HasPrefix( bech32ValPub, prefix+types.PrefixValidator+types.PrefixPublic)) @@ -305,7 +264,7 @@ func (s *addressTestSuite) TestConfiguredPrefix() { cons.String(), prefix+types.PrefixConsensus+types.PrefixAddress)) - bech32ConsPub := types.MustBech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pub) + bech32ConsPub := legacybech32.MustMarshalPubKey(legacybech32.ConsPK, pub) s.Require().True(strings.HasPrefix( bech32ConsPub, prefix+types.PrefixConsensus+types.PrefixPublic)) @@ -523,7 +482,7 @@ func (s *addressTestSuite) TestGetConsAddress() { func (s *addressTestSuite) TestGetFromBech32() { _, err := types.GetFromBech32("", "prefix") s.Require().Error(err) - s.Require().Equal("decoding Bech32 address failed: must provide an address", err.Error()) + s.Require().Equal("decoding Bech32 address failed: must provide a non empty address", err.Error()) _, err = types.GetFromBech32("cosmos1qqqsyqcyq5rqwzqfys8f67", "x") s.Require().Error(err) s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) diff --git a/types/bech32/legacybech32/pk.go b/types/bech32/legacybech32/pk.go new file mode 100644 index 000000000..d87053190 --- /dev/null +++ b/types/bech32/legacybech32/pk.go @@ -0,0 +1,68 @@ +// Deprecated: The module provides legacy bech32 functions which will be removed in a future +// release. +package legacybech32 + +import ( + "github.com/cosmos/cosmos-sdk/codec/legacy" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" +) + +// TODO: when removing this package remove: +// + sdk:config.GetBech32AccountPubPrefix (and other related functions) +// + Bech32PrefixAccAddr and other related constants + +// Deprecated: Bech32PubKeyType defines a string type alias for a Bech32 public key type. +type Bech32PubKeyType string + +// Bech32 conversion constants +const ( + AccPK Bech32PubKeyType = "accpub" + ValPK Bech32PubKeyType = "valpub" + ConsPK Bech32PubKeyType = "conspub" +) + +// Deprecated: MarshalPubKey returns a Bech32 encoded string containing the appropriate +// prefix based on the key type provided for a given PublicKey. +func MarshalPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) (string, error) { + bech32Prefix := getPrefix(pkt) + return bech32.ConvertAndEncode(bech32Prefix, legacy.Cdc.MustMarshalBinaryBare(pubkey)) +} + +// Deprecated: MustMarshalPubKey calls MarshalPubKey and panics on error. +func MustMarshalPubKey(pkt Bech32PubKeyType, pubkey cryptotypes.PubKey) string { + res, err := MarshalPubKey(pkt, pubkey) + if err != nil { + panic(err) + } + + return res +} + +func getPrefix(pkt Bech32PubKeyType) string { + cfg := sdk.GetConfig() + switch pkt { + case AccPK: + return cfg.GetBech32AccountPubPrefix() + + case ValPK: + return cfg.GetBech32ValidatorPubPrefix() + case ConsPK: + return cfg.GetBech32ConsensusPubPrefix() + } + + return "" +} + +// Deprecated: UnmarshalPubKey returns a PublicKey from a bech32-encoded PublicKey with +// a given key type. +func UnmarshalPubKey(pkt Bech32PubKeyType, pubkeyStr string) (cryptotypes.PubKey, error) { + bech32Prefix := getPrefix(pkt) + + bz, err := sdk.GetFromBech32(pubkeyStr, bech32Prefix) + if err != nil { + return nil, err + } + return legacy.PubKeyFromBytes(bz) +} diff --git a/types/address_bench_test.go b/types/bech32/legacybech32/pk_bench_test.go similarity index 79% rename from types/address_bench_test.go rename to types/bech32/legacybech32/pk_bench_test.go index 0aad726c8..087b2da3d 100644 --- a/types/address_bench_test.go +++ b/types/bech32/legacybech32/pk_bench_test.go @@ -1,4 +1,4 @@ -package types_test +package legacybech32 import ( "math/rand" @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/cosmos-sdk/types" ) func BenchmarkAccAddressString(b *testing.B) { @@ -30,7 +29,7 @@ func BenchmarkAccAddressString(b *testing.B) { require.NotEmpty(b, str2) } -func BenchmarkBech32ifyPubKey(b *testing.B) { +func BenchmarkMarshalPubKey(b *testing.B) { b.ReportAllocs() pkBz := make([]byte, ed25519.PubKeySize) pk := &ed25519.PubKey{Key: pkBz} @@ -43,7 +42,7 @@ func BenchmarkBech32ifyPubKey(b *testing.B) { rng.Read(pk.Key) b.StartTimer() - _, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + _, err := MarshalPubKey(ConsPK, pk) require.NoError(b, err) } } @@ -60,11 +59,11 @@ func BenchmarkGetPubKeyFromBech32(b *testing.B) { b.StopTimer() rng.Read(pk.Key) - pkStr, err := types.Bech32ifyPubKey(types.Bech32PubKeyTypeConsPub, pk) + pkStr, err := MarshalPubKey(ConsPK, pk) require.NoError(b, err) b.StartTimer() - pk2, err := types.GetPubKeyFromBech32(types.Bech32PubKeyTypeConsPub, pkStr) + pk2, err := UnmarshalPubKey(ConsPK, pkStr) require.NoError(b, err) require.Equal(b, pk, pk2) } diff --git a/types/bech32/legacybech32/pk_test.go b/types/bech32/legacybech32/pk_test.go new file mode 100644 index 000000000..262784c04 --- /dev/null +++ b/types/bech32/legacybech32/pk_test.go @@ -0,0 +1,26 @@ +package legacybech32 + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/ledger" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestBeach32ifPbKey(t *testing.T) { + require := require.New(t) + path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) + require.Nil(err, "%s", err) + require.NotNil(priv) + + pubKeyAddr, err := MarshalPubKey(AccPK, priv.PubKey()) + require.NoError(err) + require.Equal("cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", + pubKeyAddr, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) + +} diff --git a/types/errors/errors.go b/types/errors/errors.go index c635beb97..9127b9852 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -137,6 +137,10 @@ var ( // ErrNotFound defines an error when requested entity doesn't exist in the state. ErrNotFound = Register(RootCodespace, 38, "not found") + // ErrIO should be used to wrap internal errors caused by external operation. + // Examples: not DB domain error, file writing etc... + ErrIO = Register(RootCodespace, 39, "Internal IO error") + // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info ErrPanic = Register(UndefinedCodespace, 111222, "panic") @@ -367,6 +371,17 @@ func WithType(err error, obj interface{}) error { return Wrap(err, fmt.Sprintf("%T", obj)) } +// IsOf checks if a received error is caused by one of the target errors. +// It extends the errors.Is functionality to a list of errors. +func IsOf(received error, targets ...error) bool { + for _, t := range targets { + if errors.Is(received, t) { + return true + } + } + return false +} + // causer is an interface implemented by an error that supports wrapping. Use // it to test if an error wraps another error instance. type causer interface { diff --git a/types/errors/errors_test.go b/types/errors/errors_test.go index ea0e063c3..c72344e4f 100644 --- a/types/errors/errors_test.go +++ b/types/errors/errors_test.go @@ -149,6 +149,27 @@ func (s *errorsTestSuite) TestErrorIs() { } } +func (s *errorsTestSuite) TestIsOf() { + require := s.Require() + + var errNil *Error + var err = ErrInvalidAddress + var errW = Wrap(ErrLogic, "more info") + + require.False(IsOf(errNil), "nil error should always have no causer") + require.False(IsOf(errNil, err), "nil error should always have no causer") + + require.False(IsOf(err)) + require.False(IsOf(err, nil)) + require.False(IsOf(err, ErrLogic)) + + require.True(IsOf(errW, ErrLogic)) + require.True(IsOf(errW, err, ErrLogic)) + require.True(IsOf(errW, nil, errW), "error should much itself") + var err2 = errors.New("other error") + require.True(IsOf(err2, nil, err2), "error should much itself") +} + type customError struct { } diff --git a/types/tx/signing/signing.pb.go b/types/tx/signing/signing.pb.go index f06a270c7..cd41e1bba 100644 --- a/types/tx/signing/signing.pb.go +++ b/types/tx/signing/signing.pb.go @@ -5,12 +5,13 @@ package signing import ( fmt "fmt" - types "github.com/cosmos/cosmos-sdk/codec/types" - types1 "github.com/cosmos/cosmos-sdk/crypto/types" - proto "github.com/gogo/protobuf/proto" io "io" math "math" math_bits "math/bits" + + types "github.com/cosmos/cosmos-sdk/codec/types" + types1 "github.com/cosmos/cosmos-sdk/crypto/types" + proto "github.com/gogo/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. @@ -38,7 +39,7 @@ const ( // human-readable textual representation on top of the binary representation // from SIGN_MODE_DIRECT SignMode_SIGN_MODE_TEXTUAL SignMode = 2 - // SIGN_MODE_LEGACY_AMINO_JSON is a backwards compatibility mode which uses + // Deprecated: SIGN_MODE_LEGACY_AMINO_JSON is a backwards compatibility mode which uses // Amino JSON and will be removed in the future SignMode_SIGN_MODE_LEGACY_AMINO_JSON SignMode = 127 ) diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index daa59d0b5..a057c7454 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -186,7 +186,7 @@ func NewSigVerificationDecorator(ak AccountKeeper, signModeHandler authsigning.S func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool { switch v := sigData.(type) { case *signing.SingleSignatureData: - return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON + return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON //nolint:staticcheck case *signing.MultiSignatureData: for _, s := range v.Signatures { if !OnlyLegacyAminoSigners(s) { diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 7fdcace96..8a95eff9f 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -77,7 +77,7 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED { - txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) + txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) //nolint:staticcheck } txCfg := clientCtx.TxConfig @@ -235,7 +235,7 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error { txCfg := clientCtx.TxConfig txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED { - txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) + txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) //nolint:staticcheck } var infile = os.Stdin diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index f814f9b99..c5208bb3e 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -115,7 +115,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { } } else { if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED { - txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) + txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) //nolint:staticcheck } err = authclient.SignTxWithSignerAddress( txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true) @@ -219,7 +219,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error { return err } if txF.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED { - txF = txF.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) + txF = txF.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) //nolint:staticcheck } txCfg := clientCtx.TxConfig txBuilder, err := txCfg.WrapTxBuilder(newTx) diff --git a/x/auth/keeper/account.go b/x/auth/keeper/account.go index 9921bb96f..a26ea6427 100644 --- a/x/auth/keeper/account.go +++ b/x/auth/keeper/account.go @@ -67,7 +67,8 @@ func (ak AccountKeeper) RemoveAccount(ctx sdk.Context, acc types.AccountI) { store.Delete(types.AddressStoreKey(addr)) } -// IterateAccounts iterates over all the stored accounts and performs a callback function +// IterateAccounts iterates over all the stored accounts and performs a callback function. +// Stops iteration when callback returns true. func (ak AccountKeeper) IterateAccounts(ctx sdk.Context, cb func(account types.AccountI) (stop bool)) { store := ctx.KVStore(ak.key) iterator := sdk.KVStorePrefixIterator(store, types.AddressStoreKeyPrefix) diff --git a/x/auth/legacy/legacytx/stdsig_test.go b/x/auth/legacy/legacytx/stdsig_test.go new file mode 100644 index 000000000..3e1662ba9 --- /dev/null +++ b/x/auth/legacy/legacytx/stdsig_test.go @@ -0,0 +1,41 @@ +package legacytx_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + yaml "gopkg.in/yaml.v2" + + "github.com/cosmos/cosmos-sdk/testutil/testdata" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" +) + +func TestStdSignatureMarshalYAML(t *testing.T) { + _, pk, _ := testdata.KeyTestPubAddr() + pkStr := pk.String() + + testCases := []struct { + sig legacytx.StdSignature + expected string + }{ + { + legacytx.StdSignature{}, + "|\n pubkey: \"\"\n signature: \"\"\n", + }, + { + legacytx.StdSignature{PubKey: pk, Signature: []byte("dummySig")}, + fmt.Sprintf("|\n pubkey: %s\n signature: 64756D6D79536967\n", pkStr), + }, + { + legacytx.StdSignature{PubKey: pk, Signature: nil}, + fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", pkStr), + }, + } + + for i, tc := range testCases { + bz, err := yaml.Marshal(tc.sig) + require.NoError(t, err) + require.Equal(t, tc.expected, string(bz), "test case #%d", i) + } +} diff --git a/x/auth/legacy/legacytx/stdsign.go b/x/auth/legacy/legacytx/stdsign.go index f87900620..ba753683f 100644 --- a/x/auth/legacy/legacytx/stdsign.go +++ b/x/auth/legacy/legacytx/stdsign.go @@ -2,14 +2,17 @@ package legacytx import ( "encoding/json" + "fmt" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" + "gopkg.in/yaml.v2" ) // StdSignDoc is replay-prevention structure. @@ -59,6 +62,47 @@ type StdSignature struct { Signature []byte `json:"signature" yaml:"signature"` } +// Deprecated +func NewStdSignature(pk cryptotypes.PubKey, sig []byte) StdSignature { + return StdSignature{PubKey: pk, Signature: sig} +} + +// GetSignature returns the raw signature bytes. +func (ss StdSignature) GetSignature() []byte { + return ss.Signature +} + +// GetPubKey returns the public key of a signature as a cryptotypes.PubKey using the +// Amino codec. +func (ss StdSignature) GetPubKey() cryptotypes.PubKey { + return ss.PubKey +} + +// MarshalYAML returns the YAML representation of the signature. +func (ss StdSignature) MarshalYAML() (interface{}, error) { + pk := "" + if ss.PubKey != nil { + pk = ss.PubKey.String() + } + + bz, err := yaml.Marshal(struct { + PubKey string + Signature string + }{ + pk, + fmt.Sprintf("%X", ss.Signature), + }) + if err != nil { + return nil, err + } + + return string(bz), err +} + +func (ss StdSignature) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return codectypes.UnpackInterfaces(ss.PubKey, unpacker) +} + // StdSignatureToSignatureV2 converts a StdSignature to a SignatureV2 func StdSignatureToSignatureV2(cdc *codec.LegacyAmino, sig StdSignature) (signing.SignatureV2, error) { pk := sig.GetPubKey() diff --git a/x/auth/legacy/legacytx/stdtx.go b/x/auth/legacy/legacytx/stdtx.go index c2b60736e..55ec38e60 100644 --- a/x/auth/legacy/legacytx/stdtx.go +++ b/x/auth/legacy/legacytx/stdtx.go @@ -1,10 +1,6 @@ package legacytx import ( - "fmt" - - "gopkg.in/yaml.v2" - "github.com/cosmos/cosmos-sdk/codec/legacy" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -74,55 +70,6 @@ func (fee StdFee) GasPrices() sdk.DecCoins { return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas))) } -// Deprecated -func NewStdSignature(pk cryptotypes.PubKey, sig []byte) StdSignature { - return StdSignature{PubKey: pk, Signature: sig} -} - -// GetSignature returns the raw signature bytes. -func (ss StdSignature) GetSignature() []byte { - return ss.Signature -} - -// GetPubKey returns the public key of a signature as a cryptotypes.PubKey using the -// Amino codec. -func (ss StdSignature) GetPubKey() cryptotypes.PubKey { - return ss.PubKey -} - -// MarshalYAML returns the YAML representation of the signature. -func (ss StdSignature) MarshalYAML() (interface{}, error) { - var ( - bz []byte - pubkey string - err error - ) - - if ss.PubKey != nil { - pubkey, err = sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, ss.GetPubKey()) - if err != nil { - return nil, err - } - } - - bz, err = yaml.Marshal(struct { - PubKey string - Signature string - }{ - PubKey: pubkey, - Signature: fmt.Sprintf("%X", ss.Signature), - }) - if err != nil { - return nil, err - } - - return string(bz), err -} - -func (ss StdSignature) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - return codectypes.UnpackInterfaces(ss.PubKey, unpacker) -} - // StdTx is the legacy transaction format for wrapping a Msg with Fee and Signatures. // It only works with Amino, please prefer the new protobuf Tx in types/tx. // NOTE: the first signature is the fee payer (Signatures must not be nil). diff --git a/x/auth/legacy/legacytx/stdtx_test.go b/x/auth/legacy/legacytx/stdtx_test.go index a702a8284..f1e496ad4 100644 --- a/x/auth/legacy/legacytx/stdtx_test.go +++ b/x/auth/legacy/legacytx/stdtx_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - yaml "gopkg.in/yaml.v2" "github.com/cosmos/cosmos-sdk/codec" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -182,34 +181,6 @@ func TestDefaultTxEncoder(t *testing.T) { require.Equal(t, cdcBytes, encoderBytes) } -func TestStdSignatureMarshalYAML(t *testing.T) { - _, pubKey, _ := testdata.KeyTestPubAddr() - - testCases := []struct { - sig StdSignature - output string - }{ - { - StdSignature{}, - "|\n pubkey: \"\"\n signature: \"\"\n", - }, - { - StdSignature{PubKey: pubKey, Signature: []byte("dummySig")}, - fmt.Sprintf("|\n pubkey: %s\n signature: 64756D6D79536967\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), - }, - { - StdSignature{PubKey: pubKey, Signature: nil}, - fmt.Sprintf("|\n pubkey: %s\n signature: \"\"\n", sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubKey)), - }, - } - - for i, tc := range testCases { - bz, err := yaml.Marshal(tc.sig) - require.NoError(t, err) - require.Equal(t, tc.output, string(bz), "test case #%d", i) - } -} - func TestSignatureV2Conversions(t *testing.T) { _, pubKey, _ := testdata.KeyTestPubAddr() cdc := codec.NewLegacyAmino() diff --git a/x/auth/legacy/v038/types.go b/x/auth/legacy/v038/types.go index b7dedf003..a59098894 100644 --- a/x/auth/legacy/v038/types.go +++ b/x/auth/legacy/v038/types.go @@ -16,6 +16,7 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v034" ) @@ -175,7 +176,7 @@ func (acc BaseAccount) MarshalJSON() ([]byte, error) { } if acc.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, acc.PubKey) + pks, err := legacybech32.MarshalPubKey(legacybech32.AccPK, acc.PubKey) if err != nil { return nil, err } @@ -194,7 +195,7 @@ func (acc *BaseAccount) UnmarshalJSON(bz []byte) error { } if alias.PubKey != "" { - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + pk, err := legacybech32.UnmarshalPubKey(legacybech32.AccPK, alias.PubKey) if err != nil { return err } @@ -241,7 +242,7 @@ func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) { } if bva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, bva.PubKey) + pks, err := legacybech32.MarshalPubKey(legacybech32.AccPK, bva.PubKey) if err != nil { return nil, err } @@ -265,7 +266,7 @@ func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + pk, err = legacybech32.UnmarshalPubKey(legacybech32.AccPK, alias.PubKey) if err != nil { return err } @@ -310,7 +311,7 @@ func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) { } if cva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, cva.PubKey) + pks, err := legacybech32.MarshalPubKey(legacybech32.AccPK, cva.PubKey) if err != nil { return nil, err } @@ -334,7 +335,7 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + pk, err = legacybech32.UnmarshalPubKey(legacybech32.AccPK, alias.PubKey) if err != nil { return err } @@ -376,7 +377,7 @@ func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) { } if dva.PubKey != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, dva.PubKey) + pks, err := legacybech32.MarshalPubKey(legacybech32.AccPK, dva.PubKey) if err != nil { return nil, err } @@ -400,7 +401,7 @@ func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error { ) if alias.PubKey != "" { - pk, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, alias.PubKey) + pk, err = legacybech32.UnmarshalPubKey(legacybech32.AccPK, alias.PubKey) if err != nil { return err } diff --git a/x/auth/testutil/suite.go b/x/auth/testutil/suite.go index 253ce3409..93ffb6b72 100644 --- a/x/auth/testutil/suite.go +++ b/x/auth/testutil/suite.go @@ -226,7 +226,7 @@ func (s *TxConfigTestSuite) TestTxEncodeDecode() { sig := signingtypes.SignatureV2{ PubKey: pubkey, Data: &signingtypes.SingleSignatureData{ - SignMode: signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + SignMode: signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, //nolint:staticcheck Signature: dummySig, }, } diff --git a/x/auth/tx/mode_handler.go b/x/auth/tx/mode_handler.go index f49ee1619..861ab7773 100644 --- a/x/auth/tx/mode_handler.go +++ b/x/auth/tx/mode_handler.go @@ -10,7 +10,7 @@ import ( // DefaultSignModes are the default sign modes enabled for protobuf transactions. var DefaultSignModes = []signingtypes.SignMode{ signingtypes.SignMode_SIGN_MODE_DIRECT, - signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, //nolint:staticcheck } // makeSignModeHandler returns the default protobuf SignModeHandler supporting @@ -26,7 +26,7 @@ func makeSignModeHandler(modes []signingtypes.SignMode) signing.SignModeHandler switch mode { case signingtypes.SignMode_SIGN_MODE_DIRECT: handlers[i] = signModeDirectHandler{} - case signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON: + case signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON: //nolint:staticcheck handlers[i] = signModeLegacyAminoJSONHandler{} default: panic(fmt.Errorf("unsupported sign mode %+v", mode)) diff --git a/x/auth/vesting/types/vesting_account.go b/x/auth/vesting/types/vesting_account.go index 0438a338b..27a77d8fc 100644 --- a/x/auth/vesting/types/vesting_account.go +++ b/x/auth/vesting/types/vesting_account.go @@ -6,6 +6,7 @@ import ( yaml "gopkg.in/yaml.v2" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" @@ -187,32 +188,17 @@ func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { return nil, err } - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: accAddr, AccountNumber: bva.AccountNumber, + PubKey: getPKString(bva), Sequence: bva.Sequence, OriginalVesting: bva.OriginalVesting, DelegatedFree: bva.DelegatedFree, DelegatedVesting: bva.DelegatedVesting, EndTime: bva.EndTime, } - - pk := bva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err + return marshalYaml(out) } // Continuous Vesting Account @@ -314,9 +300,10 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { return nil, err } - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: accAddr, AccountNumber: cva.AccountNumber, + PubKey: getPKString(cva), Sequence: cva.Sequence, OriginalVesting: cva.OriginalVesting, DelegatedFree: cva.DelegatedFree, @@ -324,23 +311,7 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { EndTime: cva.EndTime, StartTime: cva.StartTime, } - - pk := cva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err + return marshalYaml(out) } // Periodic Vesting Account @@ -471,9 +442,10 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { return nil, err } - alias := vestingAccountYAML{ + out := vestingAccountYAML{ Address: accAddr, AccountNumber: pva.AccountNumber, + PubKey: getPKString(pva), Sequence: pva.Sequence, OriginalVesting: pva.OriginalVesting, DelegatedFree: pva.DelegatedFree, @@ -482,23 +454,7 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { StartTime: pva.StartTime, VestingPeriods: pva.VestingPeriods, } - - pk := pva.GetPubKey() - if pk != nil { - pks, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pk) - if err != nil { - return nil, err - } - - alias.PubKey = pks - } - - bz, err := yaml.Marshal(alias) - if err != nil { - return nil, err - } - - return string(bz), err + return marshalYaml(out) } // Delayed Vesting Account @@ -566,3 +522,22 @@ func (dva DelayedVestingAccount) String() string { out, _ := dva.MarshalYAML() return out.(string) } + +type getPK interface { + GetPubKey() cryptotypes.PubKey +} + +func getPKString(g getPK) string { + if pk := g.GetPubKey(); pk != nil { + return pk.String() + } + return "" +} + +func marshalYaml(i interface{}) (interface{}, error) { + bz, err := yaml.Marshal(i) + if err != nil { + return nil, err + } + return string(bz), nil +} diff --git a/x/bank/legacy/v043/store.go b/x/bank/legacy/v043/store.go index 74a560d5e..8f7dbc7b3 100644 --- a/x/bank/legacy/v043/store.go +++ b/x/bank/legacy/v043/store.go @@ -14,7 +14,7 @@ import ( // ref: https://github.com/cosmos/cosmos-sdk/issues/7092 func migrateSupply(store sdk.KVStore, cdc codec.BinaryMarshaler) error { // Old supply was stored as a single blob under the SupplyKey. - var oldSupply types.Supply // nolint:staticcheck + var oldSupply types.Supply err := cdc.UnmarshalBinaryBare(store.Get(v040bank.SupplyKey), &oldSupply) if err != nil { return err diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 42d957346..c7f05a30a 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -77,10 +77,10 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o } // read --pubkey, if empty take it from priv_validator.json - if valPubKeyString, _ := cmd.Flags().GetString(cli.FlagPubKey); valPubKeyString != "" { - valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString) + if val, _ := cmd.Flags().GetString(cli.FlagPubKey); val != "" { + err = clientCtx.JSONMarshaler.UnmarshalJSON([]byte(val), valPubKey) if err != nil { - return errors.Wrap(err, "failed to get consensus node public key") + return errors.Wrap(err, "failed to unmarshal consensus node public key") } } diff --git a/x/slashing/client/cli/cli_test.go b/x/slashing/client/cli/cli_test.go index 41fac414c..84be17b76 100644 --- a/x/slashing/client/cli/cli_test.go +++ b/x/slashing/client/cli/cli_test.go @@ -49,9 +49,9 @@ func (s *IntegrationTestSuite) TearDownSuite() { func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { val := s.network.Validators[0] - - valConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, val.PubKey) + pubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(val.PubKey) s.Require().NoError(err) + pubKeyStr := string(pubKeyBz) testCases := []struct { name string @@ -63,7 +63,7 @@ func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { { "valid address (json output)", []string{ - valConsPubKey, + pubKeyStr, fmt.Sprintf("--%s=json", tmcli.OutputFlag), fmt.Sprintf("--%s=1", flags.FlagHeight), }, @@ -73,7 +73,7 @@ func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { { "valid address (text output)", []string{ - valConsPubKey, + pubKeyStr, fmt.Sprintf("--%s=text", tmcli.OutputFlag), fmt.Sprintf("--%s=1", flags.FlagHeight), }, @@ -145,7 +145,6 @@ slash_fraction_downtime: "0.010000000000000000"`, func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { val := s.network.Validators[0] - testCases := []struct { name string args []string diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 6cb2f803d..361d6b081 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -7,8 +7,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" ) @@ -40,7 +40,7 @@ func GetCmdQuerySigningInfo() *cobra.Command { Short: "Query a validator's signing information", Long: strings.TrimSpace(`Use a validators' consensus public key to find the signing-info for that validator: -$ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdgexxhmz0l8c7sgswl7ulv7aulk364x4g5xsw7sr0k2g5 +$ query slashing signing-info '{"@type":"/cosmos.crypto.ed25519.PubKey","key":"OauFcTKbN5Lx3fJL689cikXBqe+hcp6Y+x0rYUdR9Jk="}' `), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -48,13 +48,13 @@ $ query slashing signing-info cosmosvalconspub1zcjduepqfhvwcmt7p06fvdgexx if err != nil { return err } - queryClient := types.NewQueryClient(clientCtx) - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, args[0]) - if err != nil { + var pk cryptotypes.PubKey + if err := clientCtx.JSONMarshaler.UnmarshalInterfaceJSON([]byte(args[0]), &pk); err != nil { return err } + queryClient := types.NewQueryClient(clientCtx) consAddr := sdk.ConsAddress(pk.Address()) params := &types.QuerySigningInfoRequest{ConsAddress: consAddr.String()} res, err := queryClient.SigningInfo(cmd.Context(), params) diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 36eb8cc24..d5d4a3a18 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -7,7 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" //nolint:staticcheck "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) @@ -29,11 +29,11 @@ func registerQueryRoutes(clientCtx client.Context, r *mux.Router) { ).Methods("GET") } -// http request handler to query signing info +// Deprecated: http request handler to query signing info func signingInfoHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, vars["validatorPubKey"]) + pk, err := legacybech32.UnmarshalPubKey(legacybech32.ConsPK, vars["validatorPubKey"]) if rest.CheckBadRequestError(w, err) { return } diff --git a/x/slashing/simulation/decoder.go b/x/slashing/simulation/decoder.go index b0ebb64ef..6855f6709 100644 --- a/x/slashing/simulation/decoder.go +++ b/x/slashing/simulation/decoder.go @@ -7,13 +7,14 @@ import ( gogotypes "github.com/gogo/protobuf/types" "github.com/cosmos/cosmos-sdk/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/kv" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding slashing type. -func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { +func NewDecodeStore(cdc codec.BinaryMarshaler) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { switch { case bytes.Equal(kvA.Key[:1], types.ValidatorSigningInfoKeyPrefix): @@ -29,10 +30,14 @@ func NewDecodeStore(cdc codec.Marshaler) func(kvA, kvB kv.Pair) string { return fmt.Sprintf("missedA: %v\nmissedB: %v", missedA.Value, missedB.Value) case bytes.Equal(kvA.Key[:1], types.AddrPubkeyRelationKeyPrefix): - var pubKeyA, pubKeyB gogotypes.StringValue - cdc.MustUnmarshalBinaryBare(kvA.Value, &pubKeyA) - cdc.MustUnmarshalBinaryBare(kvB.Value, &pubKeyB) - return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", pubKeyA.Value, pubKeyB.Value) + var pubKeyA, pubKeyB cryptotypes.PubKey + if err := cdc.UnmarshalInterface(kvA.Value, &pubKeyA); err != nil { + panic(fmt.Sprint("Can't unmarshal kvA; ", err)) + } + if err := cdc.UnmarshalInterface(kvB.Value, &pubKeyB); err != nil { + panic(fmt.Sprint("Can't unmarshal kvB; ", err)) + } + return fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", pubKeyA, pubKeyB) default: panic(fmt.Sprintf("invalid slashing key prefix %X", kvA.Key[:1])) diff --git a/x/slashing/simulation/decoder_test.go b/x/slashing/simulation/decoder_test.go index 32fb3f077..271995d9b 100644 --- a/x/slashing/simulation/decoder_test.go +++ b/x/slashing/simulation/decoder_test.go @@ -29,34 +29,35 @@ func TestDecodeStore(t *testing.T) { dec := simulation.NewDecodeStore(cdc) info := types.NewValidatorSigningInfo(consAddr1, 0, 1, time.Now().UTC(), false, 0) - bechPK := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, delPk1) missed := gogotypes.BoolValue{Value: true} + bz, err := cdc.MarshalInterface(delPk1) + require.NoError(t, err) kvPairs := kv.Pairs{ Pairs: []kv.Pair{ {Key: types.ValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshalBinaryBare(&info)}, {Key: types.ValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryBare(&missed)}, - {Key: types.AddrPubkeyRelationKey(delAddr1), Value: cdc.MustMarshalBinaryBare(&gogotypes.StringValue{Value: bechPK})}, - {Key: []byte{0x99}, Value: []byte{0x99}}, + {Key: types.AddrPubkeyRelationKey(delAddr1), Value: bz}, + {Key: []byte{0x99}, Value: []byte{0x99}}, // This test should panic }, } tests := []struct { name string expectedLog string + panics bool }{ - {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info)}, - {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed.Value, missed.Value)}, - {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", bechPK, bechPK)}, - {"other", ""}, + {"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info), false}, + {"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v", missed.Value, missed.Value), false}, + {"AddrPubkeyRelation", fmt.Sprintf("PubKeyA: %s\nPubKeyB: %s", delPk1, delPk1), false}, + {"other", "", true}, } for i, tt := range tests { i, tt := i, tt t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: + if tt.panics { require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: + } else { require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) } }) diff --git a/x/staking/client/cli/cli_test.go b/x/staking/client/cli/cli_test.go index fc270f430..a8d0332d7 100644 --- a/x/staking/client/cli/cli_test.go +++ b/x/staking/client/cli/cli_test.go @@ -42,11 +42,9 @@ func (s *IntegrationTestSuite) SetupSuite() { s.T().Skip("skipping test in unit-tests mode.") } - cfg := network.DefaultConfig() - cfg.NumValidators = 2 - - s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.cfg = network.DefaultConfig() + s.cfg.NumValidators = 2 + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) @@ -82,17 +80,18 @@ func (s *IntegrationTestSuite) TearDownSuite() { } func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { + require := s.Require() val := s.network.Validators[0] consPrivKey := ed25519.GenPrivKey() - consPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, consPrivKey.PubKey()) - s.Require().NoError(err) + consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey()) + require.NoError(err) + require.NotNil(consPubKeyBz) info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err) + require.NoError(err) newAddr := sdk.AccAddress(info.GetPubKey().Address()) - _, err = banktestutil.MsgSendExec( val.ClientCtx, val.Address, @@ -101,7 +100,7 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), ) - s.Require().NoError(err) + require.NoError(err) testCases := []struct { name string @@ -150,7 +149,7 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { { "invalid transaction (missing moniker)", []string{ - fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKey), + fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz), fmt.Sprintf("--%s=%dstake", cli.FlagAmount, sdk.PowerReduction.Int64()), fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity), fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite), @@ -170,7 +169,7 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { { "valid transaction", []string{ - fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKey), + fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz), fmt.Sprintf("--%s=%dstake", cli.FlagAmount, sdk.PowerReduction.Int64()), fmt.Sprintf("--%s=NewValidator", cli.FlagMoniker), fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity), @@ -199,13 +198,15 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() { out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) if tc.expectErr { - s.Require().Error(err) + require.Error(err) } else { - s.Require().NoError(err, out.String()) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + require.NoError(err, "test: %s\noutput: %s", tc.name, out.String()) + err = clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType) + require.NoError(err, out.String(), "test: %s, output\n:", tc.name, out.String()) txResp := tc.respType.(*sdk.TxResponse) - s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + require.Equal(tc.expectedCode, txResp.Code, + "test: %s, output\n:", tc.name, out.String()) } }) } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index b7cd500cf..edcb92f2f 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -58,8 +58,9 @@ func NewCreateValidatorCmd() *cobra.Command { if err != nil { return err } - txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). + WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags()) if err != nil { return err @@ -315,13 +316,16 @@ func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *fl } valAddr := clientCtx.GetFromAddress() - pkStr, _ := fs.GetString(FlagPubKey) - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) + pkStr, err := fs.GetString(FlagPubKey) if err != nil { return txf, nil, err } + var pk cryptotypes.PubKey + if err := clientCtx.JSONMarshaler.UnmarshalInterfaceJSON([]byte(pkStr), &pk); err != nil { + return txf, nil, err + } + moniker, _ := fs.GetString(FlagMoniker) identity, _ := fs.GetString(FlagIdentity) website, _ := fs.GetString(FlagWebsite) @@ -417,7 +421,7 @@ type TxCreateValidatorConfig struct { CommissionMaxChangeRate string MinSelfDelegation string - PubKey string + PubKey cryptotypes.PubKey IP string Website string @@ -489,7 +493,7 @@ func PrepareConfigForTxCreateValidator(flagSet *flag.FlagSet, moniker, nodeID, c } c.NodeID = nodeID - c.PubKey = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey) + c.PubKey = valPubKey c.Website = website c.SecurityContact = securityContact c.Details = details @@ -530,13 +534,6 @@ func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorC } valAddr := clientCtx.GetFromAddress() - pkStr := config.PubKey - - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) - if err != nil { - return txBldr, nil, err - } - description := types.NewDescription( config.Moniker, config.Identity, @@ -564,7 +561,7 @@ func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorC } msg, err := types.NewMsgCreateValidator( - sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation, + sdk.ValAddress(valAddr), config.PubKey, amount, description, commissionRates, minSelfDelegation, ) if err != nil { return txBldr, msg, err diff --git a/x/staking/client/cli/tx_test.go b/x/staking/client/cli/tx_test.go index 7a28aac96..a7eb30fde 100644 --- a/x/staking/client/cli/tx_test.go +++ b/x/staking/client/cli/tx_test.go @@ -7,15 +7,30 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" ) func TestPrepareConfigForTxCreateValidator(t *testing.T) { chainID := "chainID" ip := "1.1.1.1" nodeID := "nodeID" - valPubKey, _ := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, "cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a") + privKey := ed25519.GenPrivKey() + valPubKey := privKey.PubKey() moniker := "DefaultMoniker" + mkTxValCfg := func(amount, commission, commissionMax, commissionMaxChange, minSelfDelegation string) TxCreateValidatorConfig { + return TxCreateValidatorConfig{ + IP: ip, + ChainID: chainID, + NodeID: nodeID, + PubKey: valPubKey, + Moniker: moniker, + Amount: amount, + CommissionRate: commission, + CommissionMaxRate: commissionMax, + CommissionMaxChangeRate: commissionMaxChange, + MinSelfDelegation: minSelfDelegation, + } + } tests := []struct { name string @@ -27,108 +42,38 @@ func TestPrepareConfigForTxCreateValidator(t *testing.T) { fsModify: func(fs *pflag.FlagSet) { return }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Moniker: moniker, - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.01", "1"), + }, { name: "Custom amount", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagAmount, "2000stake") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: "2000stake", - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg("2000stake", "0.1", "0.2", "0.01", "1"), + }, { name: "Custom commission rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionRate, "0.54") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.54", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.54", "0.2", "0.01", "1"), + }, { name: "Custom commission max rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionMaxRate, "0.89") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.89", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "1", - }, - }, - { + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.89", "0.01", "1"), + }, { name: "Custom commission max change rate", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagCommissionMaxChangeRate, "0.55") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.55", - MinSelfDelegation: "1", - }, + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.55", "1"), }, { name: "Custom min self delegations", fsModify: func(fs *pflag.FlagSet) { fs.Set(FlagMinSelfDelegation, "0.33") }, - expectedCfg: TxCreateValidatorConfig{ - IP: ip, - Moniker: moniker, - ChainID: chainID, - NodeID: nodeID, - PubKey: sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey), - Amount: defaultAmount, - CommissionRate: "0.1", - CommissionMaxRate: "0.2", - CommissionMaxChangeRate: "0.01", - MinSelfDelegation: "0.33", - }, + expectedCfg: mkTxValCfg(defaultAmount, "0.1", "0.2", "0.01", "0.33"), }, } diff --git a/x/staking/legacy/v034/types.go b/x/staking/legacy/v034/types.go index 539e6534b..a69f4cc9b 100644 --- a/x/staking/legacy/v034/types.go +++ b/x/staking/legacy/v034/types.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" ) const ( @@ -138,7 +139,7 @@ type ( ) func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) + bechConsPubKey, err := legacybech32.MarshalPubKey(legacybech32.ConsPK, v.ConsPubKey) if err != nil { return nil, err } @@ -164,7 +165,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := legacy.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) + consPubKey, err := legacybech32.UnmarshalPubKey(legacybech32.ConsPK, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/legacy/v036/types.go b/x/staking/legacy/v036/types.go index 44cf3746d..5e73da243 100644 --- a/x/staking/legacy/v036/types.go +++ b/x/staking/legacy/v036/types.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v034" ) @@ -87,7 +88,7 @@ func NewGenesisState( } func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) + bechConsPubKey, err := legacybech32.MarshalPubKey(legacybech32.ConsPK, v.ConsPubKey) if err != nil { return nil, err } @@ -112,7 +113,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := legacy.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) + consPubKey, err := legacybech32.UnmarshalPubKey(legacybech32.ConsPK, bv.ConsPubKey) if err != nil { return err } diff --git a/x/staking/legacy/v038/types.go b/x/staking/legacy/v038/types.go index e11157d0e..f8e08acbd 100644 --- a/x/staking/legacy/v038/types.go +++ b/x/staking/legacy/v038/types.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v034" v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v036" ) @@ -112,7 +113,7 @@ func NewGenesisState( // MarshalJSON marshals the validator to JSON using Bech32 func (v Validator) MarshalJSON() ([]byte, error) { - bechConsPubKey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, v.ConsPubKey) + bechConsPubKey, err := legacybech32.MarshalPubKey(legacybech32.ConsPK, v.ConsPubKey) if err != nil { return nil, err } @@ -138,7 +139,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { if err := legacy.Cdc.UnmarshalJSON(data, bv); err != nil { return err } - consPubKey, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, bv.ConsPubKey) + consPubKey, err := legacybech32.UnmarshalPubKey(legacybech32.ConsPK, bv.ConsPubKey) if err != nil { return err }