Unverified Commit 179a9a07 authored by Steven Allen's avatar Steven Allen Committed by GitHub

Merge pull request #4 from ipfs/kevina/idstore

Add a special blockstore to support identity hashes.
parents c780dda4 4da9b7e9
package blockstore
import (
"context"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
mh "github.com/multiformats/go-multihash"
)
// idstore wraps a BlockStore to add support for identity hashes
type idstore struct {
bs Blockstore
}
func NewIdStore(bs Blockstore) Blockstore {
return &idstore{bs}
}
func extractContents(k *cid.Cid) (bool, []byte) {
dmh, err := mh.Decode(k.Hash())
if err != nil || dmh.Code != mh.ID {
return false, nil
}
return true, dmh.Digest
}
func (b *idstore) DeleteBlock(k *cid.Cid) error {
isId, _ := extractContents(k)
if isId {
return nil
}
return b.bs.DeleteBlock(k)
}
func (b *idstore) Has(k *cid.Cid) (bool, error) {
isId, _ := extractContents(k)
if isId {
return true, nil
}
return b.bs.Has(k)
}
func (b *idstore) Get(k *cid.Cid) (blocks.Block, error) {
isId, bdata := extractContents(k)
if isId {
return blocks.NewBlockWithCid(bdata, k)
}
return b.bs.Get(k)
}
func (b *idstore) Put(bl blocks.Block) error {
isId, _ := extractContents(bl.Cid())
if isId {
return nil
}
return b.bs.Put(bl)
}
func (b *idstore) PutMany(bs []blocks.Block) error {
toPut := make([]blocks.Block, 0, len(bs))
for _, bl := range bs {
isId, _ := extractContents(bl.Cid())
if isId {
continue
}
toPut = append(toPut, bl)
}
return b.bs.PutMany(toPut)
}
func (b *idstore) HashOnRead(enabled bool) {
b.bs.HashOnRead(enabled)
}
func (b *idstore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
return b.bs.AllKeysChan(ctx)
}
package blockstore
import (
"context"
"testing"
blk "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
mh "github.com/multiformats/go-multihash"
)
func createTestStores() (Blockstore, *callbackDatastore) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
ids := NewIdStore(NewBlockstore(cd))
return ids, cd
}
func TestIdStore(t *testing.T) {
idhash1, _ := cid.NewPrefixV1(cid.Raw, mh.ID).Sum([]byte("idhash1"))
idblock1, _ := blk.NewBlockWithCid([]byte("idhash1"), idhash1)
hash1, _ := cid.NewPrefixV1(cid.Raw, mh.SHA2_256).Sum([]byte("hash1"))
block1, _ := blk.NewBlockWithCid([]byte("hash1"), hash1)
ids, cb := createTestStores()
have, _ := ids.Has(idhash1)
if !have {
t.Fatal("Has() failed on idhash")
}
_, err := ids.Get(idhash1)
if err != nil {
t.Fatalf("Get() failed on idhash: %v", err)
}
noop := func() {}
failIfPassThough := func() {
t.Fatal("operation on identity hash passed though to datastore")
}
cb.f = failIfPassThough
err = ids.Put(idblock1)
if err != nil {
t.Fatal(err)
}
cb.f = noop
err = ids.Put(block1)
if err != nil {
t.Fatalf("Put() failed on normal block: %v", err)
}
have, _ = ids.Has(hash1)
if !have {
t.Fatal("normal block not added to datastore")
}
_, err = ids.Get(hash1)
if err != nil {
t.Fatal(err)
}
cb.f = failIfPassThough
err = ids.DeleteBlock(idhash1)
if err != nil {
t.Fatal(err)
}
cb.f = noop
err = ids.DeleteBlock(hash1)
if err != nil {
t.Fatal(err)
}
have, _ = ids.Has(hash1)
if have {
t.Fatal("normal block not deleted from datastore")
}
idhash2, _ := cid.NewPrefixV1(cid.Raw, mh.ID).Sum([]byte("idhash2"))
idblock2, _ := blk.NewBlockWithCid([]byte("idhash2"), idhash2)
hash2, _ := cid.NewPrefixV1(cid.Raw, mh.SHA2_256).Sum([]byte("hash2"))
block2, _ := blk.NewBlockWithCid([]byte("hash2"), hash2)
cb.f = failIfPassThough
err = ids.PutMany([]blk.Block{idblock1, idblock2})
if err != nil {
t.Fatal(err)
}
opCount := 0
cb.f = func() {
opCount++
}
err = ids.PutMany([]blk.Block{block1, block2})
if err != nil {
t.Fatal(err)
}
if opCount != 4 {
// one call to Has and Put for each Cid
t.Fatalf("expected exactly 4 operations got %d", opCount)
}
opCount = 0
err = ids.PutMany([]blk.Block{idblock1, block1})
if err != nil {
t.Fatal(err)
}
if opCount != 1 {
// just one call to Put from the normal (non-id) block
t.Fatalf("expected exactly 1 operations got %d", opCount)
}
ch, err := ids.AllKeysChan(context.TODO())
cnt := 0
for c := range ch {
cnt++
if c.Prefix().MhType == mh.ID {
t.Fatalf("block with identity hash found in blockstore")
}
}
if cnt != 2 {
t.Fatalf("expected exactly two keys returned by AllKeysChan got %d", cnt)
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment