Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3da5bbbe45 | ||
|
|
9d598bbdbd | ||
|
|
b420452400 | ||
|
|
ed7dab1755 | ||
|
|
5df89959a0 | ||
|
|
60ab0f84f0 | ||
|
|
08e15f8a6c | ||
|
|
58b483a841 | ||
|
|
79e75dffeb | ||
|
|
d93d4baeab | ||
|
|
cf8cf8856e | ||
|
|
aa8072eeb5 | ||
|
|
51871ccaa9 | ||
|
|
9238d1a533 | ||
|
|
16bbe1cf14 | ||
|
|
c91a795815 | ||
|
|
64acce09e1 | ||
|
|
2a2f67d2c4 | ||
|
|
86ca2a8300 | ||
|
|
e0a778be45 | ||
|
|
9bb7ea6920 | ||
|
|
3f1777738f |
@@ -10,7 +10,6 @@ env:
|
||||
global:
|
||||
- GOTFLAGS="-race"
|
||||
matrix:
|
||||
- BUILD_DEPTYPE=gx
|
||||
- BUILD_DEPTYPE=gomod
|
||||
|
||||
|
||||
|
||||
27
README.md
27
README.md
@@ -14,6 +14,9 @@ go-cid
|
||||
This is an implementation in Go of the [CID spec](https://github.com/ipld/cid).
|
||||
It is used in `go-ipfs` and related packages to refer to a typed hunk of data.
|
||||
|
||||
## Lead Maintainer
|
||||
|
||||
[Eric Myhre](https://github.com/warpfork)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -31,36 +34,16 @@ It is used in `go-ipfs` and related packages to refer to a typed hunk of data.
|
||||
go get github.com/ipfs/go-cid
|
||||
```
|
||||
|
||||
Note that `go-cid` is packaged with Gx, so it is recommended to use Gx to install and use it (see Usage section).
|
||||
|
||||
## Usage
|
||||
|
||||
### Using Gx and Gx-go
|
||||
|
||||
This module is packaged with [Gx](https://github.com/whyrusleeping/gx). In order to use it in your own project it is recommended that you:
|
||||
|
||||
```sh
|
||||
go get -u github.com/whyrusleeping/gx
|
||||
go get -u github.com/whyrusleeping/gx-go
|
||||
cd <your-project-repository>
|
||||
gx init
|
||||
gx import github.com/ipfs/go-cid
|
||||
gx install --global
|
||||
gx-go --rewrite
|
||||
```
|
||||
|
||||
Please check [Gx](https://github.com/whyrusleeping/gx) and [Gx-go](https://github.com/whyrusleeping/gx-go) documentation for more information.
|
||||
|
||||
### Running tests
|
||||
|
||||
Before running tests, please run:
|
||||
Run tests with `go test` from the directory root
|
||||
|
||||
```sh
|
||||
make deps
|
||||
go test
|
||||
```
|
||||
|
||||
This will make sure that dependencies are rewritten to known working versions.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Parsing string input from users
|
||||
|
||||
@@ -8,6 +8,7 @@ const (
|
||||
|
||||
DagProtobuf = 0x70
|
||||
DagCBOR = 0x71
|
||||
Libp2pKey = 0x72
|
||||
|
||||
GitRaw = 0x78
|
||||
|
||||
@@ -34,6 +35,7 @@ var Codecs = map[string]uint64{
|
||||
"raw": Raw,
|
||||
"protobuf": DagProtobuf,
|
||||
"cbor": DagCBOR,
|
||||
"libp2p-key": Libp2pKey,
|
||||
"git-raw": GitRaw,
|
||||
"eth-block": EthBlock,
|
||||
"eth-block-list": EthBlockList,
|
||||
@@ -57,6 +59,7 @@ var CodecToStr = map[uint64]string{
|
||||
Raw: "raw",
|
||||
DagProtobuf: "protobuf",
|
||||
DagCBOR: "cbor",
|
||||
Libp2pKey: "libp2p-key",
|
||||
GitRaw: "git-raw",
|
||||
EthBlock: "eth-block",
|
||||
EthBlockList: "eth-block-list",
|
||||
|
||||
@@ -38,7 +38,7 @@ func (p V0Builder) Sum(data []byte) (Cid, error) {
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
return NewCidV0(hash), nil
|
||||
return Cid{string(hash)}, nil
|
||||
}
|
||||
|
||||
func (p V0Builder) GetCodec() uint64 {
|
||||
|
||||
112
cid.go
112
cid.go
@@ -62,6 +62,7 @@ const (
|
||||
|
||||
DagProtobuf = 0x70
|
||||
DagCBOR = 0x71
|
||||
Libp2pKey = 0x72
|
||||
|
||||
GitRaw = 0x78
|
||||
|
||||
@@ -90,6 +91,7 @@ var Codecs = map[string]uint64{
|
||||
"raw": Raw,
|
||||
"protobuf": DagProtobuf,
|
||||
"cbor": DagCBOR,
|
||||
"libp2p-key": Libp2pKey,
|
||||
"git-raw": GitRaw,
|
||||
"eth-block": EthBlock,
|
||||
"eth-block-list": EthBlockList,
|
||||
@@ -135,25 +137,39 @@ var CodecToStr = map[uint64]string{
|
||||
DashTx: "dash-tx",
|
||||
}
|
||||
|
||||
// NewCidV0 returns a Cid-wrapped multihash.
|
||||
// They exist to allow IPFS to work with Cids while keeping
|
||||
// compatibility with the plain-multihash format used used in IPFS.
|
||||
// NewCidV1 should be used preferentially.
|
||||
func NewCidV0(mhash mh.Multihash) Cid {
|
||||
// tryNewCidV0 tries to convert a multihash into a CIDv0 CID and returns an
|
||||
// error on failure.
|
||||
func tryNewCidV0(mhash mh.Multihash) (Cid, error) {
|
||||
// Need to make sure hash is valid for CidV0 otherwise we will
|
||||
// incorrectly detect it as CidV1 in the Version() method
|
||||
dec, err := mh.Decode(mhash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return Undef, err
|
||||
}
|
||||
if dec.Code != mh.SHA2_256 || dec.Length != 32 {
|
||||
panic("invalid hash for cidv0")
|
||||
return Undef, fmt.Errorf("invalid hash for cidv0 %d-%d", dec.Code, dec.Length)
|
||||
}
|
||||
return Cid{string(mhash)}
|
||||
return Cid{string(mhash)}, nil
|
||||
}
|
||||
|
||||
// NewCidV0 returns a Cid-wrapped multihash.
|
||||
// They exist to allow IPFS to work with Cids while keeping
|
||||
// compatibility with the plain-multihash format used used in IPFS.
|
||||
// NewCidV1 should be used preferentially.
|
||||
//
|
||||
// Panics if the multihash isn't sha2-256.
|
||||
func NewCidV0(mhash mh.Multihash) Cid {
|
||||
c, err := tryNewCidV0(mhash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// NewCidV1 returns a new Cid using the given multicodec-packed
|
||||
// content type.
|
||||
//
|
||||
// Panics if the multihash is invalid.
|
||||
func NewCidV1(codecType uint64, mhash mh.Multihash) Cid {
|
||||
hashlen := len(mhash)
|
||||
// two 8 bytes (max) numbers plus hash
|
||||
@@ -201,7 +217,7 @@ func Parse(v interface{}) (Cid, error) {
|
||||
case []byte:
|
||||
return Cast(v2)
|
||||
case mh.Multihash:
|
||||
return NewCidV0(v2), nil
|
||||
return tryNewCidV0(v2)
|
||||
case Cid:
|
||||
return v2, nil
|
||||
default:
|
||||
@@ -232,7 +248,7 @@ func Decode(v string) (Cid, error) {
|
||||
return Undef, err
|
||||
}
|
||||
|
||||
return NewCidV0(hash), nil
|
||||
return tryNewCidV0(hash)
|
||||
}
|
||||
|
||||
_, data, err := mbase.Decode(v)
|
||||
@@ -288,36 +304,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
|
||||
@@ -541,6 +537,12 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
|
||||
length = -1
|
||||
}
|
||||
|
||||
if p.Version == 0 && (p.MhType != mh.SHA2_256 ||
|
||||
(p.MhLength != 32 && p.MhLength != -1)) {
|
||||
|
||||
return Undef, fmt.Errorf("invalid v0 prefix")
|
||||
}
|
||||
|
||||
hash, err := mh.Sum(data, p.MhType, length)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
@@ -599,3 +601,41 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
|
||||
MhLength: int(mhlen),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CidFromBytes(data []byte) (int, Cid, error) {
|
||||
if len(data) > 2 && data[0] == mh.SHA2_256 && 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, Cid{string(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
|
||||
}
|
||||
|
||||
mhnr, _, err := mh.MHFromBytes(data[n+cn:])
|
||||
if err != nil {
|
||||
return 0, Undef, err
|
||||
}
|
||||
|
||||
l := n + cn + mhnr
|
||||
|
||||
return l, Cid{string(data[0:l])}, nil
|
||||
}
|
||||
|
||||
81
cid_test.go
81
cid_test.go
@@ -19,6 +19,7 @@ var tCodecs = map[uint64]string{
|
||||
Raw: "raw",
|
||||
DagProtobuf: "protobuf",
|
||||
DagCBOR: "cbor",
|
||||
Libp2pKey: "libp2p-key",
|
||||
GitRaw: "git-raw",
|
||||
EthBlock: "eth-block",
|
||||
EthBlockList: "eth-block-list",
|
||||
@@ -332,6 +333,41 @@ func TestNewPrefixV0(t *testing.T) {
|
||||
if c1.Prefix() != c2.Prefix() {
|
||||
t.Fatal("prefixes mismatch")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInvalidV0Prefix(t *testing.T) {
|
||||
tests := []Prefix{
|
||||
{
|
||||
MhType: mh.SHA2_256,
|
||||
MhLength: 31,
|
||||
},
|
||||
{
|
||||
MhType: mh.SHA2_256,
|
||||
MhLength: 33,
|
||||
},
|
||||
{
|
||||
MhType: mh.SHA2_256,
|
||||
MhLength: -2,
|
||||
},
|
||||
{
|
||||
MhType: mh.SHA2_512,
|
||||
MhLength: 32,
|
||||
},
|
||||
{
|
||||
MhType: mh.SHA2_512,
|
||||
MhLength: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for i, p := range tests {
|
||||
t.Log(i)
|
||||
_, err := p.Sum([]byte("testdata"))
|
||||
if err == nil {
|
||||
t.Fatalf("should error (index %d)", i)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPrefixRoundtrip(t *testing.T) {
|
||||
@@ -514,3 +550,48 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadParse(t *testing.T) {
|
||||
hash, err := mh.Sum([]byte("foobar"), mh.SHA3_256, -1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = Parse(hash)
|
||||
if err == nil {
|
||||
t.Fatal("expected to fail to parse an invalid CIDv1 CID")
|
||||
}
|
||||
}
|
||||
|
||||
4
go.mod
4
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.1
|
||||
github.com/multiformats/go-multihash v0.0.10
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
||||
32
go.sum
32
go.sum
@@ -1,20 +1,28 @@
|
||||
github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ=
|
||||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
|
||||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0=
|
||||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM=
|
||||
github.com/multiformats/go-multihash v0.0.10/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
Reference in New Issue
Block a user