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

fix multisig output #4790

Merged
merged 4 commits into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
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
63 changes: 29 additions & 34 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 int `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 int `json:"weight" yaml:"weight"`
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
}

// 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 All @@ -100,10 +95,10 @@ func Bech32KeyOutput(info Info) (KeyOutput, error) {
return KeyOutput{}, err
}

pubKeys[i] = multisigPubKeyOutput{accAddr.String(), bechPubKey, pk.Weight}
pubKeys[i] = multisigPubKeyOutput{accAddr.String(), bechPubKey, int(pk.Weight)}
}

ko.Threshold = mInfo.Threshold
ko.Threshold = int(mInfo.Threshold)
ko.PubKeys = 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