Skip to content
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 .github/workflows/go-workspace-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ on:
workflow_call:
inputs:
go-version:
description: 'Go toolchain to install. Must be >= the max `go` directive across all workspace members (guppy pins 1.26.1).'
description: 'Go toolchain to install. Must be >= the highest `go` directive among the workspace members this run clones. The default tracks the latest release, which satisfies that; override only to pin a specific toolchain.'
type: string
default: 'stable'

Expand Down
71 changes: 55 additions & 16 deletions commands/ucan/cbor_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 79 additions & 0 deletions commands/ucan/codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//go:build !codegen

package ucan_test

import (
"bytes"
"io"
"reflect"
"testing"

ucancmds "github.com/fil-forge/libforge/commands/ucan"
"github.com/ipfs/go-cid"
"github.com/stretchr/testify/require"
)

var (
rcptA = cid.MustParse("bafkreiaixnpf23vkyecj5xqispjq5ubcwgsntnnurw2bjaz5pmjhndcxqi")
rcptB = cid.MustParse("bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy")
)

type wire interface {
MarshalCBOR(w io.Writer) error
UnmarshalCBOR(r io.Reader) error
MarshalDagJSON(w io.Writer) error
UnmarshalDagJSON(r io.Reader) error
}

// roundTrip encodes in as CBOR and DAG-JSON, decodes each and asserts
// equality. It returns the DAG-JSON encoding.
func roundTrip[T any, PT interface {
*T
wire
}](t *testing.T, in PT) string {
t.Helper()
var cb bytes.Buffer
require.NoError(t, in.MarshalCBOR(&cb))
outCBOR := PT(new(T))
require.NoError(t, outCBOR.UnmarshalCBOR(bytes.NewReader(cb.Bytes())))
require.True(t, reflect.DeepEqual(*in, *outCBOR), "CBOR round-trip mismatch:\n got %#v\nwant %#v", *outCBOR, *in)

var jb bytes.Buffer
require.NoError(t, in.MarshalDagJSON(&jb))
outJSON := PT(new(T))
require.NoError(t, outJSON.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())), "json: %s", jb.String())
require.True(t, reflect.DeepEqual(*in, *outJSON), "DAG-JSON round-trip mismatch:\n got %#v\nwant %#v", *outJSON, *in)
return jb.String()
}

// TestConcludeArgumentsOne pins the one-receipt case: still a list, so every
// delivery has the same shape on the wire.
func TestConcludeArgumentsOne(t *testing.T) {
in := &ucancmds.ConcludeArguments{Receipts: []cid.Cid{rcptA}}
require.Equal(t, `{"receipts":[{"/":"`+rcptA.String()+`"}]}`, roundTrip(t, in))
}

func TestConcludeArgumentsMany(t *testing.T) {
in := &ucancmds.ConcludeArguments{Receipts: []cid.Cid{rcptA, rcptB}}
require.Equal(t,
`{"receipts":[{"/":"`+rcptA.String()+`"},{"/":"`+rcptB.String()+`"}]}`,
roundTrip(t, in))
}

// Delivering nothing is a no-op that encodes as an empty list. An empty slice
// decodes back as nil, which every reader treats the same way.
func TestConcludeArgumentsEmpty(t *testing.T) {
var cb bytes.Buffer
require.NoError(t, (&ucancmds.ConcludeArguments{}).MarshalCBOR(&cb))

var out ucancmds.ConcludeArguments
require.NoError(t, out.UnmarshalCBOR(bytes.NewReader(cb.Bytes())))
require.Empty(t, out.Receipts)

var jb bytes.Buffer
require.NoError(t, (&ucancmds.ConcludeArguments{}).MarshalDagJSON(&jb))

var outJSON ucancmds.ConcludeArguments
require.NoError(t, outJSON.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())))
require.Empty(t, outJSON.Receipts)
}
76 changes: 64 additions & 12 deletions commands/ucan/json_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion commands/ucan/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package ucan

import "github.com/ipfs/go-cid"

// ConcludeArguments delivers receipts to an audience awaiting them. It is
// always a list, however many are delivered: a delivering agent often holds a
// receipt per blob of a large upload, and a round trip per receipt costs more
// than the work each one triggers. An empty list delivers nothing.
type ConcludeArguments struct {
Receipt cid.Cid `cborgen:"receipt" dagjsongen:"receipt"`
Receipts []cid.Cid `cborgen:"receipts" dagjsongen:"receipts"`
}

type RevokeArguments struct {
Expand Down