Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: attach blocks to delegation #27

Merged
merged 2 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion core/delegation/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,5 @@ func Delegate[C ucan.CaveatBuilder](issuer ucan.Signer, audience ucan.Principal,
return nil, fmt.Errorf("adding delegation root to store: %s", err)
}

return NewDelegation(rt, bs), nil
return NewDelegation(rt, bs)
}
30 changes: 22 additions & 8 deletions core/delegation/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/storacha/go-ucanto/core/ipld/block"
"github.com/storacha/go-ucanto/core/ipld/codec/cbor"
"github.com/storacha/go-ucanto/core/ipld/hash/sha256"
"github.com/storacha/go-ucanto/core/iterable"
"github.com/storacha/go-ucanto/ucan"
"github.com/storacha/go-ucanto/ucan/crypto/signature"
udm "github.com/storacha/go-ucanto/ucan/datamodel/ucan"
Expand All @@ -30,13 +31,18 @@ type Delegation interface {
Link() ucan.Link
// Archive writes the delegation to a Content Addressed aRchive (CAR).
Archive() io.Reader
// Attach a block to the delegation DAG so it will be included in the block
// iterator. You should only attach blocks that are referenced from
// `Capabilities` or `Facts`.
Attach(block block.Block) error
}

type delegation struct {
rt ipld.Block
blks blockstore.BlockReader
ucan ucan.View
once sync.Once
rt ipld.Block
blks blockstore.BlockReader
atchblks blockstore.BlockStore
ucan ucan.View
once sync.Once
}

var _ Delegation = (*delegation)(nil)
Expand Down Expand Up @@ -65,7 +71,7 @@ func (d *delegation) Link() ucan.Link {
}

func (d *delegation) Blocks() iter.Seq2[ipld.Block, error] {
return d.blks.Iterator()
return iterable.Concat2(d.blks.Iterator(), d.atchblks.Iterator())
}

func (d *delegation) Archive() io.Reader {
Expand Down Expand Up @@ -112,8 +118,16 @@ func (d *delegation) Signature() signature.SignatureView {
return d.Data().Signature()
}

func NewDelegation(root ipld.Block, bs blockstore.BlockReader) Delegation {
return &delegation{rt: root, blks: bs}
func (d *delegation) Attach(b block.Block) error {
return d.atchblks.Put(b)
}

func NewDelegation(root ipld.Block, bs blockstore.BlockReader) (Delegation, error) {
attachments, err := blockstore.NewBlockStore()
if err != nil {
return nil, err
}
return &delegation{rt: root, blks: bs, atchblks: attachments}, nil
}

func NewDelegationView(root ipld.Link, bs blockstore.BlockReader) (Delegation, error) {
Expand All @@ -124,7 +138,7 @@ func NewDelegationView(root ipld.Link, bs blockstore.BlockReader) (Delegation, e
if !ok {
return nil, fmt.Errorf("missing delegation root block: %s", root)
}
return NewDelegation(blk, bs), nil
return NewDelegation(blk, bs)
}

func Archive(d Delegation) io.Reader {
Expand Down
36 changes: 36 additions & 0 deletions core/delegation/delegation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package delegation

import (
"testing"

"github.com/storacha/go-ucanto/core/ipld/block"
"github.com/storacha/go-ucanto/testing/fixtures"
"github.com/storacha/go-ucanto/testing/helpers"
"github.com/storacha/go-ucanto/ucan"
"github.com/stretchr/testify/require"
)

func TestAttach(t *testing.T) {
dlg, err := Delegate(
fixtures.Alice,
fixtures.Bob,
[]ucan.Capability[ucan.NoCaveats]{
ucan.NewCapability("test/attach", fixtures.Alice.DID().String(), ucan.NoCaveats{}),
},
)
require.NoError(t, err)

blk := block.NewBlock(helpers.RandomCID(), helpers.RandomBytes(32))
err = dlg.Attach(blk)
require.NoError(t, err)

found := false
for b, err := range dlg.Blocks() {
require.NoError(t, err)
if b.Link().String() == blk.Link().String() {
found = true
break
}
}
require.True(t, found)
}
2 changes: 1 addition & 1 deletion core/invocation/invocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Invocation interface {
delegation.Delegation
}

func NewInvocation(root ipld.Block, bs blockstore.BlockReader) Invocation {
func NewInvocation(root ipld.Block, bs blockstore.BlockReader) (Invocation, error) {
return delegation.NewDelegation(root, bs)
}

Expand Down
26 changes: 26 additions & 0 deletions testing/helpers/helpers.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package helpers

import (
crand "crypto/rand"

"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime/datamodel"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/multiformats/go-multihash"
)

// Must takes return values from a function and returns the non-error one. If
// the error value is non-nil then it panics.
func Must[T any](val T, err error) T {
Expand All @@ -8,3 +17,20 @@ func Must[T any](val T, err error) T {
}
return val
}

func RandomBytes(size int) []byte {
bytes := make([]byte, size)
_, _ = crand.Read(bytes)
return bytes
}

func RandomCID() datamodel.Link {
bytes := RandomBytes(10)
c, _ := cid.Prefix{
Version: 1,
Codec: cid.Raw,
MhType: multihash.SHA2_256,
MhLength: -1,
}.Sum(bytes)
return cidlink.Link{Cid: c}
}
3 changes: 2 additions & 1 deletion validator/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,8 @@ func TestAccess(t *testing.T) {
bs, err := blockstore.NewBlockStore(blockstore.WithBlocks([]block.Block{rt}))
require.NoError(t, err)

dlg := delegation.NewDelegation(rt, bs)
dlg, err := delegation.NewDelegation(rt, bs)
require.NoError(t, err)

inv, err := storeAdd.Invoke(
fixtures.Bob,
Expand Down
Loading