Compare commits

..

10 Commits

Author SHA1 Message Date
hannahhoward
8f7b37bab5 feat(cid): add FromDigest for previously computed hash 2021-02-25 17:38:21 -08:00
dependabot-preview[bot]
e530276a70 Bump github.com/multiformats/go-varint from 0.0.5 to 0.0.6
Bumps [github.com/multiformats/go-varint](https://github.com/multiformats/go-varint) from 0.0.5 to 0.0.6.
- [Release notes](https://github.com/multiformats/go-varint/releases)
- [Commits](https://github.com/multiformats/go-varint/compare/v0.0.5...v0.0.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-15 14:27:46 +11:00
dependabot-preview[bot]
45f4147a06 Bump github.com/multiformats/go-multihash from 0.0.13 to 0.0.14
Bumps [github.com/multiformats/go-multihash](https://github.com/multiformats/go-multihash) from 0.0.13 to 0.0.14.
- [Release notes](https://github.com/multiformats/go-multihash/releases)
- [Commits](https://github.com/multiformats/go-multihash/compare/v0.0.13...v0.0.14)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-15 14:12:37 +11:00
Rod Vagg
b34ad3cfa5 s/characters/bytes 2020-10-15 14:05:52 +11:00
gammazero
ec089b8a53 Fix inaccurate comment for uvarint
This fixes the comment to be consistent with the code, and fixes spelling.

Fixes Issue #111
2020-10-15 14:05:52 +11:00
Rod Vagg
efe2d2de45 coverage: more tests for cid 2020-10-15 14:00:36 +11:00
Rod Vagg
46aac88838 coverage: more tests for varint 2020-10-15 14:00:36 +11:00
Rod Vagg
f60e346b24 coverage: more tests for builder 2020-10-15 14:00:36 +11:00
Rod Vagg
8647a1d84b fix: make tests run with Go 1.15
> ./cid_test.go:451:52: conversion from uint64 to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
2020-10-15 14:00:36 +11:00
Alex Good
de49849130 Add the dagjose multiformat 2020-10-15 14:00:36 +11:00
7 changed files with 279 additions and 25 deletions

View File

@@ -65,9 +65,29 @@ func TestCodecChange(t *testing.T) {
p := Prefix{Version: 1, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
testCodecChange(t, p)
})
t.Run("Prefix-NoChange", func(t *testing.T) {
p := Prefix{Version: 0, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
if p.GetCodec() != DagProtobuf {
t.Fatal("original builder not using Protobuf codec")
}
pn := p.WithCodec(DagProtobuf)
if pn != p {
t.Fatal("should have returned same builder")
}
})
t.Run("V0Builder", func(t *testing.T) {
testCodecChange(t, V0Builder{})
})
t.Run("V0Builder-NoChange", func(t *testing.T) {
b := V0Builder{}
if b.GetCodec() != DagProtobuf {
t.Fatal("original builder not using Protobuf codec")
}
bn := b.WithCodec(DagProtobuf)
if bn != b {
t.Fatal("should have returned same builder")
}
})
t.Run("V1Builder", func(t *testing.T) {
testCodecChange(t, V1Builder{Codec: DagProtobuf, MhType: mh.SHA2_256})
})

12
cid.go
View File

@@ -58,6 +58,7 @@ const (
GitRaw = 0x78
DagJOSE = 0x85
EthBlock = 0x90
EthBlockList = 0x91
EthTxTrie = 0x92
@@ -106,6 +107,7 @@ var Codecs = map[string]uint64{
"dash-tx": DashTx,
"fil-commitment-unsealed": FilCommitmentUnsealed,
"fil-commitment-sealed": FilCommitmentSealed,
"dag-jose": DagJOSE,
}
// CodecToStr maps the numeric codec to its name
@@ -133,6 +135,7 @@ var CodecToStr = map[uint64]string{
DashTx: "dash-tx",
FilCommitmentUnsealed: "fil-commitment-unsealed",
FilCommitmentSealed: "fil-commitment-sealed",
DagJOSE: "dag-jose",
}
// tryNewCidV0 tries to convert a multihash into a CIDv0 CID and returns an
@@ -570,8 +573,15 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
return Undef, fmt.Errorf("invalid v0 prefix")
}
digest, err := mh.Digest(data, p.MhType, length)
if err != nil {
return Undef, err
}
return p.FromDigest(digest)
}
hash, err := mh.Sum(data, p.MhType, length)
func (p Prefix) FromDigest(digest []byte) (Cid, error) {
hash, err := mh.Encode(digest, p.MhType)
if err != nil {
return Undef, err
}

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"strings"
"testing"
@@ -40,6 +41,7 @@ var tCodecs = map[uint64]string{
DashTx: "dash-tx",
FilCommitmentUnsealed: "fil-commitment-unsealed",
FilCommitmentSealed: "fil-commitment-sealed",
DagJOSE: "dag-jose",
}
func assertEqual(t *testing.T, a, b Cid) {
@@ -103,7 +105,37 @@ func TestPrefixSum(t *testing.T) {
}
}
}
func TestPrefixDigest(t *testing.T) {
// Test creating CIDs both manually and with Prefix.
// Tests: https://github.com/ipfs/go-cid/issues/83
for _, hashfun := range []uint64{
mh.ID, mh.SHA3, mh.SHA2_256,
} {
h1, err := mh.Sum([]byte("TEST"), hashfun, -1)
if err != nil {
t.Fatal(err)
}
c1 := NewCidV1(Raw, h1)
h2, err := mh.Sum([]byte("foobar"), hashfun, -1)
if err != nil {
t.Fatal(err)
}
c2 := NewCidV1(Raw, h2)
digest, err := mh.Digest([]byte("foobar"), hashfun, -1)
if err != nil {
t.Fatal(err)
}
c3, err := c1.Prefix().FromDigest(digest)
if err != nil {
t.Fatal(err)
}
if !c2.Equals(c3) {
t.Fatal("expected CIDs to be equal")
}
}
}
func TestBasicMarshaling(t *testing.T) {
h, err := mh.Sum([]byte("TEST"), mh.SHA3, 4)
if err != nil {
@@ -184,8 +216,32 @@ func TestBasesMarshaling(t *testing.T) {
}
s2 := cid.Encode(encoder)
if s != s2 {
t.Fatalf("'%s' != '%s'", s, s2)
t.Fatalf("%q != %q", s, s2)
}
ee, err := ExtractEncoding(s)
if err != nil {
t.Fatal(err)
}
if ee != b {
t.Fatalf("could not properly determine base (got %v)", ee)
}
}
ee, err := ExtractEncoding("QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n")
if err != nil {
t.Fatal(err)
}
if ee != mbase.Base58BTC {
t.Fatalf("expected Base58BTC from Qm string (got %v)", ee)
}
ee, err = ExtractEncoding("1")
if err == nil {
t.Fatal("expected too-short error from ExtractEncoding")
}
if ee != -1 {
t.Fatal("expected -1 from too-short ExtractEncoding")
}
}
@@ -194,18 +250,32 @@ func TestBinaryMarshaling(t *testing.T) {
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
c := NewCidV1(DagCBOR, hash)
var c2 Cid
var c3 Cid
data, err := c.MarshalBinary()
if err != nil {
t.Fatal(err)
}
err = c2.UnmarshalBinary(data)
if err != nil {
if err = c2.UnmarshalBinary(data); err != nil {
t.Fatal(err)
}
if !c.Equals(c2) {
t.Errorf("cids should be the same: %s %s", c, c2)
}
var buf bytes.Buffer
wrote, err := c.WriteBytes(&buf)
if err != nil {
t.Fatal(err)
}
if wrote != 36 {
t.Fatalf("expected 36 bytes written (got %d)", wrote)
}
if err = c3.UnmarshalBinary(data); err != nil {
t.Fatal(err)
}
if !c.Equals(c3) {
t.Errorf("cids should be the same: %s %s", c, c3)
}
}
func TestTextMarshaling(t *testing.T) {
@@ -218,13 +288,16 @@ func TestTextMarshaling(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = c2.UnmarshalText(data)
if err != nil {
if err = c2.UnmarshalText(data); err != nil {
t.Fatal(err)
}
if !c.Equals(c2) {
t.Errorf("cids should be the same: %s %s", c, c2)
}
if c.KeyString() != string(c.Bytes()) {
t.Errorf("got unexpected KeyString() result")
}
}
func TestEmptyString(t *testing.T) {
@@ -254,6 +327,11 @@ func TestV0Handling(t *testing.T) {
t.Fatal("marshaling roundtrip failed")
}
byteLen := cid.ByteLen()
if byteLen != 34 {
t.Fatalf("expected V0 ByteLen to be 34 (got %d)", byteLen)
}
new, err := cid.StringOfBase(mbase.Base58BTC)
if err != nil {
t.Fatal(err)
@@ -269,6 +347,11 @@ func TestV0Handling(t *testing.T) {
if cid.Encode(encoder) != old {
t.Fatal("Encode roundtrip failed")
}
_, err = cid.StringOfBase(mbase.Base32)
if err != ErrInvalidEncoding {
t.Fatalf("expected ErrInvalidEncoding for V0 StringOfBase(Base32) (got %v)", err)
}
}
func TestV0ErrorCases(t *testing.T) {
@@ -369,7 +452,14 @@ func TestInvalidV0Prefix(t *testing.T) {
t.Fatalf("should error (index %d)", i)
}
}
}
func TestBadPrefix(t *testing.T) {
p := Prefix{Version: 3, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: 3}
_, err := p.Sum([]byte{0x00, 0x01, 0x03})
if err == nil {
t.Fatalf("expected error on v3 prefix Sum")
}
}
func TestPrefixRoundtrip(t *testing.T) {
@@ -401,6 +491,25 @@ func TestPrefixRoundtrip(t *testing.T) {
}
}
func TestBadPrefixFromBytes(t *testing.T) {
_, err := PrefixFromBytes([]byte{0x80})
if err == nil {
t.Fatal("expected error for bad byte 0")
}
_, err = PrefixFromBytes([]byte{0x01, 0x80})
if err == nil {
t.Fatal("expected error for bad byte 1")
}
_, err = PrefixFromBytes([]byte{0x01, 0x01, 0x80})
if err == nil {
t.Fatal("expected error for bad byte 2")
}
_, err = PrefixFromBytes([]byte{0x01, 0x01, 0x01, 0x80})
if err == nil {
t.Fatal("expected error for bad byte 3")
}
}
func Test16BytesVarint(t *testing.T) {
data := []byte("this is some test content")
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
@@ -448,7 +557,7 @@ func TestParse(t *testing.T) {
return err
}
if cid.Version() != 0 {
return fmt.Errorf("expected version 0, got %s", string(cid.Version()))
return fmt.Errorf("expected version 0, got %d", cid.Version())
}
actual := cid.Hash().B58String()
if actual != expected {
@@ -462,8 +571,7 @@ func TestParse(t *testing.T) {
}
for _, args := range assertions {
err := assert(args[0], args[1].(string))
if err != nil {
if err := assert(args[0], args[1].(string)); err != nil {
t.Fatal(err)
}
}
@@ -497,8 +605,7 @@ func TestFromJson(t *testing.T) {
cval := "bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm"
jsoncid := []byte(`{"/":"` + cval + `"}`)
var c Cid
err := json.Unmarshal(jsoncid, &c)
if err != nil {
if err := json.Unmarshal(jsoncid, &c); err != nil {
t.Fatal(err)
}
@@ -508,6 +615,7 @@ func TestFromJson(t *testing.T) {
}
func TestJsonRoundTrip(t *testing.T) {
expectedJSON := `{"/":"bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm"}`
exp, err := Decode("bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm")
if err != nil {
t.Fatal(err)
@@ -519,21 +627,50 @@ func TestJsonRoundTrip(t *testing.T) {
t.Fatal(err)
}
var actual Cid
err = json.Unmarshal(enc, &actual)
if err = json.Unmarshal(enc, &actual); err != nil {
t.Fatal(err)
}
if !exp.Equals(actual) {
t.Fatal("cids not equal for *Cid")
}
if string(enc) != expectedJSON {
t.Fatalf("did not get expected JSON form (got %q)", string(enc))
}
// Verify it works for a Cid.
enc, err = json.Marshal(exp)
if err != nil {
t.Fatal(err)
}
var actual2 Cid
err = json.Unmarshal(enc, &actual2)
if err = json.Unmarshal(enc, &actual2); err != nil {
t.Fatal(err)
}
if !exp.Equals(actual2) {
t.Fatal("cids not equal for Cid")
}
if err = actual2.UnmarshalJSON([]byte("1")); err == nil {
t.Fatal("expected error for too-short JSON")
}
if err = actual2.UnmarshalJSON([]byte(`{"nope":"nope"}`)); err == nil {
t.Fatal("expected error for bad CID JSON")
}
if err = actual2.UnmarshalJSON([]byte(`bad "" json!`)); err == nil {
t.Fatal("expected error for bad JSON")
}
var actual3 Cid
enc, err = actual3.MarshalJSON()
if err != nil {
t.Fatal(err)
}
if string(enc) != "null" {
t.Fatalf("expected 'null' string for undefined CID (got %q)", string(enc))
}
}
func BenchmarkStringV1(b *testing.B) {
@@ -588,6 +725,52 @@ func TestReadCidsFromBuffer(t *testing.T) {
}
}
func TestBadCidFromBytes(t *testing.T) {
l, c, err := CidFromBytes([]byte{mh.SHA2_256, 32, 0x00})
if err == nil {
t.Fatal("expected not-enough-bytes for V0 CidFromBytes")
}
if l != 0 {
t.Fatal("expected length=0 from bad CidFromBytes")
}
if c != Undef {
t.Fatal("expected Undef CID from bad CidFromBytes")
}
c, err = Decode("bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm")
if err != nil {
t.Fatal(err)
}
byts := make([]byte, c.ByteLen())
copy(byts, c.Bytes())
byts[1] = 0x80 // bad codec varint
byts[2] = 0x00
l, c, err = CidFromBytes(byts)
if err == nil {
t.Fatal("expected not-enough-bytes for V1 CidFromBytes")
}
if l != 0 {
t.Fatal("expected length=0 from bad CidFromBytes")
}
if c != Undef {
t.Fatal("expected Undef CID from bad CidFromBytes")
}
copy(byts, c.Bytes())
byts[2] = 0x80 // bad multihash varint
byts[3] = 0x00
l, c, err = CidFromBytes(byts)
if err == nil {
t.Fatal("expected not-enough-bytes for V1 CidFromBytes")
}
if l != 0 {
t.Fatal("expected length=0 from bad CidFromBytes")
}
if c != Undef {
t.Fatal("expected Undef CID from bad CidFromBytes")
}
}
func TestBadParse(t *testing.T) {
hash, err := mh.Sum([]byte("foobar"), mh.SHA3_256, -1)
if err != nil {
@@ -598,3 +781,16 @@ func TestBadParse(t *testing.T) {
t.Fatal("expected to fail to parse an invalid CIDv1 CID")
}
}
func TestLoggable(t *testing.T) {
c, err := Decode("bafkreie5qrjvaw64n4tjm6hbnm7fnqvcssfed4whsjqxzslbd3jwhsk3mm")
if err != nil {
t.Fatal(err)
}
actual := c.Loggable()
expected := make(map[string]interface{})
expected["cid"] = c
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("did not get expected loggable form (got %v)", actual)
}
}

4
go.mod
View File

@@ -2,8 +2,8 @@ module github.com/ipfs/go-cid
require (
github.com/multiformats/go-multibase v0.0.3
github.com/multiformats/go-multihash v0.0.13
github.com/multiformats/go-varint v0.0.5
github.com/multiformats/go-multihash v0.0.15-0.20210226003459-69a4fed1d6f2
github.com/multiformats/go-varint v0.0.6
)
go 1.13

5
go.sum
View File

@@ -14,8 +14,13 @@ github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.15-0.20210226003459-69a4fed1d6f2 h1:0DZ3ybel2YfQ4L9GrglYgfXxdXVT8CVkJt//crxSQDM=
github.com/multiformats/go-multihash v0.0.15-0.20210226003459-69a4fed1d6f2/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

View File

@@ -4,7 +4,7 @@ import (
"github.com/multiformats/go-varint"
)
// Version of varint function that work with a string rather than
// Version of varint function that works with a string rather than
// []byte to avoid unnecessary allocation
// Copyright 2011 The Go Authors. All rights reserved.
@@ -12,23 +12,20 @@ import (
// license as given at https://golang.org/LICENSE
// uvarint decodes a uint64 from buf and returns that value and the
// number of characters read (> 0). If an error occurred, the value is 0
// and the number of bytes n is <= 0 meaning:
//
// n == 0: buf too small
// n < 0: value larger than 64 bits (overflow)
// and -n is the number of bytes read
//
// number of bytes read (> 0). If an error occurred, then 0 is
// returned for both the value and the number of bytes read, and an
// error is returned.
func uvarint(buf string) (uint64, int, error) {
var x uint64
var s uint
// we have a binary string so we can't use a range loope
// we have a binary string so we can't use a range loop
for i := 0; i < len(buf); i++ {
b := buf[i]
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
return 0, 0, varint.ErrOverflow
} else if b == 0 && i > 0 {
}
if b == 0 && i > 0 {
return 0, 0, varint.ErrNotMinimal
}
return x | uint64(b)<<s, i + 1, nil

View File

@@ -28,3 +28,29 @@ func TestUvarintRoundTrip(t *testing.T) {
}
}
}
func TestUvarintEdges(t *testing.T) {
tests := []struct {
name string
input []byte
want error
}{
{"ErrNotMinimal", []byte{0x01 | 0x80, 0}, varint.ErrNotMinimal},
{"ErrOverflow", []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01}, varint.ErrOverflow},
{"ErrUnderflow", []byte{0x80}, varint.ErrUnderflow},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
v, l1, err := uvarint(string(test.input))
if err != test.want {
t.Fatalf("error case (%v) should return varint.%s (got: %v)", test.input, test.name, err)
}
if v != 0 {
t.Fatalf("error case (%v) should return 0 value (got %d)", test.input, v)
}
if l1 != 0 {
t.Fatalf("error case (%v) should return 0 length (got %d)", test.input, l1)
}
})
}
}