From dc718fa4dab1866476fd9f379718fdd619455a4f Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jul 2019 14:25:48 -0700 Subject: [PATCH 1/2] feat: support encoding/decoding peer IDs as CIDs _in text_ --- peer/peer.go | 73 ++++++++++++++++++++++++++++++++++++++++++----- peer/peer_test.go | 45 +++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/peer/peer.go b/peer/peer.go index edef635c..9ae0a844 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -5,7 +5,9 @@ import ( "encoding/hex" "errors" "fmt" + "strings" + cid "github.com/ipfs/go-cid" ic "github.com/libp2p/go-libp2p-core/crypto" b58 "github.com/mr-tron/base58/base58" mh "github.com/multiformats/go-multihash" @@ -129,23 +131,24 @@ func IDFromBytes(b []byte) (ID, error) { return ID(b), nil } -// IDB58Decode accepts a base58-encoded multihash representing a peer ID -// and returns the decoded ID if the input is valid. +// IDB58Decode decodes a peer ID. +// +// Deprecated: Use Decode. func IDB58Decode(s string) (ID, error) { - m, err := mh.FromB58String(s) - if err != nil { - return "", err - } - return ID(m), err + return Decode(s) } // IDB58Encode returns the base58-encoded multihash representation of the ID. +// +// Deprecated: Use Encode. func IDB58Encode(id ID) string { return b58.Encode([]byte(id)) } // IDHexDecode accepts a hex-encoded multihash representing a peer ID // and returns the decoded ID if the input is valid. +// +// Deprecated: Don't raw-hex encode peer IDs, use base16 CIDs. func IDHexDecode(s string) (ID, error) { m, err := mh.FromHexString(s) if err != nil { @@ -155,10 +158,66 @@ func IDHexDecode(s string) (ID, error) { } // IDHexEncode returns the hex-encoded multihash representation of the ID. +// +// Deprecated: Don't raw-hex encode peer IDs, use base16 CIDs. func IDHexEncode(id ID) string { return hex.EncodeToString([]byte(id)) } +// Decode accepts an encoded peer ID and returns the decoded ID if the input is +// valid. +// +// The encoded peer ID can either be a CID of a key or a raw multihash (identity +// or sha256-256). +func Decode(s string) (ID, error) { + if strings.HasPrefix(s, "Qm") || strings.HasPrefix(s, "1") { + // base58 encoded sha256 or identity multihash + m, err := mh.FromB58String(s) + if err != nil { + return "", fmt.Errorf("failed to parse peer ID: %s", err) + } + return ID(m), nil + } + + c, err := cid.Decode(s) + if err != nil { + return "", fmt.Errorf("failed to parse peer ID: %s", err) + } + return FromCid(c) +} + +// Encode encodes a peer ID as a string. +// +// At the moment, it base58 encodes the peer ID but, in the future, it will +// switch to encoding it as a CID by default. +func Encode(id ID) string { + return IDB58Encode(id) +} + +// FromCid converts a CID to a peer ID, if possible. +func FromCid(c cid.Cid) (ID, error) { + ty := c.Type() + if ty != cid.Libp2pKey { + s := cid.CodecToStr[ty] + if s == "" { + s = fmt.Sprintf("[unknown multicodec %d]", ty) + } + return "", fmt.Errorf("can't convert CID of type %s to a peer ID", s) + } + return ID(c.Hash()), nil +} + +// ToCid encodes a peer ID as a CID of the public key. +// +// If the peer ID is invalid (e.g., empty), this will return the empty CID. +func ToCid(id ID) cid.Cid { + m, err := mh.Cast([]byte(id)) + if err != nil { + return cid.Cid{} + } + return cid.NewCidV1(cid.Libp2pKey, m) +} + // IDFromPublicKey returns the Peer ID corresponding to the public key pk. func IDFromPublicKey(pk ic.PubKey) (ID, error) { b, err := pk.Bytes() diff --git a/peer/peer_test.go b/peer/peer_test.go index 757f085c..b203a7ad 100644 --- a/peer/peer_test.go +++ b/peer/peer_test.go @@ -153,6 +153,51 @@ func TestIDMatchesPrivateKey(t *testing.T) { test(man) } +func TestIDEncoding(t *testing.T) { + test := func(ks keyset) { + p1, err := IDB58Decode(ks.hpkp) + if err != nil { + t.Fatal(err) + } + + if ks.hpk != string(p1) { + t.Error("p1 and hpk differ") + } + + c := ToCid(p1) + p2, err := FromCid(c) + if err != nil || p1 != p2 { + t.Fatal("failed to round-trip through CID:", err) + } + p3, err := Decode(c.String()) + if err != nil { + t.Fatal(err) + } + if p3 != p1 { + t.Fatal("failed to round trip through CID string") + } + + if ks.hpkp != Encode(p1) { + t.Fatal("should always encode peer IDs as base58 by default") + } + } + + test(gen1) + test(gen2) + test(man) + + exampleCid := "bafkreifoybygix7fh3r3g5rqle3wcnhqldgdg4shzf4k3ulyw3gn7mabt4" + _, err := Decode(exampleCid) + if err == nil { + t.Fatal("should refuse to decode a non-peer ID CID") + } + + c := ToCid("") + if c.Defined() { + t.Fatal("cid of empty peer ID should have been undefined") + } +} + func TestPublicKeyExtraction(t *testing.T) { t.Skip("disabled until libp2p/go-libp2p-crypto#51 is fixed") // Happy path From 0bdeee6376482efc43ea129f7fe2ec64799d0dff Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 2 Oct 2019 08:27:27 -0700 Subject: [PATCH 2/2] ci: bump to go 1.12 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 63e938d6..dba28730 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ os: language: go go: - - 1.11.x + - 1.12.x env: global: