Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
77f3c7c
refactor: move some things around
Aug 15, 2024
fc48554
feat(validator): add error models
hannahhoward Jul 30, 2024
37e2c10
feat: progress
Aug 16, 2024
4770f7c
feat: policy for capability validation
Aug 19, 2024
b51775c
feat: add policy implementation
Aug 19, 2024
5bba918
feat: better selector
Aug 20, 2024
0f7760f
feat: simplify
Aug 20, 2024
9a910f1
chore: tidy regexps
Aug 20, 2024
0183581
feat: wildcard
Aug 21, 2024
e0c9b6a
feat: quantification
Aug 21, 2024
7610709
refactor: reorg tests
Aug 21, 2024
20adcd2
feat: more validation
Aug 21, 2024
9baee6c
feat: authorization implementation
Aug 21, 2024
21e16a7
feat: progress towards completing Authorize function
Aug 22, 2024
a1820a1
feat: compiles
Aug 23, 2024
5451848
test: initial test
Aug 23, 2024
f40f932
test(selector): add tests for "Supported Forms"
smoyer64 Aug 23, 2024
178a323
test(selector): add tests for "Supported Forms" (#15)
hannahhoward Aug 28, 2024
0e2a3b2
fix: initial test
Sep 2, 2024
815d7c3
test: more tests and fixes
Sep 3, 2024
fb370bd
feat: CAR offsets (#16)
hannahhoward Sep 3, 2024
7b3a12c
test: more tests
Sep 3, 2024
d07877f
Merge branch 'feat/delegation-chain-validation' of github.com:storach…
Sep 3, 2024
d853467
wip: switch to non-result internals
Sep 4, 2024
5d4eeb4
fix: wip errors
Sep 4, 2024
e3214a1
test: more testing progress
Sep 5, 2024
30191b3
fix: server tests
Sep 5, 2024
f23dcea
fix: more validator tests
Sep 5, 2024
85af3cd
fix: more tests and fixes
Sep 5, 2024
e627fba
test: more tests
Sep 6, 2024
109e8f6
feat(iterable): use built in iterators
hannahhoward Sep 3, 2024
9307a23
Use built in iterators (#17)
hannahhoward Sep 14, 2024
525e4eb
feat(schema): add mapped reader
hannahhoward Sep 14, 2024
3bed702
feat(schema): add link, URI, and or schema readers
hannahhoward Sep 16, 2024
c9a9184
feat: delegate and invoke from validator capability
Sep 16, 2024
0eef0d7
Merge branch 'feat/delegation-chain-validation' of github.com:storach…
Sep 16, 2024
3525500
feat: use go-ucan for policy implementation
Sep 16, 2024
9117b55
refactor: use capability invoke and delegate shorthand in tests
Sep 16, 2024
0229a79
test: external proof
Sep 16, 2024
815d21f
More schema reader (#18)
hannahhoward Sep 16, 2024
e1ac2a3
test: more validator tests
Sep 16, 2024
21a740f
test: some attestation tests
Sep 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.out
4 changes: 2 additions & 2 deletions client/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"crypto/sha256"
"fmt"
"hash"
"iter"

"github.com/storacha-network/go-ucanto/core/invocation"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/iterable"
"github.com/storacha-network/go-ucanto/core/message"
"github.com/storacha-network/go-ucanto/transport"
"github.com/storacha-network/go-ucanto/transport/car"
Expand Down Expand Up @@ -96,7 +96,7 @@ func (c *conn) Hasher() hash.Hash {
type ExecutionResponse interface {
// Blocks returns an iterator of all the IPLD blocks that are included in
// the response.
Blocks() iterable.Iterator[block.Block]
Blocks() iter.Seq2[block.Block, error]
// Get returns a link to a receipt, given an invocation link.
Get(inv ucan.Link) (ucan.Link, bool)
}
Expand Down
90 changes: 67 additions & 23 deletions core/car/car.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ import (
"bufio"
"fmt"
"io"
"iter"

"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
ipldcar "github.com/ipld/go-car"
"github.com/ipld/go-car/util"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/multiformats/go-varint"
"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/ipld/block"
"github.com/storacha-network/go-ucanto/core/iterable"
)

// ContentType is the value the HTTP Content-Type header should have for CARs.
// See https://www.iana.org/assignments/media-types/application/vnd.ipld.car
const ContentType = "application/vnd.ipld.car"

func Encode(roots []ipld.Link, blocks iterable.Iterator[ipld.Block]) io.Reader {
func Encode(roots []ipld.Link, blocks iter.Seq2[ipld.Block, error]) io.Reader {
reader, writer := io.Pipe()
go func() {
cids := []cid.Cid{}
Expand All @@ -41,23 +42,43 @@ func Encode(roots []ipld.Link, blocks iterable.Iterator[ipld.Block]) io.Reader {
return
}
util.LdWrite(writer, hb)
for {
block, err := blocks.Next()
for block, err := range blocks {
if err != nil {
writer.CloseWithError(fmt.Errorf("writing CAR blocks: %s", err))
return
}
err = util.LdWrite(writer, []byte(block.Link().Binary()), block.Bytes())
if err != nil {
if err == io.EOF {
break
}
writer.CloseWithError(fmt.Errorf("writing CAR blocks: %s", err))
return
}
util.LdWrite(writer, []byte(block.Link().Binary()), block.Bytes())
}
writer.Close()
}()
return reader
}

func Decode(reader io.Reader) ([]ipld.Link, iterable.Iterator[ipld.Block], error) {
type CarBlock interface {
ipld.Block
Offset() uint64
Length() uint64
}

type carBlock struct {
ipld.Block
offset uint64
length uint64
}

func (cb carBlock) Offset() uint64 {
return cb.offset
}

func (cb carBlock) Length() uint64 {
return cb.length
}

func Decode(reader io.Reader) ([]ipld.Link, iter.Seq2[ipld.Block, error], error) {
br := bufio.NewReader(reader)

h, err := ipldcar.ReadHeader(br)
Expand All @@ -69,29 +90,52 @@ func Decode(reader io.Reader) ([]ipld.Link, iterable.Iterator[ipld.Block], error
return nil, nil, fmt.Errorf("invalid car version: %d", h.Version)
}

offset, err := ipldcar.HeaderSize(h)
if err != nil {
return nil, nil, err
}

var roots []ipld.Link
for _, r := range h.Roots {
roots = append(roots, cidlink.Link{Cid: r})
}

return roots, iterable.NewIterator(func() (ipld.Block, error) {
cid, bytes, err := util.ReadNode(br)
if err != nil {
r := &blkReader{br, offset}
return roots, func(yield func(ipld.Block, error) bool) {
for {
blk, err := r.next()
if err == io.EOF {
br = nil
return
}
if !yield(blk, err) {
return
}
return nil, err
}
}, nil
}

hashed, err := cid.Prefix().Sum(bytes)
if err != nil {
return nil, err
}
type blkReader struct {
br *bufio.Reader
offset uint64
}

if !hashed.Equals(cid) {
return nil, fmt.Errorf("mismatch in content integrity, name: %s, data: %s", cid, hashed)
}
func (r *blkReader) next() (CarBlock, error) {
cid, bytes, err := util.ReadNode(r.br)
if err != nil {
return nil, err
}

hashed, err := cid.Prefix().Sum(bytes)
if err != nil {
return nil, err
}

if !hashed.Equals(cid) {
return nil, fmt.Errorf("mismatch in content integrity, name: %s, data: %s", cid, hashed)
}

ss := uint64(cid.ByteLen()) + uint64(len(bytes))
r.offset += uint64(varint.UvarintSize(ss)) + ss

return block.NewBlock(cidlink.Link{Cid: cid}, bytes), nil
}), nil
return carBlock{block.NewBlock(cidlink.Link{Cid: cid}, bytes), r.offset - uint64(len(bytes)), uint64(len(bytes))}, nil
}
30 changes: 23 additions & 7 deletions core/car/car_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ func TestDecodeCAR(t *testing.T) {
t.Fatalf("unexpected root: %s, expected: %s", roots[0], fixtures[0].root)
}

var blks []ipld.Block
for {
b, err := blocks.Next()
var blks []CarBlock
for b, err := range blocks {
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("reading blocks: %s", err)
}
blks = append(blks, b)
cb, ok := b.(CarBlock)
if !ok {
t.Fatalf("should have returned a car block")
}
blks = append(blks, cb)
}

if len(blks) != len(fixtures[0].blocks) {
Expand All @@ -66,6 +66,22 @@ func TestDecodeCAR(t *testing.T) {
if b.String() != blks[i].Link().String() {
t.Fatalf("unexpected block: %s, expected: %s", b, blks[i].Link())
}
// verify offset and length can be used to directly read the block in the CAR file
file.Seek(int64(blks[i].Offset()), io.SeekStart)
data := make([]byte, blks[i].Length())
_, err := file.Read(data)
if err != nil {
t.Fatalf("error reading block from raw file")
}
hashed, err := blks[i].Link().(cidlink.Link).Cid.Prefix().Sum(data)
if err != nil {
t.Fatalf("error hashing block from raw file")
}

if hashed.String() != blks[i].Link().String() {
t.Fatalf("raw read from offset block: %s, expected: %s", hashed, blks[i].Link())
}

}
}

Expand Down
86 changes: 33 additions & 53 deletions core/dag/blockstore/blockstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package blockstore

import (
"fmt"
"io"
"iter"
"sync"

"github.com/storacha-network/go-ucanto/core/ipld"
"github.com/storacha-network/go-ucanto/core/iterable"
)

type BlockReader interface {
Get(link ipld.Link) (ipld.Block, bool, error)
Iterator() iterable.Iterator[ipld.Block]
Iterator() iter.Seq2[ipld.Block, error]
}

type BlockWriter interface {
Expand All @@ -33,20 +32,19 @@ func (br *blockreader) Get(link ipld.Link) (ipld.Block, bool, error) {
return b, ok, nil
}

func (br *blockreader) Iterator() iterable.Iterator[ipld.Block] {
i := 0
return iterable.NewIterator(func() (ipld.Block, error) {
if len(br.keys) <= i {
return nil, io.EOF
}
k := br.keys[i]
v, ok := br.blks[k]
if !ok {
return nil, fmt.Errorf("missing block for key: %s", k)
func (br *blockreader) Iterator() iter.Seq2[ipld.Block, error] {
return func(yield func(ipld.Block, error) bool) {
for _, k := range br.keys {
v, ok := br.blks[k]
var err error
if !ok {
err = fmt.Errorf("missing block for key: %s", k)
}
if !yield(v, err) {
return
}
}
i++
return v, nil
})
}
}

type blockstore struct {
Expand Down Expand Up @@ -75,31 +73,29 @@ func (bs *blockstore) Get(link ipld.Link) (ipld.Block, bool, error) {
return bs.blockreader.Get(link)
}

func (bs *blockstore) Iterator() iterable.Iterator[ipld.Block] {
func (bs *blockstore) Iterator() iter.Seq2[ipld.Block, error] {
bs.Lock()
defer bs.Unlock()
keys := bs.keys[:]
i := 0
return iterable.NewIterator(func() (ipld.Block, error) {
if len(keys) <= i {
return nil, io.EOF
}
k := keys[i]
v, ok := bs.blks[k]
if !ok {
return nil, fmt.Errorf("missing block for key: %s", k)
return func(yield func(ipld.Block, error) bool) {
for _, k := range bs.keys {
v, ok := bs.blks[k]
var err error
if !ok {
err = fmt.Errorf("missing block for key: %s", k)
}
if !yield(v, err) {
return
}
}
i++
return v, nil
})
}
}

// Option is an option configuring a block reader/writer.
type Option func(cfg *bsConfig) error

type bsConfig struct {
blks []ipld.Block
blksiter iterable.Iterator[ipld.Block]
blksiter iter.Seq2[ipld.Block, error]
}

// WithBlocks configures the blocks the blockstore should contain.
Expand All @@ -111,7 +107,7 @@ func WithBlocks(blks []ipld.Block) Option {
}

// WithBlocksIterator configures the blocks the blockstore should contain.
func WithBlocksIterator(blks iterable.Iterator[ipld.Block]) Option {
func WithBlocksIterator(blks iter.Seq2[ipld.Block, error]) Option {
return func(cfg *bsConfig) error {
cfg.blksiter = blks
return nil
Expand All @@ -138,15 +134,11 @@ func NewBlockStore(options ...Option) (BlockStore, error) {
}
}
if cfg.blksiter != nil {
for {
b, err := cfg.blksiter.Next()
for b, err := range cfg.blksiter {
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
err = bs.Put(b)
err := bs.Put(b)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -175,12 +167,8 @@ func NewBlockReader(options ...Option) (BlockReader, error) {
keys = append(keys, b.Link().String())
}
if cfg.blksiter != nil {
for {
b, err := cfg.blksiter.Next()
for b, err := range cfg.blksiter {
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
_, ok := blks[b.Link().String()]
Expand All @@ -196,16 +184,8 @@ func NewBlockReader(options ...Option) (BlockReader, error) {
}

func WriteInto(view ipld.View, bs BlockWriter) error {
blks := view.Blocks()
for {
b, err := blks.Next()
if err != nil {
if err == io.EOF {
break
}
return fmt.Errorf("reading proof blocks: %s", err)
}
err = bs.Put(b)
for b := range view.Blocks() {
err := bs.Put(b)
if err != nil {
return fmt.Errorf("putting proof block: %s", err)
}
Expand Down
Loading