Skip to content

Commit

Permalink
Merge PR cosmos#4790: Fix multisig output
Browse files Browse the repository at this point in the history
  • Loading branch information
fedekunze authored and alexanderbez committed Jul 31, 2019
1 parent 8c989fd commit 7c70912
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 36 deletions.
1 change: 1 addition & 0 deletions .pending/bugfixes/keys/_4338-fix-multisig-o
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#4338 fix multisig key output for CLI
59 changes: 27 additions & 32 deletions crypto/keys/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@ import (
// KeyOutput defines a structure wrapping around an Info object used for output
// functionality.
type KeyOutput struct {
Name string `json:"name"`
Type string `json:"type"`
Address string `json:"address"`
PubKey string `json:"pubkey"`
Mnemonic string `json:"mnemonic,omitempty"`
Threshold uint `json:"threshold,omitempty"`
PubKeys []multisigPubKeyOutput `json:"pubkeys,omitempty"`
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"`
}

// NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys
func NewKeyOutput(name, keyType, address, pubkey string) KeyOutput {
return KeyOutput{
Name: name,
Type: keyType,
Address: address,
PubKey: pubkey,
}
}

type multisigPubKeyOutput struct {
Address string `json:"address"`
PubKey string `json:"pubkey"`
Weight uint `json:"weight"`
Address string `json:"address" yaml:"address"`
PubKey string `json:"pubkey" yaml:"pubkey"`
Weight uint `json:"weight" yaml:"weight"`
}

// Bech32KeysOutput returns a slice of KeyOutput objects, each with the "acc"
Expand Down Expand Up @@ -47,12 +57,7 @@ func Bech32ConsKeyOutput(keyInfo Info) (KeyOutput, error) {
return KeyOutput{}, err
}

return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: consAddr.String(),
PubKey: bechPubKey,
}, nil
return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), consAddr.String(), bechPubKey), nil
}

// Bech32ValKeyOutput create a KeyOutput in with "val" Bech32 prefixes.
Expand All @@ -64,32 +69,22 @@ func Bech32ValKeyOutput(keyInfo Info) (KeyOutput, error) {
return KeyOutput{}, err
}

return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: valAddr.String(),
PubKey: bechPubKey,
}, nil
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(info Info) (KeyOutput, error) {
accAddr := sdk.AccAddress(info.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyAccPub(info.GetPubKey())
func Bech32KeyOutput(keyInfo Info) (KeyOutput, error) {
accAddr := sdk.AccAddress(keyInfo.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyAccPub(keyInfo.GetPubKey())
if err != nil {
return KeyOutput{}, err
}

ko := KeyOutput{
Name: info.GetName(),
Type: info.GetType().String(),
Address: accAddr.String(),
PubKey: bechPubKey,
}
ko := NewKeyOutput(keyInfo.GetName(), keyInfo.GetType().String(), accAddr.String(), bechPubKey)

if mInfo, ok := info.(multiInfo); ok {
if mInfo, ok := keyInfo.(*multiInfo); ok {
pubKeys := make([]multisigPubKeyOutput, len(mInfo.PubKeys))

for i, pk := range mInfo.PubKeys {
Expand Down
30 changes: 30 additions & 0 deletions crypto/keys/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package keys

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/multisig"
"github.com/tendermint/tendermint/crypto/secp256k1"
)

func TestBech32KeysOutput(t *testing.T) {
tmpKey := secp256k1.GenPrivKey().PubKey()
bechTmpKey := sdk.MustBech32ifyAccPub(tmpKey)
tmpAddr := sdk.AccAddress(tmpKey.Address().Bytes())

multisigPks := multisig.NewPubKeyMultisigThreshold(1, []crypto.PubKey{tmpKey})
multiInfo := NewMultiInfo("multisig", multisigPks)
accAddr := sdk.AccAddress(multiInfo.GetPubKey().Address().Bytes())
bechPubKey := sdk.MustBech32ifyAccPub(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})
require.NoError(t, err)
require.Equal(t, expectedOutput, outputs[0])
}
23 changes: 23 additions & 0 deletions crypto/keys/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,27 @@ func newLocalInfo(name string, pub crypto.PubKey, privArmor string) Info {
}
}

// GetType implements Info interface
func (i localInfo) GetType() KeyType {
return TypeLocal
}

// GetType implements Info interface
func (i localInfo) GetName() string {
return i.Name
}

// GetType implements Info interface
func (i localInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}

// GetType implements Info interface
func (i localInfo) GetAddress() types.AccAddress {
return i.PubKey.Address().Bytes()
}

// GetType implements Info interface
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
}
Expand All @@ -153,22 +158,27 @@ func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params) Info {
}
}

// GetType implements Info interface
func (i ledgerInfo) GetType() KeyType {
return TypeLedger
}

// GetName implements Info interface
func (i ledgerInfo) GetName() string {
return i.Name
}

// GetPubKey implements Info interface
func (i ledgerInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}

// GetAddress implements Info interface
func (i ledgerInfo) GetAddress() types.AccAddress {
return i.PubKey.Address().Bytes()
}

// GetPath implements Info interface
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
tmp := i.Path
return &tmp, nil
Expand All @@ -187,22 +197,27 @@ func newOfflineInfo(name string, pub crypto.PubKey) Info {
}
}

// GetType implements Info interface
func (i offlineInfo) GetType() KeyType {
return TypeOffline
}

// GetName implements Info interface
func (i offlineInfo) GetName() string {
return i.Name
}

// GetPubKey implements Info interface
func (i offlineInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}

// GetAddress implements Info interface
func (i offlineInfo) GetAddress() types.AccAddress {
return i.PubKey.Address().Bytes()
}

// GetPath implements Info interface
func (i offlineInfo) GetPath() (*hd.BIP44Params, error) {
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
}
Expand All @@ -211,13 +226,16 @@ type multisigPubKeyInfo struct {
PubKey crypto.PubKey `json:"pubkey"`
Weight uint `json:"weight"`
}

// multiInfo is the public information about a multisig key
type multiInfo struct {
Name string `json:"name"`
PubKey crypto.PubKey `json:"pubkey"`
Threshold uint `json:"threshold"`
PubKeys []multisigPubKeyInfo `json:"pubkeys"`
}

// NewMultiInfo creates a new multiInfo instance
func NewMultiInfo(name string, pub crypto.PubKey) Info {
multiPK := pub.(multisig.PubKeyMultisigThreshold)

Expand All @@ -235,22 +253,27 @@ func NewMultiInfo(name string, pub crypto.PubKey) Info {
}
}

// GetType implements Info interface
func (i multiInfo) GetType() KeyType {
return TypeMulti
}

// GetName implements Info interface
func (i multiInfo) GetName() string {
return i.Name
}

// GetPubKey implements Info interface
func (i multiInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}

// GetAddress implements Info interface
func (i multiInfo) GetAddress() types.AccAddress {
return i.PubKey.Address().Bytes()
}

// GetPath implements Info interface
func (i multiInfo) GetPath() (*hd.BIP44Params, error) {
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
}
Expand Down
5 changes: 1 addition & 4 deletions crypto/keys/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ func Test_writeReadLedgerInfo(t *testing.T) {
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
copy(tmpKey[:], bz)

lInfo := ledgerInfo{
"some_name",
tmpKey,
*hd.NewFundraiserParams(5, types.CoinType, 1)}
lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1))
assert.Equal(t, TypeLedger, lInfo.GetType())

path, err := lInfo.GetPath()
Expand Down

0 comments on commit 7c70912

Please sign in to comment.