From 7c709122635aab33325b9e0454a75bfdef0df034 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Wed, 31 Jul 2019 17:47:18 +0200 Subject: [PATCH] Merge PR #4790: Fix multisig output --- .pending/bugfixes/keys/_4338-fix-multisig-o | 1 + crypto/keys/output.go | 59 ++++++++++----------- crypto/keys/output_test.go | 30 +++++++++++ crypto/keys/types.go | 23 ++++++++ crypto/keys/types_test.go | 5 +- 5 files changed, 82 insertions(+), 36 deletions(-) create mode 100644 .pending/bugfixes/keys/_4338-fix-multisig-o create mode 100644 crypto/keys/output_test.go diff --git a/.pending/bugfixes/keys/_4338-fix-multisig-o b/.pending/bugfixes/keys/_4338-fix-multisig-o new file mode 100644 index 0000000000..5f41751394 --- /dev/null +++ b/.pending/bugfixes/keys/_4338-fix-multisig-o @@ -0,0 +1 @@ +#4338 fix multisig key output for CLI \ No newline at end of file diff --git a/crypto/keys/output.go b/crypto/keys/output.go index 22a614ddbc..809715df67 100644 --- a/crypto/keys/output.go +++ b/crypto/keys/output.go @@ -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" @@ -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. @@ -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 { diff --git a/crypto/keys/output_test.go b/crypto/keys/output_test.go new file mode 100644 index 0000000000..1bc0f403f5 --- /dev/null +++ b/crypto/keys/output_test.go @@ -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]) +} diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 89e59da615..c8424b9692 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -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") } @@ -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 @@ -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") } @@ -211,6 +226,8 @@ 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"` @@ -218,6 +235,7 @@ type multiInfo struct { PubKeys []multisigPubKeyInfo `json:"pubkeys"` } +// NewMultiInfo creates a new multiInfo instance func NewMultiInfo(name string, pub crypto.PubKey) Info { multiPK := pub.(multisig.PubKeyMultisigThreshold) @@ -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") } diff --git a/crypto/keys/types_test.go b/crypto/keys/types_test.go index feb4131c2d..3b368aa2e6 100644 --- a/crypto/keys/types_test.go +++ b/crypto/keys/types_test.go @@ -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()