Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto/keyring: change addrKey to store chain-agnostic addresses #5858

Merged
merged 4 commits into from
Mar 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ and provided directly the IAVL store.
* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`.
* (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis`
to now accept a `codec.JSONMarshaler` for modular serialization of genesis state.
* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op.
* (crypto/keyring) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's `Update()` function is now no-op.
* (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions.
* (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface.
* (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and
`Result` from the execution.
* (crypto/keys) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keybase/`.
* (crypto/keyring) [\#5866](https://github.com/cosmos/cosmos-sdk/pull/5866) Move `Keyring` and `Keybase` implementations and their associated types from `crypto/keys/` to `crypto/keyring/`.
* (crypto) [\#5880](https://github.com/cosmos/cosmos-sdk/pull/5880) Merge `crypto/keys/mintkey` into `crypto`.
* (crypto/keyring) [\#5858](https://github.com/cosmos/cosmos-sdk/pull/5858) Make Keyring store keys by name and address's hexbytes representation.

### Features

Expand All @@ -85,7 +86,7 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state

* (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied.
* (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist.
* (crypto/keys) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures
* (crypto/keyring) [\#5844](https://github.com/cosmos/cosmos-sdk/pull/5844) Keybase/Keyring `Sign()` methods no longer decode amino signatures
when method receivers are offline/multisig keys.

### State Machine Breaking
Expand Down
2 changes: 1 addition & 1 deletion client/keys/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo
switch output {
case OutputFormatText:
cmd.PrintErrln()
printKeyInfo(info, keyring.Bech32KeyOutput)
printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput)

// print mnemonic unless requested not to.
if showMnemonic {
Expand Down
4 changes: 2 additions & 2 deletions client/keys/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ func runListCmd(cmd *cobra.Command, _ []string) error {
return err
}

cmd.SetOut(cmd.OutOrStdout())
if !viper.GetBool(flagListNames) {
printInfos(infos)
printInfos(cmd.OutOrStdout(), infos)
return nil
}

cmd.SetOut(cmd.OutOrStdout())
for _, info := range infos {
cmd.Println(info.GetName())
}
Expand Down
18 changes: 10 additions & 8 deletions client/keys/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -83,38 +84,39 @@ hexadecimal into bech32 cosmos prefixed format and vice versa.
return cmd
}

func parseKey(_ *cobra.Command, args []string) error {
func parseKey(cmd *cobra.Command, args []string) error {
addr := strings.TrimSpace(args[0])
outstream := cmd.OutOrStdout()
if len(addr) == 0 {
return errors.New("couldn't parse empty input")
}
if !(runFromBech32(addr) || runFromHex(addr)) {
if !(runFromBech32(outstream, addr) || runFromHex(outstream, addr)) {
return errors.New("couldn't find valid bech32 nor hex data")
}
return nil
}

// print info from bech32
func runFromBech32(bech32str string) bool {
func runFromBech32(w io.Writer, bech32str string) bool {
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
if err != nil {
return false
}
displayParseKeyInfo(newHexOutput(hrp, bz))
displayParseKeyInfo(w, newHexOutput(hrp, bz))
return true
}

// print info from hex
func runFromHex(hexstr string) bool {
func runFromHex(w io.Writer, hexstr string) bool {
bz, err := hex.DecodeString(hexstr)
if err != nil {
return false
}
displayParseKeyInfo(newBech32Output(bz))
displayParseKeyInfo(w, newBech32Output(bz))
return true
}

func displayParseKeyInfo(stringer fmt.Stringer) {
func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer) {
var out []byte
var err error

Expand All @@ -136,5 +138,5 @@ func displayParseKeyInfo(stringer fmt.Stringer) {
panic(err)
}

fmt.Println(string(out))
fmt.Fprintln(w, string(out))
}
2 changes: 1 addition & 1 deletion client/keys/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestParseKey(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.wantErr, parseKey(nil, tt.args) != nil)
require.Equal(t, tt.wantErr, parseKey(ParseKeyStringCommand(), tt.args) != nil)
})
}
}
40 changes: 28 additions & 12 deletions client/keys/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ const (
// ShowKeysCmd shows key information for a given key name.
func ShowKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show [name [name...]]",
Short: "Show key info for the given name",
Long: `Return public details of a single local key. If multiple names are
provided, then an ephemeral multisig key will be created under the name "multi"
Use: "show [name_or_address [name_or_address...]]",
Short: "Retrieve key information by name or address",
Long: `Display keys details. If multiple names or addresses are provided,
then an ephemeral multisig key will be created under the name "multi"
consisting of all the keys provided by name and multisig threshold.`,
Args: cobra.MinimumNArgs(1),
RunE: runShowCmd,
Expand All @@ -62,16 +62,16 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
return err
}
if len(args) == 1 {
info, err = kb.Get(args[0])
info, err = fetchKey(kb, args[0])
if err != nil {
return err
return fmt.Errorf("%s is not a valid name or address: %v", args[0], err)
}
} else {
pks := make([]tmcrypto.PubKey, len(args))
for i, keyName := range args {
info, err := kb.Get(keyName)
for i, keyref := range args {
info, err := fetchKey(kb, keyref)
if err != nil {
return err
return fmt.Errorf("%s is not a valid name or address: %v", keyref, err)
}

pks[i] = info.GetPubKey()
Expand Down Expand Up @@ -112,11 +112,11 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {

switch {
case isShowAddr:
printKeyAddress(info, bechKeyOut)
printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut)
case isShowPubKey:
printPubKey(info, bechKeyOut)
printPubKey(cmd.OutOrStdout(), info, bechKeyOut)
default:
printKeyInfo(info, bechKeyOut)
printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut)
}

if isShowDevice {
Expand All @@ -142,6 +142,22 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
return nil
}

func fetchKey(kb keyring.Keybase, keyref string) (keyring.Info, error) {
info, err := kb.Get(keyref)
alessio marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
accAddr, err := sdk.AccAddressFromBech32(keyref)
if err != nil {
return info, err
}

info, err = kb.GetByAddress(accAddr)
if err != nil {
alessio marked this conversation as resolved.
Show resolved Hide resolved
return info, errors.New("key not found")
}
}
return info, nil
}

func validateMultisigThreshold(k, nKeys int) error {
if k <= 0 {
return fmt.Errorf("threshold must be a positive integer")
Expand Down
10 changes: 8 additions & 2 deletions client/keys/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func Test_runShowCmd(t *testing.T) {
runningUnattended := isRunningUnattended()
cmd := ShowKeysCmd()
mockIn, _, _ := tests.ApplyMockIO(cmd)
require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "The specified item could not be found in the keyring")
require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "The specified item could not be found in the keyring")
require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "invalid is not a valid name or address: decoding bech32 failed: invalid bech32 string length 7")
require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "invalid1 is not a valid name or address: decoding bech32 failed: invalid index of 1")

// Prepare a key base
// Now add a temporary keybase
Expand Down Expand Up @@ -78,7 +78,13 @@ func Test_runShowCmd(t *testing.T) {
if runningUnattended {
mockIn.Reset("testpass1\n")
}

// try fetch by name
require.NoError(t, runShowCmd(cmd, []string{fakeKeyName1}))
// try fetch by addr
info, err := kb.Get(fakeKeyName1)
require.NoError(t, err)
require.NoError(t, runShowCmd(cmd, []string{info.GetAddress().String()}))

// Now try multisig key - set bech to acc
viper.Set(FlagBechPrefix, sdk.PrefixAccount)
Expand Down
27 changes: 14 additions & 13 deletions client/keys/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package keys

import (
"fmt"
"io"
"path/filepath"

"github.com/99designs/keyring"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
yaml "gopkg.in/yaml.v2"
"gopkg.in/yaml.v2"

"github.com/cosmos/cosmos-sdk/client/flags"
cryptokeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
Expand Down Expand Up @@ -37,15 +38,15 @@ func getLazyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption)
return cryptokeyring.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil
}

func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(keyInfo)
if err != nil {
panic(err)
}

switch viper.Get(cli.OutputFlag) {
case OutputFormatText:
printTextInfos([]cryptokeyring.KeyOutput{ko})
printTextInfos(w, []cryptokeyring.KeyOutput{ko})

case OutputFormatJSON:
var out []byte
Expand All @@ -59,19 +60,19 @@ func printKeyInfo(keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
panic(err)
}

fmt.Println(string(out))
fmt.Fprintln(w, string(out))
}
}

func printInfos(infos []cryptokeyring.Info) {
func printInfos(w io.Writer, infos []cryptokeyring.Info) {
kos, err := cryptokeyring.Bech32KeysOutput(infos)
if err != nil {
panic(err)
}

switch viper.Get(cli.OutputFlag) {
case OutputFormatText:
printTextInfos(kos)
printTextInfos(w, kos)

case OutputFormatJSON:
var out []byte
Expand All @@ -86,34 +87,34 @@ func printInfos(infos []cryptokeyring.Info) {
if err != nil {
panic(err)
}
fmt.Printf("%s", out)
fmt.Fprintf(w, "%s", out)
}
}

func printTextInfos(kos []cryptokeyring.KeyOutput) {
func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) {
out, err := yaml.Marshal(&kos)
if err != nil {
panic(err)
}
fmt.Println(string(out))
fmt.Fprintln(w, string(out))
}

func printKeyAddress(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
func printKeyAddress(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}

fmt.Println(ko.Address)
fmt.Fprintln(w, ko.Address)
}

func printPubKey(info cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
func printPubKey(w io.Writer, info cryptokeyring.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}

fmt.Println(ko.PubKey)
fmt.Fprintln(w, ko.PubKey)
}

func isRunningUnattended() bool {
Expand Down
14 changes: 10 additions & 4 deletions crypto/keyring/db_keybase.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keyring

import (
"encoding/hex"
"fmt"
"reflect"
"strings"
Expand Down Expand Up @@ -126,7 +127,7 @@ func (kb dbKeybase) Get(name string) (Info, error) {
// GetByAddress returns Info based on a provided AccAddress. An error is returned
// if the address does not exist.
func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) {
ik, err := kb.db.Get(addrKey(address))
ik, err := kb.db.Get(addrStringKey(address))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -344,7 +345,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
batch := kb.db.NewBatch()
defer batch.Close()

batch.Delete(addrKey(info.GetAddress()))
batch.Delete(addrStringKey(info.GetAddress()))
batch.Delete(infoKey(name))

return batch.WriteSync()
Expand Down Expand Up @@ -414,13 +415,18 @@ func (kb dbKeybase) writeInfo(name string, info Info) {
kb.db.SetSync(key, serializedInfo)

// store a pointer to the infokey by address for fast lookup
kb.db.SetSync(addrKey(info.GetAddress()), key)
kb.db.SetSync(addrStringKey(info.GetAddress()), key)
}

func addrKey(address types.AccAddress) []byte {
// this is to be removed together with dbKeybase and the old Keybase interface
func addrStringKey(address types.AccAddress) []byte {
return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix))
}

func addrHexKey(address types.AccAddress) []byte {
return []byte(fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix))
}

func infoKey(name string) []byte {
return []byte(fmt.Sprintf("%s.%s", name, infoSuffix))
}
Loading