From 16bbe1cf14c088304aa4accd82c0fe7e8dd5c371 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Sun, 10 Nov 2019 22:17:41 -0800 Subject: [PATCH 1/3] Add a command to read a cid from an array of bytes --- cid.go | 71 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/cid.go b/cid.go index d88b661..52e9932 100644 --- a/cid.go +++ b/cid.go @@ -290,36 +290,16 @@ func uvError(read int) error { // Please use decode when parsing a regular Cid string, as Cast does not // expect multibase-encoded data. Cast accepts the output of Cid.Bytes(). func Cast(data []byte) (Cid, error) { - if len(data) == 34 && data[0] == 18 && data[1] == 32 { - h, err := mh.Cast(data) - if err != nil { - return Undef, err - } - - return NewCidV0(h), nil - } - - vers, n := binary.Uvarint(data) - if err := uvError(n); err != nil { - return Undef, err - } - - if vers != 1 { - return Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers) - } - - _, cn := binary.Uvarint(data[n:]) - if err := uvError(cn); err != nil { - return Undef, err - } - - rest := data[n+cn:] - h, err := mh.Cast(rest) + nr, c, err := CidFromBytes(data) if err != nil { return Undef, err } - return Cid{string(data[0 : n+cn+len(h)])}, nil + if nr != len(data) { + return Undef, fmt.Errorf("trailing bytes in data buffer passed to cid Cast") + } + + return c, nil } // UnmarshalBinary is equivalent to Cast(). It implements the @@ -601,3 +581,42 @@ func PrefixFromBytes(buf []byte) (Prefix, error) { MhLength: int(mhlen), }, nil } + +func CidFromBytes(data []byte) (int, Cid, error) { + if len(data) > 2 && data[0] == 18 && data[1] == 32 { + if len(data) < 34 { + return 0, Undef, fmt.Errorf("not enough bytes for cid v0") + } + + h, err := mh.Cast(data[:34]) + if err != nil { + return 0, Undef, err + } + + return 34, NewCidV0(h), nil + } + + vers, n := binary.Uvarint(data) + if err := uvError(n); err != nil { + return 0, Undef, err + } + + if vers != 1 { + return 0, Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers) + } + + _, cn := binary.Uvarint(data[n:]) + if err := uvError(cn); err != nil { + return 0, Undef, err + } + + mhr := mh.NewReader(bytes.NewReader(data[n+cn:])) + h, err := mhr.ReadMultihash() + if err != nil { + return 0, Undef, err + } + + l := n + cn + len(h) + + return l, Cid{string(data[0:l])}, nil +} From cf8cf8856e8a267684fe42b562efff8e940d5c90 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 11 Nov 2019 16:33:49 -0800 Subject: [PATCH 2/3] Use optimized multihash method for parsing --- cid.go | 5 ++--- go.mod | 4 +++- go.sum | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cid.go b/cid.go index 52e9932..6e27d52 100644 --- a/cid.go +++ b/cid.go @@ -610,13 +610,12 @@ func CidFromBytes(data []byte) (int, Cid, error) { return 0, Undef, err } - mhr := mh.NewReader(bytes.NewReader(data[n+cn:])) - h, err := mhr.ReadMultihash() + mhnr, _, err := mh.MHFromBytes(data[n+cn:]) if err != nil { return 0, Undef, err } - l := n + cn + len(h) + l := n + cn + mhnr return l, Cid{string(data[0:l])}, nil } diff --git a/go.mod b/go.mod index b250632..4644bc8 100644 --- a/go.mod +++ b/go.mod @@ -2,5 +2,7 @@ module github.com/ipfs/go-cid require ( github.com/multiformats/go-multibase v0.0.1 - github.com/multiformats/go-multihash v0.0.8 + github.com/multiformats/go-multihash v0.0.9 ) + +go 1.13 diff --git a/go.sum b/go.sum index d6db5f6..bded98b 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPk github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.9 h1:aoijQXYYl7Xtb2pUUP68R+ys1TlnlR3eX6wmozr0Hp4= +github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= From d93d4baeabdb7622aa2680e1c4afddbbb55d5071 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 11 Nov 2019 16:48:19 -0800 Subject: [PATCH 3/3] add a simple test for reading cids from a buffer --- cid_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/cid_test.go b/cid_test.go index 1c181f9..c64b569 100644 --- a/cid_test.go +++ b/cid_test.go @@ -515,3 +515,37 @@ func BenchmarkStringV1(b *testing.B) { b.FailNow() } } + +func TestReadCidsFromBuffer(t *testing.T) { + cidstr := []string{ + "bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm", + "Qmf5Qzp6nGBku7CEn2UQx4mgN8TW69YUok36DrGa6NN893", + "zb2rhZi1JR4eNc2jBGaRYJKYM8JEB4ovenym8L1CmFsRAytkz", + } + + var cids []Cid + var buf []byte + for _, cs := range cidstr { + c, err := Decode(cs) + if err != nil { + t.Fatal(err) + } + cids = append(cids, c) + buf = append(buf, c.Bytes()...) + } + + var cur int + for _, expc := range cids { + n, c, err := CidFromBytes(buf[cur:]) + if err != nil { + t.Fatal(err) + } + if c != expc { + t.Fatal("cids mismatched") + } + cur += n + } + if cur != len(buf) { + t.Fatal("had trailing bytes") + } +}