mirror of
https://github.com/libp2p/go-libp2p-core.git
synced 2025-04-28 17:10:14 +08:00
feat: support encoding/decoding peer IDs as CIDs in text (#41)
What: 1. Supports decoding CIDs (of libp2p keys) as peer IDs (https://github.com/libp2p/specs/issues/216) 2. Continues to encode peer IDs as base58 multihashes by default. 3. Adds functions for converting between peer IDs and CIDs. 4. Deprecates IDB58{Decode,Encode}, replacing them with {Decode,Encode}. Why: 1. We _need_ to support multibase somehow, so we can put peer IDs in domains. 2. This makes peer IDs fully self describing. That is, the CID itself indicates that it's a hash of a libp2p public key. 3. It's much easier to upgrade wire protocols than text. This change punts pids-as-cids on the wire down the road but that's something we can revisit if it ever becomes relevant. See https://github.com/libp2p/specs/issues/111 for context. Deviations from that issue: * This _retains_ the current peer ID inlining of ed25519 keys. That turned out to be a nightmare, one I'd like to punt a bit more down the road. * Likewise, this _punts_ the question of embedding the multi-hash algorithm in the public key.
This commit is contained in:
commit
ba9101b589
73
peer/peer.go
73
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()
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user