From 7446b55905f9dc8fe80179f44a7a0bed5bf9e7a8 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Tue, 8 Apr 2025 12:02:05 +0200 Subject: [PATCH 01/28] inital implementation --- client/client.go | 316 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/upload.go | 176 ++++++++++++++++++++++++++ cmd/util/util.go | 4 +- cmd/w3.go | 35 +++++- go.mod | 43 +++++-- go.sum | 305 +++++++++++++++++++++++++++++++++++++++------ 6 files changed, 828 insertions(+), 51 deletions(-) create mode 100644 cmd/upload.go diff --git a/client/client.go b/client/client.go index df671487..31a71066 100644 --- a/client/client.go +++ b/client/client.go @@ -2,12 +2,34 @@ package client import ( "fmt" + "io" + "maps" + "net/http" + "net/url" + "slices" + "github.com/ipfs/go-cid" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/multiformats/go-multihash" + "github.com/storacha/go-libstoracha/capabilities/blob" + httpcap "github.com/storacha/go-libstoracha/capabilities/http" + spaceblob "github.com/storacha/go-libstoracha/capabilities/space/blob" + captypes "github.com/storacha/go-libstoracha/capabilities/types" + ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" "github.com/storacha/go-ucanto/client" + "github.com/storacha/go-ucanto/core/dag/blockstore" + "github.com/storacha/go-ucanto/core/delegation" "github.com/storacha/go-ucanto/core/invocation" + "github.com/storacha/go-ucanto/core/invocation/ran" + "github.com/storacha/go-ucanto/core/ipld" "github.com/storacha/go-ucanto/core/receipt" + "github.com/storacha/go-ucanto/core/result" + "github.com/storacha/go-ucanto/core/result/failure" + fdm "github.com/storacha/go-ucanto/core/result/failure/datamodel" "github.com/storacha/go-ucanto/did" "github.com/storacha/go-ucanto/principal" + "github.com/storacha/go-ucanto/principal/ed25519/signer" + "github.com/storacha/go-ucanto/ucan" "github.com/storacha/go-w3up/capability/storeadd" "github.com/storacha/go-w3up/capability/uploadadd" "github.com/storacha/go-w3up/capability/uploadlist" @@ -152,3 +174,297 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat return reader.Read(rcptlnk, resp.Blocks()) } + +// BlobAdd adds a blob to the service. The issuer needs proof of +// `space/blob/add` delegated capability. +// +// Required delegated capability proofs: `space/blob/add` +// +// The `issuer` is the signing authority that is issuing the UCAN invocation. +// +// The `space` is the resource the invocation applies to. It is typically the +// DID of a space. +func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options ...Option) (ipld.Link, delegation.Delegation, error) { + cfg := ClientConfig{conn: DefaultConnection} + for _, opt := range options { + if err := opt(&cfg); err != nil { + return nil, nil, err + } + } + + contentBytes, err := io.ReadAll(content) + if err != nil { + return nil, nil, fmt.Errorf("reading content: %w", err) + } + + contentHash, err := multihash.Sum(contentBytes, multihash.SHA2_256, -1) + if err != nil { + return nil, nil, fmt.Errorf("computing content multihash: %w", err) + } + + contentLink := cidlink.Link{Cid: cid.NewCidV1(0x0202, contentHash)} + + caveats := spaceblob.AddCaveats{ + Blob: spaceblob.Blob{ + Digest: contentHash, + Size: uint64(len(contentBytes)), + }, + } + + inv, err := spaceblob.Add.Invoke(issuer, cfg.conn.ID(), space.String(), caveats, convertToInvocationOptions(cfg)...) + if err != nil { + return nil, nil, fmt.Errorf("generating invocation: %w", err) + } + + resp, err := client.Execute([]invocation.Invocation{inv}, cfg.conn) + if err != nil { + return nil, nil, fmt.Errorf("sending invocation: %w", err) + } + + rcptlnk, ok := resp.Get(inv.Link()) + if !ok { + return nil, nil, fmt.Errorf("receipt not found: %s", inv.Link()) + } + + reader, err := receipt.NewReceiptReaderFromTypes[spaceblob.AddOk, fdm.FailureModel](spaceblob.AddOkType(), fdm.FailureType()) + if err != nil { + return nil, nil, fmt.Errorf("generating receipt reader: %w", err) + } + + rcpt, err := reader.Read(rcptlnk, resp.Blocks()) + if err != nil { + return nil, nil, fmt.Errorf("reading receipt: %w", err) + } + + _, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("blob add failed: %w", err) + } + + var allocateTask, putTask, acceptTask invocation.Invocation + var concludeFxs []invocation.Invocation + for _, task := range rcpt.Fx().Fork() { + inv, ok := task.Invocation() + if ok { + switch inv.Capabilities()[0].Can() { + case blob.AllocateAbility: + allocateTask = inv + case ucancap.ConcludeAbility: + concludeFxs = append(concludeFxs, inv) + case httpcap.PutAbility: + putTask = inv + case blob.AcceptAbility: + acceptTask = inv + } + } + } + + if allocateTask == nil || len(concludeFxs) == 0 || putTask == nil || acceptTask == nil { + return nil, nil, fmt.Errorf("mandatory tasks not received in space/blob/add receipt") + } + + var allocateRcpt receipt.Receipt[blob.AllocateOk, fdm.FailureModel] + var putRcpt receipt.AnyReceipt + var acceptRcpt receipt.Receipt[*blob.AcceptOk, fdm.FailureModel] + for _, concludeFx := range concludeFxs { + concludeRcpt, err := getConcludeReceipt(concludeFx) + if err != nil { + return nil, nil, fmt.Errorf("reading ucan/conclude receipt: %w", err) + } + + switch concludeRcpt.Ran().Link() { + case allocateTask.Link(): + allocateRcpt, err = receipt.Rebind[blob.AllocateOk, fdm.FailureModel](concludeRcpt, blob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) + } + case putTask.Link(): + putRcpt = concludeRcpt + case acceptTask.Link(): + acceptRcpt, err = receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) + } + } + } + + if allocateRcpt == nil { + return nil, nil, fmt.Errorf("mandatory receipts not received in space/blob/add receipt") + } + + allocateOk, err := result.Unwrap(result.MapError(allocateRcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("blob allocation failed: %w", err) + } + + // put the blob where assigned + address := allocateOk.Address + if address == nil { + return nil, nil, fmt.Errorf("blob allocation failed: no address") + } + + if err := putBlob(address.URL, address.Headers, content); err != nil { + return nil, nil, fmt.Errorf("putting blob: %w", err) + } + + // invoke `ucan/conclude` with `http/put` receipt + if putRcpt != nil { + putOk, _ := result.Unwrap(putRcpt.Out()) + if putOk == nil { + putKeys, ok := putTask.Facts()[0]["keys"].(map[string]any) + if !ok { + return nil, nil, fmt.Errorf("invalid put facts") + } + + derivedKey, ok := slices.Collect(maps.Values(putKeys))[0].([]byte) + if !ok { + return nil, nil, fmt.Errorf("invalid derived key") + } + + derivedSigner, err := signer.FromRaw(derivedKey) + if err != nil { + return nil, nil, fmt.Errorf("deriving signer: %w", err) + } + + putRcpt, err = receipt.Issue(derivedSigner, result.Ok[httpcap.PutOk, ipld.Builder](httpcap.PutOk{}), ran.FromLink(putTask.Link())) + if err != nil { + return nil, nil, fmt.Errorf("generating receipt: %w", err) + } + + // var concludeFacts []ucan.FactBuilder + // for rcptBlock, err := range putRcpt.Blocks() { + // if err != nil { + // return nil, nil, fmt.Errorf("getting receipt block: %w", err) + // } + + // concludeFacts = append(concludeFacts, rcptBlock.Link()) + // } + + httpPutConcludeInvocation, err := ucancap.Conclude.Invoke( + derivedSigner, + cfg.conn.ID(), + issuer.DID().String(), + ucancap.ConcludeCaveats{ + Receipt: putRcpt.Root().Link(), + }, + // delegation.WithFacts(concludeFacts), + delegation.WithNoExpiration(), + ) + if err != nil { + return nil, nil, fmt.Errorf("generating invocation: %w", err) + } + + // attach the receipt to the conclude invocation + for rcptBlock, err := range putRcpt.Blocks() { + if err != nil { + return nil, nil, fmt.Errorf("getting receipt block: %w", err) + } + httpPutConcludeInvocation.Attach(rcptBlock) + } + + resp, err := client.Execute([]invocation.Invocation{httpPutConcludeInvocation}, cfg.conn) + if err != nil { + return nil, nil, fmt.Errorf("executing conclude invocation: %w", err) + } + + rcptlnk, ok := resp.Get(httpPutConcludeInvocation.Link()) + if !ok { + return nil, nil, fmt.Errorf("receipt not found: %s", httpPutConcludeInvocation.Link()) + } + + reader, err := receipt.NewReceiptReaderFromTypes[ucancap.ConcludeOk, fdm.FailureModel](ucancap.ConcludeOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("generating receipt reader: %w", err) + } + + rcpt, err := reader.Read(rcptlnk, resp.Blocks()) + if err != nil { + return nil, nil, fmt.Errorf("reading receipt: %w", err) + } + + _, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("ucan/conclude failed: %w", err) + } + } + } + + // ensure the blob has been accepted + if acceptRcpt != nil { + acceptOk, _ := result.Unwrap(acceptRcpt.Out()) + if acceptOk == nil { + acceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn) + if err != nil { + return nil, nil, fmt.Errorf("polling blob accept: %w", err) + } + + _, acceptFail := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) + if acceptFail != nil { + return nil, nil, fmt.Errorf("blob/accept failed: %w", acceptFail) + } + } + } + + acceptOk, _ := result.Unwrap(acceptRcpt.Out()) + + locationBlocks, err := blockstore.NewBlockStore(blockstore.WithBlocksIterator(acceptRcpt.Blocks())) + if err != nil { + return nil, nil, fmt.Errorf("reading location commitment blocks: %w", err) + } + + location, err := delegation.NewDelegationView(acceptOk.Site, locationBlocks) + if err != nil { + return nil, nil, fmt.Errorf("creating location delegation: %w", err) + } + + return contentLink, location, nil +} + +func getConcludeReceipt(concludeFx invocation.Invocation) (receipt.AnyReceipt, error) { + concludeNb, fail := ucancap.ConcludeCaveatsReader.Read(concludeFx.Capabilities()[0].Nb()) + if fail != nil { + return nil, fmt.Errorf("invalid conclude receipt: %w", fail) + } + + reader := receipt.NewAnyReceiptReader(captypes.Converters...) + rcpt, err := reader.Read(concludeNb.Receipt, concludeFx.Blocks()) + if err != nil { + return nil, fmt.Errorf("reading receipt: %w", err) + } + + return rcpt, nil +} + +func putBlob(url url.URL, headers http.Header, body io.Reader) error { + req, err := http.NewRequest(http.MethodPut, url.String(), body) + if err != nil { + return fmt.Errorf("creating upload request: %w", err) + } + + for k, v := range headers { + req.Header.Set(k, v[0]) + } + + // TODO: custom HTTP client with timeout + // TODO: retries + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("uploading blob: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("uploading blob: %s", resp.Status) + } + + return nil +} + +func pollAccept(link ucan.Link, conn client.Connection) (receipt.Receipt[*blob.AcceptOk, fdm.FailureModel], error) { + rcpt, err := receipt.Issue(ucan.Signer(signer.Ed25519Signer{}), result.Ok[*blob.AcceptOk, ipld.Builder](&blob.AcceptOk{}), ran.FromLink(link)) + if err != nil { + return nil, fmt.Errorf("generating receipt: %w", err) + } + + return receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](rcpt, blob.AcceptOkType(), fdm.FailureType()) +} diff --git a/cmd/upload.go b/cmd/upload.go new file mode 100644 index 00000000..a0f09ab8 --- /dev/null +++ b/cmd/upload.go @@ -0,0 +1,176 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" + + uclient "github.com/storacha/go-ucanto/client" + "github.com/storacha/go-ucanto/core/car" + "github.com/storacha/go-ucanto/core/delegation" + "github.com/storacha/go-ucanto/core/ipld" + "github.com/storacha/go-ucanto/core/result" + "github.com/storacha/go-ucanto/did" + "github.com/storacha/go-ucanto/principal" + "github.com/storacha/go-w3up/capability/uploadadd" + "github.com/storacha/go-w3up/car/sharding" + "github.com/storacha/go-w3up/client" + "github.com/storacha/go-w3up/cmd/util" + "github.com/urfave/cli/v2" +) + +// upload handles file and directory uploads to Storacha +func upload(cCtx *cli.Context) error { + signer := util.MustGetSigner() + conn := util.MustGetConnection() + space := util.MustParseDID(cCtx.String("space")) + proofs := []delegation.Delegation{util.MustGetProof(cCtx.String("proof"))} + + // Handle options + isCAR := cCtx.String("car") != "" + isJSON := cCtx.Bool("json") + // isVerbose := cCtx.Bool("verbose") + isWrap := cCtx.Bool("wrap") + // shardSize := cCtx.Int("shard-size") + // concurrentRequests := cCtx.Int("concurrent-requests") + + var paths []string + if isCAR { + paths = []string{cCtx.String("car")} + } else { + paths = cCtx.Args().Slice() + } + + var root ipld.Link + if isCAR { + var err error + root, err = uploadCAR(paths[0], signer, conn, space, proofs) + if err != nil { + return err + } + } else { + if len(paths) == 1 && !isWrap { + var err error + root, err = uploadFile(paths[0], signer, conn, space, proofs) + if err != nil { + return err + } + } else { + var err error + root, err = uploadDirectory(paths, signer, conn, space, proofs) + if err != nil { + return err + } + } + } + + if isJSON { + fmt.Printf("{\"root\":\"%s\"}\n", root) + } else { + fmt.Printf("⁂ https://w3s.link/ipfs/%s\n", root) + } + + return nil +} + +func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { + f0, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("opening file: %s", err) + } + defer f0.Close() + + var shdlnks []ipld.Link + + stat, err := f0.Stat() + if err != nil { + return nil, fmt.Errorf("stat file: %s", err) + } + + if stat.Size() < sharding.ShardSize { + link, err := addBlob(f0, signer, conn, space, proofs) + if err != nil { + return nil, err + } + + shdlnks = append(shdlnks, link) + } else { + _, blocks, err := car.Decode(f0) + if err != nil { + log.Fatalf("decoding CAR: %s", err) + } + shds, err := sharding.NewSharder([]ipld.Link{}, blocks) + if err != nil { + log.Fatalf("sharding CAR: %s", err) + } + + for shd, err := range shds { + if err != nil { + log.Fatal(err) + } + + link, err := addBlob(shd, signer, conn, space, proofs) + if err != nil { + return nil, err + } + + shdlnks = append(shdlnks, link) + } + } + + // TODO: build, add and register index + + f1, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("opening file: %s", err) + } + defer f1.Close() + + roots, _, err := car.Decode(f1) + if err != nil { + return nil, fmt.Errorf("reading roots: %s", err) + } + + if len(roots) == 0 { + return nil, fmt.Errorf("missing root CID") + } + + rcpt, err := client.UploadAdd( + signer, + space, + uploadadd.Caveat{ + Root: roots[0], + Shards: shdlnks, + }, + client.WithConnection(conn), + client.WithProofs(proofs), + ) + if err != nil { + return nil, err + } + + _, upFailure := result.Unwrap(rcpt.Out()) + if upFailure != nil { + return nil, fmt.Errorf("%+v\n", upFailure) + } + + return roots[0], nil +} + +func uploadFile(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { + return nil, nil +} + +func uploadDirectory(paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { + return nil, nil +} + +func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { + contentLink, _, err := client.BlobAdd(content, signer, space, client.WithConnection(conn), client.WithProofs(proofs)) + if err != nil { + return nil, err + } + + return contentLink, nil +} diff --git a/cmd/util/util.go b/cmd/util/util.go index 501416e0..4e17586c 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -94,12 +94,12 @@ func mustReadConfig() *configurationModel { func MustGetConnection() client.Connection { // service URL & DID - serviceURL, err := url.Parse("https://up.web3.storage") + serviceURL, err := url.Parse("https://staging.upload.storacha.network") if err != nil { log.Fatal(err) } - servicePrincipal, err := did.Parse("did:web:web3.storage") + servicePrincipal, err := did.Parse("did:web:staging.upload.storacha.network") if err != nil { log.Fatal(err) } diff --git a/cmd/w3.go b/cmd/w3.go index 8793e0c2..10a879f6 100644 --- a/cmd/w3.go +++ b/cmd/w3.go @@ -57,8 +57,41 @@ func main() { Value: "", Usage: "Path to CAR file to upload.", }, + &cli.BoolFlag{ + Name: "hidden", + Aliases: []string{"H"}, + Value: false, + Usage: "Include paths that start with \".\".", + }, + &cli.BoolFlag{ + Name: "json", + Aliases: []string{"j"}, + Value: false, + Usage: "Format as newline delimited JSON", + }, + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Value: false, + Usage: "Output more details.", + }, + &cli.BoolFlag{ + Name: "wrap", + Value: true, + Usage: "Wrap single input file in a directory. Has no effect on directory or CAR uploads. Pass --no-wrap to disable.", + }, + &cli.IntFlag{ + Name: "shard-size", + Value: 0, + Usage: "Shard uploads into CAR files of approximately this size in bytes.", + }, + &cli.IntFlag{ + Name: "concurrent-requests", + Value: 5, + Usage: "Send up to this many CAR shards concurrently.", + }, }, - Action: up, + Action: upload, }, { Name: "ls", diff --git a/go.mod b/go.mod index 3ef5dce3..eb4f1b00 100644 --- a/go.mod +++ b/go.mod @@ -2,22 +2,34 @@ module github.com/storacha/go-w3up go 1.23.3 +replace github.com/storacha/go-libstoracha => ../go-libstoracha + +replace github.com/storacha/go-ucanto => ../go-ucanto + require ( - github.com/ipfs/go-cid v0.4.1 + github.com/ipfs/go-cid v0.5.0 github.com/ipld/go-ipld-prime v0.21.1-0.20240917223228-6148356a4c2e github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-varint v0.0.7 + github.com/storacha/go-libstoracha v0.0.0-00010101000000-000000000000 github.com/storacha/go-ucanto v0.3.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.25.7 ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/filecoin-project/go-data-segment v0.0.1 // indirect + github.com/filecoin-project/go-fil-commcid v0.2.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/ipfs/bbloom v0.0.4 // indirect @@ -39,32 +51,49 @@ require ( github.com/ipld/go-car v0.6.2 // indirect github.com/ipld/go-codec-dagpb v1.6.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect + github.com/multiformats/go-multiaddr v0.14.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/onsi/ginkgo/v2 v2.23.3 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/ice/v2 v2.3.37 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/sctp v1.8.37 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/webrtc/v4 v4.0.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.0 // indirect + github.com/quic-go/qpack v0.5.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/whyrusleeping/cbor-gen v0.1.2 // indirect + github.com/ucan-wg/go-ucan v0.0.0-20240916120445-37f52863156c // indirect + github.com/whyrusleeping/cbor-gen v0.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect go.uber.org/atomic v1.11.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 702a2c25..a0151782 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= @@ -36,9 +38,15 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -46,9 +54,16 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -57,6 +72,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -67,8 +83,11 @@ github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TI github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -77,10 +96,22 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/filecoin-project/go-data-segment v0.0.1 h1:1wmDxOG4ubWQm3ZC1XI5nCon5qgSq7Ra3Rb6Dbu10Gs= +github.com/filecoin-project/go-data-segment v0.0.1/go.mod h1:H0/NKbsRxmRFBcLibmABv+yFNHdmtl5AyplYLnb0Zv4= +github.com/filecoin-project/go-fil-commcid v0.2.0 h1:B+5UX8XGgdg/XsdUpST4pEBviKkFOw+Fvl2bLhSKGpI= +github.com/filecoin-project/go-fil-commcid v0.2.0/go.mod h1:8yigf3JDIil+/WpqR5zoKyP0jBPCOGtEqq/K1CcMy9Q= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -89,14 +120,20 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -136,8 +173,10 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= @@ -155,15 +194,22 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -200,8 +246,8 @@ github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNi github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= @@ -252,8 +298,12 @@ github.com/ipld/go-ipld-prime v0.21.1-0.20240917223228-6148356a4c2e/go.mod h1:LN github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -261,8 +311,10 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -270,6 +322,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -277,8 +330,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= -github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= +github.com/libp2p/go-libp2p v0.39.1 h1:1Ur6rPCf3GR+g8jkrnaQaM0ha2IGespsnNlCqJLLALE= +github.com/libp2p/go-libp2p v0.39.1/go.mod h1:3zicI8Lp7Isun+Afo/JOACUbbJqqR2owK6RQWFsVAbI= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= @@ -291,19 +344,17 @@ github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= -github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= -github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= -github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -315,6 +366,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -323,10 +375,8 @@ github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aG github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= -github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= -github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= +github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= @@ -335,16 +385,69 @@ github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3 github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= -github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= +github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= +github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= +github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= +github.com/pion/ice/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0= +github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= +github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.13 h1:8uSUPpjSL4OlwZI8Ygqu7+h2p9NPFB+yAZ461Xn5sNg= +github.com/pion/rtp v1.8.13/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.11 h1:VhgVSopdsBKwhCFoyyPmT1fKMeV9nLMrEKxNOdy3IVI= +github.com/pion/sdp/v3 v3.0.11/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= +github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/turn/v2 v2.1.3 h1:pYxTVWG2gpC97opdRc5IGsQ1lJ9O/IlNhkzj7MMrGAA= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= +github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= +github.com/pion/webrtc/v4 v4.0.14 h1:nyds/sFRR+HvmWoBa6wrL46sSfpArE0qR883MBW96lg= +github.com/pion/webrtc/v4 v4.0.14/go.mod h1:R3+qTnQTS03UzwDarYecgioNf7DYgTsldxnCXB821Kk= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -354,20 +457,62 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a h1:cgqrm0F3zwf9IPzca7xN4w+Zy6MC9ZkPvAC8QEWa/iQ= github.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a/go.mod h1:ocZfO/tLSHqfScRDNTJbAJR1by4D1lewauX9OwTaPuY= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= +github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= +github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= @@ -375,8 +520,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -385,27 +530,39 @@ github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t6 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/storacha/go-ucanto v0.3.0 h1:m4jDVREdA6VjcI+j3/lMmRDCmP8gijDk+EkzzC6ANBU= -github.com/storacha/go-ucanto v0.3.0/go.mod h1:kslS8xldf12d2D4kj0wBfOvAP1gftzMjTxBdJwGKwZE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/ucan-wg/go-ucan v0.0.0-20240916120445-37f52863156c h1:A1pMNIlHPnJ6KROqNc6SKg7QlSiQA6umiEoy89Os4cM= +github.com/ucan-wg/go-ucan v0.0.0-20240916120445-37f52863156c/go.mod h1:IiRc1OKWUk7FziOTWmOo7iwbcEMr7ch0lgs3UrF13pU= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= -github.com/whyrusleeping/cbor-gen v0.1.2 h1:WQFlrPhpcQl+M2/3dP5cvlTLWPVsL6LGBb9jJt6l/cA= -github.com/whyrusleeping/cbor-gen v0.1.2/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/whyrusleeping/cbor-gen v0.2.0 h1:v8DREoK/1qQBSc6/UZ4OgU06+9FkywTh8glX0Hi+jkc= +github.com/whyrusleeping/cbor-gen v0.2.0/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -417,6 +574,7 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -437,6 +595,8 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -447,8 +607,12 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -456,8 +620,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -468,8 +635,11 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -495,15 +665,20 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -536,9 +711,15 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -550,6 +731,7 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -562,13 +744,17 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -612,12 +798,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -628,10 +823,18 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -687,14 +890,18 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -718,6 +925,8 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -725,6 +934,10 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -765,6 +978,9 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -797,14 +1013,17 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -814,6 +1033,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -826,3 +1047,5 @@ lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= From 4b8f87bcec651920c8a90c7b8cc722c5b6994e66 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 9 Apr 2025 13:02:38 +0200 Subject: [PATCH 02/28] use legacy blob capabilities --- client/client.go | 107 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/client/client.go b/client/client.go index 31a71066..24ce17a3 100644 --- a/client/client.go +++ b/client/client.go @@ -16,6 +16,7 @@ import ( spaceblob "github.com/storacha/go-libstoracha/capabilities/space/blob" captypes "github.com/storacha/go-libstoracha/capabilities/types" ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" + w3sBlob "github.com/storacha/go-libstoracha/capabilities/web3.storage/blob" "github.com/storacha/go-ucanto/client" "github.com/storacha/go-ucanto/core/dag/blockstore" "github.com/storacha/go-ucanto/core/delegation" @@ -226,19 +227,21 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options return nil, nil, fmt.Errorf("receipt not found: %s", inv.Link()) } - reader, err := receipt.NewReceiptReaderFromTypes[spaceblob.AddOk, fdm.FailureModel](spaceblob.AddOkType(), fdm.FailureType()) - if err != nil { - return nil, nil, fmt.Errorf("generating receipt reader: %w", err) - } + // reader, err := receipt.NewReceiptReaderFromTypes[spaceblob.AddOk, fdm.FailureModel](spaceblob.AddOkType(), fdm.FailureType()) + // if err != nil { + // return nil, nil, fmt.Errorf("generating receipt reader: %w", err) + // } + reader := receipt.NewAnyReceiptReader(captypes.Converters...) rcpt, err := reader.Read(rcptlnk, resp.Blocks()) if err != nil { return nil, nil, fmt.Errorf("reading receipt: %w", err) } - _, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) - if err != nil { - return nil, nil, fmt.Errorf("blob add failed: %w", err) + //_, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) + _, fail := result.Unwrap(rcpt.Out()) + if fail != nil { + return nil, nil, fmt.Errorf("blob add failed: %w", fail) } var allocateTask, putTask, acceptTask invocation.Invocation @@ -249,12 +252,20 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options switch inv.Capabilities()[0].Can() { case blob.AllocateAbility: allocateTask = inv + case w3sBlob.AllocateAbility: + if allocateTask == nil { + allocateTask = inv + } case ucancap.ConcludeAbility: concludeFxs = append(concludeFxs, inv) case httpcap.PutAbility: putTask = inv case blob.AcceptAbility: acceptTask = inv + case w3sBlob.AcceptAbility: + if acceptTask == nil { + acceptTask = inv + } } } } @@ -264,8 +275,10 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options } var allocateRcpt receipt.Receipt[blob.AllocateOk, fdm.FailureModel] + var legacyAllocateRcpt receipt.Receipt[w3sBlob.AllocateOk, fdm.FailureModel] var putRcpt receipt.AnyReceipt var acceptRcpt receipt.Receipt[*blob.AcceptOk, fdm.FailureModel] + var legacyAcceptRcpt receipt.Receipt[*w3sBlob.AcceptOk, fdm.FailureModel] for _, concludeFx := range concludeFxs { concludeRcpt, err := getConcludeReceipt(concludeFx) if err != nil { @@ -274,36 +287,71 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options switch concludeRcpt.Ran().Link() { case allocateTask.Link(): - allocateRcpt, err = receipt.Rebind[blob.AllocateOk, fdm.FailureModel](concludeRcpt, blob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) - if err != nil { - return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) + switch allocateTask.Capabilities()[0].Can() { + case blob.AllocateAbility: + allocateRcpt, err = receipt.Rebind[blob.AllocateOk, fdm.FailureModel](concludeRcpt, blob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) + } + case w3sBlob.AllocateAbility: + legacyAllocateRcpt, err = receipt.Rebind[w3sBlob.AllocateOk, fdm.FailureModel](concludeRcpt, w3sBlob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) + } } case putTask.Link(): putRcpt = concludeRcpt case acceptTask.Link(): - acceptRcpt, err = receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) - if err != nil { - return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) + switch allocateTask.Capabilities()[0].Can() { + case blob.AcceptAbility: + acceptRcpt, err = receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) + } + case w3sBlob.AcceptAbility: + legacyAcceptRcpt, err = receipt.Rebind[*w3sBlob.AcceptOk, fdm.FailureModel](concludeRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) + } } } } - if allocateRcpt == nil { + if allocateRcpt == nil && legacyAllocateRcpt == nil { return nil, nil, fmt.Errorf("mandatory receipts not received in space/blob/add receipt") } - allocateOk, err := result.Unwrap(result.MapError(allocateRcpt.Out(), failure.FromFailureModel)) - if err != nil { - return nil, nil, fmt.Errorf("blob allocation failed: %w", err) - } + var url url.URL + var headers http.Header + if allocateRcpt != nil { + allocateOk, err := result.Unwrap(result.MapError(allocateRcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("blob allocation failed: %w", err) + } + + address := allocateOk.Address + if address == nil { + return nil, nil, fmt.Errorf("blob allocation failed: no address") + } + + url = address.URL + headers = address.Headers + } else { + allocateOk, err := result.Unwrap(result.MapError(legacyAllocateRcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("blob allocation failed: %w", err) + } - // put the blob where assigned - address := allocateOk.Address - if address == nil { - return nil, nil, fmt.Errorf("blob allocation failed: no address") + address := allocateOk.Address + if address == nil { + return nil, nil, fmt.Errorf("blob allocation failed: no address") + } + + url = address.URL + headers = address.Headers } - if err := putBlob(address.URL, address.Headers, content); err != nil { + if err := putBlob(url, headers, content); err != nil { return nil, nil, fmt.Errorf("putting blob: %w", err) } @@ -398,6 +446,19 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options return nil, nil, fmt.Errorf("polling blob accept: %w", err) } + _, acceptFail := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) + if acceptFail != nil { + return nil, nil, fmt.Errorf("blob/accept failed: %w", acceptFail) + } + } + } else if legacyAcceptRcpt != nil { + acceptOk, _ := result.Unwrap(legacyAcceptRcpt.Out()) + if acceptOk == nil { + acceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn) + if err != nil { + return nil, nil, fmt.Errorf("polling blob accept: %w", err) + } + _, acceptFail := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) if acceptFail != nil { return nil, nil, fmt.Errorf("blob/accept failed: %w", acceptFail) From b9e9698dc089923344ba6a529a4732940bfef0e1 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 9 Apr 2025 15:48:11 +0200 Subject: [PATCH 03/28] fix HTTP PUT request not having ContentLength set --- client/client.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/client.go b/client/client.go index 24ce17a3..18426700 100644 --- a/client/client.go +++ b/client/client.go @@ -1,6 +1,7 @@ package client import ( + "bytes" "fmt" "io" "maps" @@ -351,7 +352,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options headers = address.Headers } - if err := putBlob(url, headers, content); err != nil { + if err := putBlob(url, headers, contentBytes); err != nil { return nil, nil, fmt.Errorf("putting blob: %w", err) } @@ -496,8 +497,8 @@ func getConcludeReceipt(concludeFx invocation.Invocation) (receipt.AnyReceipt, e return rcpt, nil } -func putBlob(url url.URL, headers http.Header, body io.Reader) error { - req, err := http.NewRequest(http.MethodPut, url.String(), body) +func putBlob(url url.URL, headers http.Header, body []byte) error { + req, err := http.NewRequest(http.MethodPut, url.String(), bytes.NewReader(body)) if err != nil { return fmt.Errorf("creating upload request: %w", err) } @@ -513,6 +514,8 @@ func putBlob(url url.URL, headers http.Header, body io.Reader) error { if err != nil { return fmt.Errorf("uploading blob: %w", err) } + io.ReadAll(resp.Body) + resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("uploading blob: %s", resp.Status) From 8046cb8133ed9bda43dd53ead9516598f12ba483 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 9 Apr 2025 18:50:58 +0200 Subject: [PATCH 04/28] fix ucan/conclude with http/put receipt --- client/client.go | 214 ++++++++++++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 78 deletions(-) diff --git a/client/client.go b/client/client.go index 18426700..d285430f 100644 --- a/client/client.go +++ b/client/client.go @@ -4,10 +4,8 @@ import ( "bytes" "fmt" "io" - "maps" "net/http" "net/url" - "slices" "github.com/ipfs/go-cid" cidlink "github.com/ipld/go-ipld-prime/linking/cid" @@ -357,84 +355,12 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options } // invoke `ucan/conclude` with `http/put` receipt - if putRcpt != nil { + if putRcpt == nil { + sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn) + } else { putOk, _ := result.Unwrap(putRcpt.Out()) if putOk == nil { - putKeys, ok := putTask.Facts()[0]["keys"].(map[string]any) - if !ok { - return nil, nil, fmt.Errorf("invalid put facts") - } - - derivedKey, ok := slices.Collect(maps.Values(putKeys))[0].([]byte) - if !ok { - return nil, nil, fmt.Errorf("invalid derived key") - } - - derivedSigner, err := signer.FromRaw(derivedKey) - if err != nil { - return nil, nil, fmt.Errorf("deriving signer: %w", err) - } - - putRcpt, err = receipt.Issue(derivedSigner, result.Ok[httpcap.PutOk, ipld.Builder](httpcap.PutOk{}), ran.FromLink(putTask.Link())) - if err != nil { - return nil, nil, fmt.Errorf("generating receipt: %w", err) - } - - // var concludeFacts []ucan.FactBuilder - // for rcptBlock, err := range putRcpt.Blocks() { - // if err != nil { - // return nil, nil, fmt.Errorf("getting receipt block: %w", err) - // } - - // concludeFacts = append(concludeFacts, rcptBlock.Link()) - // } - - httpPutConcludeInvocation, err := ucancap.Conclude.Invoke( - derivedSigner, - cfg.conn.ID(), - issuer.DID().String(), - ucancap.ConcludeCaveats{ - Receipt: putRcpt.Root().Link(), - }, - // delegation.WithFacts(concludeFacts), - delegation.WithNoExpiration(), - ) - if err != nil { - return nil, nil, fmt.Errorf("generating invocation: %w", err) - } - - // attach the receipt to the conclude invocation - for rcptBlock, err := range putRcpt.Blocks() { - if err != nil { - return nil, nil, fmt.Errorf("getting receipt block: %w", err) - } - httpPutConcludeInvocation.Attach(rcptBlock) - } - - resp, err := client.Execute([]invocation.Invocation{httpPutConcludeInvocation}, cfg.conn) - if err != nil { - return nil, nil, fmt.Errorf("executing conclude invocation: %w", err) - } - - rcptlnk, ok := resp.Get(httpPutConcludeInvocation.Link()) - if !ok { - return nil, nil, fmt.Errorf("receipt not found: %s", httpPutConcludeInvocation.Link()) - } - - reader, err := receipt.NewReceiptReaderFromTypes[ucancap.ConcludeOk, fdm.FailureModel](ucancap.ConcludeOkType(), fdm.FailureType(), captypes.Converters...) - if err != nil { - return nil, nil, fmt.Errorf("generating receipt reader: %w", err) - } - - rcpt, err := reader.Read(rcptlnk, resp.Blocks()) - if err != nil { - return nil, nil, fmt.Errorf("reading receipt: %w", err) - } - - _, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) - if err != nil { - return nil, nil, fmt.Errorf("ucan/conclude failed: %w", err) - } + sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn) } } @@ -524,6 +450,138 @@ func putBlob(url url.URL, headers http.Header, body []byte) error { return nil } +func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience ucan.Principal, conn client.Connection) error { + putKeysNode, ok := putTask.Facts()[0]["keys"].(ipld.Node) + if !ok { + return fmt.Errorf("invalid put facts") + } + + // TODO: define a schema and use bindnode.Rebind rather than doing this manually + var id did.DID + keys := map[string][]byte{} + it := putKeysNode.MapIterator() + for !it.Done() { + k, v, err := it.Next() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + kStr, err := k.AsString() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + switch kStr { + case "id": + // v is a did string + vStr, err := v.AsString() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + id, err = did.Parse(vStr) + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + case "keys": + // v is a did to key map + it2 := v.MapIterator() + for !it2.Done() { + k2, v2, err := it2.Next() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + k2Str, err := k2.AsString() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + v2Bytes, err := v2.AsBytes() + if err != nil { + return fmt.Errorf("invalid put facts: %w", err) + } + + keys[k2Str] = v2Bytes + } + } + } + + derivedKey, ok := keys[id.String()] + if !ok { + return fmt.Errorf("invalid put facts: missing key for %s", id.String()) + } + + derivedSigner, err := signer.Decode(derivedKey) + if err != nil { + return fmt.Errorf("deriving signer: %w", err) + } + + putRcpt, err := receipt.Issue(derivedSigner, result.Ok[httpcap.PutOk, ipld.Builder](httpcap.PutOk{}), ran.FromInvocation(putTask)) + if err != nil { + return fmt.Errorf("generating receipt: %w", err) + } + + // var concludeFacts []ucan.FactBuilder + // for rcptBlock, err := range putRcpt.Blocks() { + // if err != nil { + // return nil, nil, fmt.Errorf("getting receipt block: %w", err) + // } + + // concludeFacts = append(concludeFacts, rcptBlock.Link()) + // } + + httpPutConcludeInvocation, err := ucancap.Conclude.Invoke( + issuer, + audience, + issuer.DID().String(), + ucancap.ConcludeCaveats{ + Receipt: putRcpt.Root().Link(), + }, + // delegation.WithFacts(concludeFacts), + delegation.WithNoExpiration(), + ) + if err != nil { + return fmt.Errorf("generating invocation: %w", err) + } + + // attach the receipt to the conclude invocation + for rcptBlock, err := range putRcpt.Blocks() { + if err != nil { + return fmt.Errorf("getting receipt block: %w", err) + } + + httpPutConcludeInvocation.Attach(rcptBlock) + } + + resp, err := client.Execute([]invocation.Invocation{httpPutConcludeInvocation}, conn) + if err != nil { + return fmt.Errorf("executing conclude invocation: %w", err) + } + + rcptlnk, ok := resp.Get(httpPutConcludeInvocation.Link()) + if !ok { + return fmt.Errorf("receipt not found: %s", httpPutConcludeInvocation.Link()) + } + + reader, err := receipt.NewReceiptReaderFromTypes[ucancap.ConcludeOk, fdm.FailureModel](ucancap.ConcludeOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return fmt.Errorf("generating receipt reader: %w", err) + } + + rcpt, err := reader.Read(rcptlnk, resp.Blocks()) + if err != nil { + return fmt.Errorf("reading receipt: %w", err) + } + + _, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) + if err != nil { + return fmt.Errorf("ucan/conclude failed: %w", err) + } + + return nil +} + func pollAccept(link ucan.Link, conn client.Connection) (receipt.Receipt[*blob.AcceptOk, fdm.FailureModel], error) { rcpt, err := receipt.Issue(ucan.Signer(signer.Ed25519Signer{}), result.Ok[*blob.AcceptOk, ipld.Builder](&blob.AcceptOk{}), ran.FromLink(link)) if err != nil { From 94de2f8d264f2325023a119bec7e36f97ea3aa8e Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 9 Apr 2025 19:00:58 +0200 Subject: [PATCH 05/28] wip: poll receipts endpoint for blob/accept receipt --- client/client.go | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/client/client.go b/client/client.go index d285430f..cadb75d9 100644 --- a/client/client.go +++ b/client/client.go @@ -365,31 +365,18 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options } // ensure the blob has been accepted - if acceptRcpt != nil { - acceptOk, _ := result.Unwrap(acceptRcpt.Out()) - if acceptOk == nil { - acceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn) - if err != nil { - return nil, nil, fmt.Errorf("polling blob accept: %w", err) - } - - _, acceptFail := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) - if acceptFail != nil { - return nil, nil, fmt.Errorf("blob/accept failed: %w", acceptFail) - } + if acceptRcpt == nil && legacyAcceptRcpt == nil { + pollAccept(acceptTask.Link(), cfg.conn) + } else { + var ok any + if acceptRcpt != nil { + ok, _ = result.Unwrap(acceptRcpt.Out()) + } else { + ok, _ = result.Unwrap(legacyAcceptRcpt.Out()) } - } else if legacyAcceptRcpt != nil { - acceptOk, _ := result.Unwrap(legacyAcceptRcpt.Out()) - if acceptOk == nil { - acceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn) - if err != nil { - return nil, nil, fmt.Errorf("polling blob accept: %w", err) - } - _, acceptFail := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) - if acceptFail != nil { - return nil, nil, fmt.Errorf("blob/accept failed: %w", acceptFail) - } + if ok == nil { + pollAccept(acceptTask.Link(), cfg.conn) } } From 27475df9a7d737200049d3e6d41c6a125fe1356f Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 9 Apr 2025 19:15:12 +0200 Subject: [PATCH 06/28] point to new service in staging --- cmd/util/util.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/util/util.go b/cmd/util/util.go index 4e17586c..e3e20b04 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -94,12 +94,12 @@ func mustReadConfig() *configurationModel { func MustGetConnection() client.Connection { // service URL & DID - serviceURL, err := url.Parse("https://staging.upload.storacha.network") + serviceURL, err := url.Parse("https://staging.up.storacha.network") if err != nil { log.Fatal(err) } - servicePrincipal, err := did.Parse("did:web:staging.upload.storacha.network") + servicePrincipal, err := did.Parse("did:web:staging.up.storacha.network") if err != nil { log.Fatal(err) } From 3a0e1f90dcc56b469d5ce5018813797248a00745 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Thu, 17 Apr 2025 17:35:24 +0200 Subject: [PATCH 07/28] get receipts URL --- cmd/util/util.go | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/cmd/util/util.go b/cmd/util/util.go index e3e20b04..ad6b2ef8 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -2,6 +2,7 @@ package util import ( _ "embed" + "fmt" "log" "net/url" "os" @@ -20,6 +21,8 @@ import ( cdg "github.com/storacha/go-w3up/delegation" ) +const defaultServiceName = "staging.up.storacha.network" + //go:embed config.ipldsch var configsch []byte @@ -94,12 +97,22 @@ func mustReadConfig() *configurationModel { func MustGetConnection() client.Connection { // service URL & DID - serviceURL, err := url.Parse("https://staging.up.storacha.network") + serviceURLStr := os.Getenv("RACHA_SERVICE_URL") // use env var preferably + if serviceURLStr == "" { + serviceURLStr = fmt.Sprintf("https://%s", defaultServiceName) + } + + serviceURL, err := url.Parse(serviceURLStr) if err != nil { log.Fatal(err) } - servicePrincipal, err := did.Parse("did:web:staging.up.storacha.network") + serviceDIDStr := os.Getenv("RACHA_SERVICE_DID") + if serviceDIDStr == "" { + serviceDIDStr = fmt.Sprintf("did:web:%s", defaultServiceName) + } + + servicePrincipal, err := did.Parse(serviceDIDStr) if err != nil { log.Fatal(err) } @@ -116,6 +129,20 @@ func MustGetConnection() client.Connection { return conn } +func MustGetReceiptsURL() *url.URL { + receiptsURLStr := os.Getenv("RACHA_RECEIPTS_URL") + if receiptsURLStr == "" { + receiptsURLStr = fmt.Sprintf("https://%s/receipt", defaultServiceName) + } + + receiptsURL, err := url.Parse(receiptsURLStr) + if err != nil { + log.Fatal(err) + } + + return receiptsURL +} + func MustParseDID(str string) did.DID { did, err := did.Parse(str) if err != nil { From d638c08db09f7d4111488fb9ab1e69067d9f53e7 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Fri, 18 Apr 2025 01:53:50 +0200 Subject: [PATCH 08/28] poll accept receipt --- client/client.go | 142 +++++++++++++++++++++++++++++++++++++++-------- cmd/upload.go | 22 ++++---- 2 files changed, 131 insertions(+), 33 deletions(-) diff --git a/client/client.go b/client/client.go index cadb75d9..c9248947 100644 --- a/client/client.go +++ b/client/client.go @@ -4,8 +4,10 @@ import ( "bytes" "fmt" "io" + "iter" "net/http" "net/url" + "time" "github.com/ipfs/go-cid" cidlink "github.com/ipld/go-ipld-prime/linking/cid" @@ -22,6 +24,7 @@ import ( "github.com/storacha/go-ucanto/core/invocation" "github.com/storacha/go-ucanto/core/invocation/ran" "github.com/storacha/go-ucanto/core/ipld" + "github.com/storacha/go-ucanto/core/message" "github.com/storacha/go-ucanto/core/receipt" "github.com/storacha/go-ucanto/core/result" "github.com/storacha/go-ucanto/core/result/failure" @@ -29,6 +32,7 @@ import ( "github.com/storacha/go-ucanto/did" "github.com/storacha/go-ucanto/principal" "github.com/storacha/go-ucanto/principal/ed25519/signer" + ucanhttp "github.com/storacha/go-ucanto/transport/http" "github.com/storacha/go-ucanto/ucan" "github.com/storacha/go-w3up/capability/storeadd" "github.com/storacha/go-w3up/capability/uploadadd" @@ -184,7 +188,7 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat // // The `space` is the resource the invocation applies to. It is typically the // DID of a space. -func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options ...Option) (ipld.Link, delegation.Delegation, error) { +func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (ipld.Link, delegation.Delegation, error) { cfg := ClientConfig{conn: DefaultConnection} for _, opt := range options { if err := opt(&cfg); err != nil { @@ -244,6 +248,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options } var allocateTask, putTask, acceptTask invocation.Invocation + legacyAccept := false var concludeFxs []invocation.Invocation for _, task := range rcpt.Fx().Fork() { inv, ok := task.Invocation() @@ -264,6 +269,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options case w3sBlob.AcceptAbility: if acceptTask == nil { acceptTask = inv + legacyAccept = true } } } @@ -276,8 +282,8 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options var allocateRcpt receipt.Receipt[blob.AllocateOk, fdm.FailureModel] var legacyAllocateRcpt receipt.Receipt[w3sBlob.AllocateOk, fdm.FailureModel] var putRcpt receipt.AnyReceipt - var acceptRcpt receipt.Receipt[*blob.AcceptOk, fdm.FailureModel] - var legacyAcceptRcpt receipt.Receipt[*w3sBlob.AcceptOk, fdm.FailureModel] + var acceptRcpt receipt.Receipt[blob.AcceptOk, fdm.FailureModel] + var legacyAcceptRcpt receipt.Receipt[w3sBlob.AcceptOk, fdm.FailureModel] for _, concludeFx := range concludeFxs { concludeRcpt, err := getConcludeReceipt(concludeFx) if err != nil { @@ -303,12 +309,12 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options case acceptTask.Link(): switch allocateTask.Capabilities()[0].Can() { case blob.AcceptAbility: - acceptRcpt, err = receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + acceptRcpt, err = receipt.Rebind[blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) } case w3sBlob.AcceptAbility: - legacyAcceptRcpt, err = receipt.Rebind[*w3sBlob.AcceptOk, fdm.FailureModel](concludeRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + legacyAcceptRcpt, err = receipt.Rebind[w3sBlob.AcceptOk, fdm.FailureModel](concludeRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) } @@ -356,38 +362,85 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, options // invoke `ucan/conclude` with `http/put` receipt if putRcpt == nil { - sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn) + if err := sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn); err != nil { + return nil, nil, fmt.Errorf("sending put receipt: %w", err) + } } else { putOk, _ := result.Unwrap(putRcpt.Out()) if putOk == nil { - sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn) + if err := sendPutReceipt(putTask, issuer, cfg.conn.ID(), cfg.conn); err != nil { + return nil, nil, fmt.Errorf("sending put receipt: %w", err) + } } } // ensure the blob has been accepted + var anyAcceptRcpt receipt.AnyReceipt + var site ucan.Link + var rcptBlocks iter.Seq2[ipld.Block, error] if acceptRcpt == nil && legacyAcceptRcpt == nil { - pollAccept(acceptTask.Link(), cfg.conn) - } else { - var ok any - if acceptRcpt != nil { - ok, _ = result.Unwrap(acceptRcpt.Out()) + anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + if err != nil { + return nil, nil, fmt.Errorf("polling accept: %w", err) + } + } else if acceptRcpt != nil { + if acceptRcpt.Out().Ok() == nil { + anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + if err != nil { + return nil, nil, fmt.Errorf("polling accept: %w", err) + } } else { - ok, _ = result.Unwrap(legacyAcceptRcpt.Out()) + site = acceptRcpt.Out().Ok().Site + rcptBlocks = acceptRcpt.Blocks() } - - if ok == nil { - pollAccept(acceptTask.Link(), cfg.conn) + } else if legacyAcceptRcpt != nil { + if legacyAcceptRcpt.Out().Ok() == nil { + anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + if err != nil { + return nil, nil, fmt.Errorf("polling accept: %w", err) + } + } else { + site = legacyAcceptRcpt.Out().Ok().Site + rcptBlocks = legacyAcceptRcpt.Blocks() } } - acceptOk, _ := result.Unwrap(acceptRcpt.Out()) + if site == nil { + if !legacyAccept { + acceptRcpt, err = receipt.Rebind[blob.AcceptOk, fdm.FailureModel](anyAcceptRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("fetching accept receipt: %w", err) + } - locationBlocks, err := blockstore.NewBlockStore(blockstore.WithBlocksIterator(acceptRcpt.Blocks())) + acceptOk, err := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("blob/accept failed: %w", err) + } + + site = acceptOk.Site + rcptBlocks = acceptRcpt.Blocks() + } else { + legacyAcceptRcpt, err = receipt.Rebind[w3sBlob.AcceptOk, fdm.FailureModel](anyAcceptRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + if err != nil { + return nil, nil, fmt.Errorf("fetching legacy accept receipt: %w", err) + } + + acceptOk, err := result.Unwrap(result.MapError(legacyAcceptRcpt.Out(), failure.FromFailureModel)) + if err != nil { + return nil, nil, fmt.Errorf("web3.storage/blob/accept failed: %w", err) + } + + site = acceptOk.Site + rcptBlocks = legacyAcceptRcpt.Blocks() + } + } + + locationBlocks, err := blockstore.NewBlockStore(blockstore.WithBlocksIterator(rcptBlocks)) if err != nil { return nil, nil, fmt.Errorf("reading location commitment blocks: %w", err) } - location, err := delegation.NewDelegationView(acceptOk.Site, locationBlocks) + location, err := delegation.NewDelegationView(site, locationBlocks) if err != nil { return nil, nil, fmt.Errorf("creating location delegation: %w", err) } @@ -569,11 +622,54 @@ func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience return nil } -func pollAccept(link ucan.Link, conn client.Connection) (receipt.Receipt[*blob.AcceptOk, fdm.FailureModel], error) { - rcpt, err := receipt.Issue(ucan.Signer(signer.Ed25519Signer{}), result.Ok[*blob.AcceptOk, ipld.Builder](&blob.AcceptOk{}), ran.FromLink(link)) +func pollAccept(link ucan.Link, conn client.Connection, receiptsURL *url.URL) (receipt.AnyReceipt, error) { + receiptURL := receiptsURL.JoinPath(link.String()) + req, err := http.NewRequest(http.MethodGet, receiptURL.String(), nil) if err != nil { - return nil, fmt.Errorf("generating receipt: %w", err) + return nil, fmt.Errorf("creating get request: %w", err) + } + + // TODO: custom HTTP client with timeout + client := &http.Client{} + + var msg message.AgentMessage + for retry := 0; retry < 5 && msg == nil; retry++ { + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("polling receipts endpoint: %w", err) + } + defer resp.Body.Close() + + respBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("reading response body: %w", err) + } + + switch resp.StatusCode { + case http.StatusOK: + msg, err = conn.Codec().Decode(ucanhttp.NewHTTPResponse(resp.StatusCode, bytes.NewReader(respBytes), resp.Header)) + if err != nil { + return nil, fmt.Errorf("decoding message: %w", err) + } + + case http.StatusNotFound: + time.Sleep(1 * time.Second) + + default: + return nil, fmt.Errorf("polling receipts endpoint: %s", resp.Status) + } + } + + if msg == nil { + return nil, fmt.Errorf("accept receipt not found: %s", link) + } + + rcptlnk, ok := msg.Get(link) + if !ok { + return nil, fmt.Errorf("accept receipt not found: %s", link) } - return receipt.Rebind[*blob.AcceptOk, fdm.FailureModel](rcpt, blob.AcceptOkType(), fdm.FailureType()) + reader := receipt.NewAnyReceiptReader(captypes.Converters...) + + return reader.Read(rcptlnk, msg.Blocks()) } diff --git a/cmd/upload.go b/cmd/upload.go index a0f09ab8..46e0cfe9 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "log" + "net/url" "os" uclient "github.com/storacha/go-ucanto/client" @@ -26,6 +27,7 @@ func upload(cCtx *cli.Context) error { conn := util.MustGetConnection() space := util.MustParseDID(cCtx.String("space")) proofs := []delegation.Delegation{util.MustGetProof(cCtx.String("proof"))} + receiptsURL := util.MustGetReceiptsURL() // Handle options isCAR := cCtx.String("car") != "" @@ -45,20 +47,20 @@ func upload(cCtx *cli.Context) error { var root ipld.Link if isCAR { var err error - root, err = uploadCAR(paths[0], signer, conn, space, proofs) + root, err = uploadCAR(paths[0], signer, conn, space, proofs, receiptsURL) if err != nil { return err } } else { if len(paths) == 1 && !isWrap { var err error - root, err = uploadFile(paths[0], signer, conn, space, proofs) + root, err = uploadFile(paths[0], signer, conn, space, proofs, receiptsURL) if err != nil { return err } } else { var err error - root, err = uploadDirectory(paths, signer, conn, space, proofs) + root, err = uploadDirectory(paths, signer, conn, space, proofs, receiptsURL) if err != nil { return err } @@ -74,7 +76,7 @@ func upload(cCtx *cli.Context) error { return nil } -func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { +func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { f0, err := os.Open(path) if err != nil { return nil, fmt.Errorf("opening file: %s", err) @@ -89,7 +91,7 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp } if stat.Size() < sharding.ShardSize { - link, err := addBlob(f0, signer, conn, space, proofs) + link, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, err } @@ -110,7 +112,7 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp log.Fatal(err) } - link, err := addBlob(shd, signer, conn, space, proofs) + link, err := addBlob(shd, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, err } @@ -158,16 +160,16 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return roots[0], nil } -func uploadFile(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { +func uploadFile(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { return nil, nil } -func uploadDirectory(paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { +func uploadDirectory(paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { return nil, nil } -func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation) (ipld.Link, error) { - contentLink, _, err := client.BlobAdd(content, signer, space, client.WithConnection(conn), client.WithProofs(proofs)) +func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { + contentLink, _, err := client.BlobAdd(content, signer, space, receiptsURL, client.WithConnection(conn), client.WithProofs(proofs)) if err != nil { return nil, err } From 6f674c84ff5c6c6b5d7f1562827db4a445431aa2 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Fri, 18 Apr 2025 13:50:19 +0200 Subject: [PATCH 09/28] use go-libstoracha upload/add capability --- cmd/upload.go | 59 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/cmd/upload.go b/cmd/upload.go index 46e0cfe9..62b7c4ed 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -7,14 +7,16 @@ import ( "net/url" "os" + captypes "github.com/storacha/go-libstoracha/capabilities/types" + uploadcap "github.com/storacha/go-libstoracha/capabilities/upload" uclient "github.com/storacha/go-ucanto/client" "github.com/storacha/go-ucanto/core/car" "github.com/storacha/go-ucanto/core/delegation" + "github.com/storacha/go-ucanto/core/invocation" "github.com/storacha/go-ucanto/core/ipld" - "github.com/storacha/go-ucanto/core/result" + "github.com/storacha/go-ucanto/core/receipt" "github.com/storacha/go-ucanto/did" "github.com/storacha/go-ucanto/principal" - "github.com/storacha/go-w3up/capability/uploadadd" "github.com/storacha/go-w3up/car/sharding" "github.com/storacha/go-w3up/client" "github.com/storacha/go-w3up/cmd/util" @@ -138,23 +140,50 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return nil, fmt.Errorf("missing root CID") } - rcpt, err := client.UploadAdd( - signer, - space, - uploadadd.Caveat{ - Root: roots[0], - Shards: shdlnks, - }, - client.WithConnection(conn), - client.WithProofs(proofs), - ) + // rcpt, err := client.UploadAdd( + // signer, + // space, + // uploadadd.Caveat{ + // Root: roots[0], + // Shards: shdlnks, + // }, + // client.WithConnection(conn), + // client.WithProofs(proofs), + // ) + caveats := uploadcap.AddCaveats{ + Root: roots[0], + Shards: shdlnks, + } + + asProofs := []delegation.Proof{} + for _, dlg := range proofs { + asProofs = append(asProofs, delegation.FromDelegation(dlg)) + } + + inv, err := uploadcap.Add.Invoke(signer, conn.ID(), space.String(), caveats, delegation.WithProof(asProofs...)) + if err != nil { + return nil, err + } + + resp, err := uclient.Execute([]invocation.Invocation{inv}, conn) + if err != nil { + return nil, err + } + + rcptlnk, ok := resp.Get(inv.Link()) + if !ok { + return nil, fmt.Errorf("receipt not found: %s", inv.Link()) + } + + reader := receipt.NewAnyReceiptReader(captypes.Converters...) + + rcpt, err := reader.Read(rcptlnk, resp.Blocks()) if err != nil { return nil, err } - _, upFailure := result.Unwrap(rcpt.Out()) - if upFailure != nil { - return nil, fmt.Errorf("%+v\n", upFailure) + if rcpt.Out().Err() != nil { + return nil, fmt.Errorf("%+v", rcpt.Out().Err()) } return roots[0], nil From da673887f491fe4310a1cd9eb5b2dd7906beab2f Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Fri, 18 Apr 2025 14:40:38 +0200 Subject: [PATCH 10/28] minimal UI feedback --- cmd/upload.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/upload.go b/cmd/upload.go index 62b7c4ed..c0cb4af8 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -48,6 +48,7 @@ func upload(cCtx *cli.Context) error { var root ipld.Link if isCAR { + fmt.Printf("Uploading %s...\n", paths[0]) var err error root, err = uploadCAR(paths[0], signer, conn, space, proofs, receiptsURL) if err != nil { @@ -186,6 +187,8 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return nil, fmt.Errorf("%+v", rcpt.Out().Err()) } + fmt.Printf("Uploaded %d bytes\n", stat.Size()) + return roots[0], nil } From 733df42eba8a94b6f0509b83387e531619ebfbb4 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Fri, 25 Apr 2025 13:48:55 +0200 Subject: [PATCH 11/28] first iteration of the test passing --- client/client.go | 12 +- client/client_test.go | 430 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 440 insertions(+), 2 deletions(-) create mode 100644 client/client_test.go diff --git a/client/client.go b/client/client.go index c9248947..ea6708d4 100644 --- a/client/client.go +++ b/client/client.go @@ -244,7 +244,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts //_, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) _, fail := result.Unwrap(rcpt.Out()) if fail != nil { - return nil, nil, fmt.Errorf("blob add failed: %w", fail) + return nil, nil, fmt.Errorf("blob add failed: %v", fail) } var allocateTask, putTask, acceptTask invocation.Invocation @@ -491,9 +491,17 @@ func putBlob(url url.URL, headers http.Header, body []byte) error { } func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience ucan.Principal, conn client.Connection) error { + if len(putTask.Facts()) != 1 { + return fmt.Errorf("invalid put facts, wanted 1 fact but got %d", len(putTask.Facts())) + } + + if _, ok := putTask.Facts()[0]["keys"]; !ok { + return fmt.Errorf("invalid put facts, missing 'keys' field") + } + putKeysNode, ok := putTask.Facts()[0]["keys"].(ipld.Node) if !ok { - return fmt.Errorf("invalid put facts") + return fmt.Errorf("invalid put facts, 'keys' field is not a node") } // TODO: define a schema and use bindnode.Rebind rather than doing this manually diff --git a/client/client_test.go b/client/client_test.go new file mode 100644 index 00000000..01f3b0e2 --- /dev/null +++ b/client/client_test.go @@ -0,0 +1,430 @@ +package client_test + +import ( + "bytes" + "crypto/rand" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime/datamodel" + "github.com/ipld/go-ipld-prime/fluent/qp" + "github.com/ipld/go-ipld-prime/node/basicnode" + "github.com/multiformats/go-multihash" + "github.com/storacha/go-libstoracha/capabilities/assert" + blobcap "github.com/storacha/go-libstoracha/capabilities/blob" + httpcap "github.com/storacha/go-libstoracha/capabilities/http" + spaceblobcap "github.com/storacha/go-libstoracha/capabilities/space/blob" + "github.com/storacha/go-libstoracha/capabilities/types" + ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" + uploadcap "github.com/storacha/go-libstoracha/capabilities/upload" + uclient "github.com/storacha/go-ucanto/client" + "github.com/storacha/go-ucanto/core/delegation" + "github.com/storacha/go-ucanto/core/invocation" + "github.com/storacha/go-ucanto/core/invocation/ran" + "github.com/storacha/go-ucanto/core/message" + "github.com/storacha/go-ucanto/core/receipt" + "github.com/storacha/go-ucanto/core/receipt/fx" + "github.com/storacha/go-ucanto/core/result" + "github.com/storacha/go-ucanto/core/result/failure" + "github.com/storacha/go-ucanto/did" + "github.com/storacha/go-ucanto/principal" + ed25519signer "github.com/storacha/go-ucanto/principal/ed25519/signer" + "github.com/storacha/go-ucanto/principal/signer" + "github.com/storacha/go-ucanto/server" + "github.com/storacha/go-ucanto/transport/car" + carresp "github.com/storacha/go-ucanto/transport/car/response" + uhttp "github.com/storacha/go-ucanto/transport/http" + "github.com/storacha/go-ucanto/ucan" + "github.com/stretchr/testify/require" + + "github.com/storacha/go-w3up/client" +) + +var acceptInvocation invocation.Invocation + +func TestBlobAdd(t *testing.T) { + issuer, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + space, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + serviceKey, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + servicePrincipal, err := did.Parse("did:web:storacha.test") + if err != nil { + t.Fatal(err) + } + + serviceSigner, err := signer.Wrap(serviceKey, servicePrincipal) + if err != nil { + t.Fatal(err) + } + + mux := http.NewServeMux() + httpSrv := httptest.NewServer(mux) + defer httpSrv.Close() + + ucanURL, err := url.Parse(httpSrv.URL + "/ucan") + if err != nil { + t.Fatal(err) + } + putBlobURL, err := url.Parse(httpSrv.URL + "/blob") + if err != nil { + t.Fatal(err) + } + receiptsURL, err := url.Parse(httpSrv.URL + "/receipt") + if err != nil { + t.Fatal(err) + } + + ucanSrv := setupTestUCANServer(t, serviceSigner, putBlobURL) + + setupHTTPHandlers(t, mux, ucanSrv, ucanURL, putBlobURL, receiptsURL) + + channel := uhttp.NewHTTPChannel(ucanURL) + codec := car.NewCAROutboundCodec() + + conn, err := uclient.NewConnection(servicePrincipal, channel, uclient.WithOutboundCodec(codec)) + if err != nil { + t.Fatal(err) + } + + // delegate * to the space + cap := ucan.NewCapability("*", space.DID().String(), ucan.NoCaveats{}) + proof, err := delegation.Delegate(space, issuer, []ucan.Capability[ucan.NoCaveats]{cap}, delegation.WithNoExpiration()) + if err != nil { + t.Fatal(err) + } + + testBlob := bytes.NewReader([]byte("test")) + + _, _, err = client.BlobAdd(testBlob, issuer, space.DID(), receiptsURL, client.WithConnection(conn), client.WithProof(proof)) + require.NoError(t, err) +} + +type httpPutFact struct { + id string + key []byte +} + +func (hpf httpPutFact) ToIPLD() (map[string]datamodel.Node, error) { + n, err := qp.BuildMap(basicnode.Prototype.Any, 2, func(ma datamodel.MapAssembler) { + qp.MapEntry(ma, "id", qp.String(hpf.id)) + qp.MapEntry(ma, "keys", qp.Map(2, func(ma datamodel.MapAssembler) { + qp.MapEntry(ma, hpf.id, qp.Bytes(hpf.key)) + })) + }) + if err != nil { + return nil, err + } + + return map[string]datamodel.Node{ + "keys": n, + }, nil +} + +func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlobURL *url.URL) server.ServerView { + // space/blob/add handler + mockSPKey, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + mockSPDID, err := did.Parse("did:web:sp.test") + if err != nil { + t.Fatal(err) + } + + mockSPPrincipal, err := signer.Wrap(mockSPKey, mockSPDID) + if err != nil { + t.Fatal(err) + } + + spaceBlobAddMethod := server.Provide( + spaceblobcap.Add, + func(cap ucan.Capability[spaceblobcap.AddCaveats], inv invocation.Invocation, ctx server.InvocationContext) (spaceblobcap.AddOk, fx.Effects, error) { + // add task for blob/allocate + blobDigest := cap.Nb().Blob.Digest + blobSize := cap.Nb().Blob.Size + + spaceDID, err := did.Parse(cap.With()) + if err != nil { + t.Fatal(err) + } + allocateCaveats := blobcap.AllocateCaveats{ + Space: spaceDID, + Blob: blobcap.Blob{ + Digest: blobDigest, + Size: blobSize, + }, + Cause: inv.Link(), + } + allocateInv, err := blobcap.Allocate.Invoke(serverPrincipal, mockSPPrincipal, cap.With(), allocateCaveats) + if err != nil { + t.Fatal(err) + } + allocateInv.Attach(inv.Root()) + + // add task for ucan/conclude (with the receipt of blob/allocate) + allocateResult := result.Ok[blobcap.AllocateOk, failure.IPLDBuilderFailure](blobcap.AllocateOk{ + Size: blobSize, + Address: &blobcap.Address{ + URL: *putBlobURL, + Headers: http.Header{"some-header": []string{"some-value"}}, + Expires: uint64(time.Now().Add(1 * time.Minute).Unix()), + }, + }) + allocateRcpt, err := receipt.Issue(mockSPPrincipal, allocateResult, ran.FromInvocation(allocateInv)) + if err != nil { + t.Fatal(err) + } + concludeCaveats := ucancap.ConcludeCaveats{ + Receipt: allocateRcpt.Root().Link(), + } + concludeInv, err := ucancap.Conclude.Invoke(serverPrincipal, mockSPPrincipal, cap.With(), concludeCaveats) + if err != nil { + t.Fatal(err) + } + concludeInv.Attach(allocateRcpt.Root()) + + // add task for http/put + httpPutCaveats := httpcap.PutCaveats{ + URL: types.Promise{ + UcanAwait: types.Await{ + Selector: ".out.ok.address.url", + Link: allocateRcpt.Root().Link()}, + }, + Headers: types.Promise{ + UcanAwait: types.Await{ + Selector: ".out.ok.address.headers", + Link: allocateRcpt.Root().Link()}, + }, + Body: httpcap.Body{ + Digest: blobDigest, + Size: blobSize, + }, + } + + // random signer rather than the proper derived one + //blobProvider, err := ed25519signer.FromSeed([]byte(blobDigest)[len(blobDigest)-32:]) + blobProvider, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + fct := httpPutFact{ + id: blobProvider.DID().String(), + key: blobProvider.Encode(), + } + + facts := []ucan.FactBuilder{fct} + httpPutInv, err := httpcap.Put.Invoke(blobProvider, blobProvider, blobProvider.DID().String(), httpPutCaveats, delegation.WithFacts(facts)) + if err != nil { + t.Fatal(err) + } + httpPutInv.Attach(allocateRcpt.Root()) + + // add task for blob/accept + acceptCaveats := blobcap.AcceptCaveats{ + Space: spaceDID, + Blob: blobcap.Blob{ + Digest: blobDigest, + Size: blobSize, + }, + Put: blobcap.Promise{ + UcanAwait: blobcap.Await{ + Selector: ".out.ok", + Link: httpPutInv.Root().Link(), + }, + }, + } + acceptInv, err := blobcap.Accept.Invoke(serverPrincipal, mockSPPrincipal, mockSPPrincipal.DID().String(), acceptCaveats) + if err != nil { + t.Fatal(err) + } + acceptInv.Attach(httpPutInv.Root()) + + acceptInvocation = acceptInv + + forks := []fx.Effect{ + fx.FromInvocation(allocateInv), + fx.FromInvocation(concludeInv), + fx.FromInvocation(httpPutInv), + fx.FromInvocation(acceptInv), + } + fxs := fx.NewEffects(fx.WithFork(forks...)) + + ok := spaceblobcap.AddOk{ + Site: spaceblobcap.Promise{ + UcanAwait: spaceblobcap.Await{ + Selector: ".out.ok.site", + Link: acceptInv.Root().Link(), + }, + }, + } + + return ok, fxs, nil + }, + ) + + // ucan/conclude handler + ucanConcludeMethod := server.Provide( + ucancap.Conclude, + func(capability ucan.Capability[ucancap.ConcludeCaveats], invocation invocation.Invocation, context server.InvocationContext) (ucancap.ConcludeOk, fx.Effects, error) { + return ucancap.ConcludeOk{}, nil, nil + }, + ) + + // upload/add handler + uploadAddMethod := server.Provide( + uploadcap.Add, + func(capability ucan.Capability[uploadcap.AddCaveats], invocation invocation.Invocation, context server.InvocationContext) (uploadcap.AddOk, fx.Effects, error) { + return uploadcap.AddOk{}, nil, nil + }, + ) + + srv, err := server.NewServer( + serverPrincipal, + server.WithInboundCodec(car.NewCARInboundCodec()), + server.WithServiceMethod(spaceblobcap.AddAbility, spaceBlobAddMethod), + server.WithServiceMethod(ucancap.ConcludeAbility, ucanConcludeMethod), + server.WithServiceMethod(uploadcap.AddAbility, uploadAddMethod), + ) + if err != nil { + t.Fatal(err) + } + + return srv +} + +func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerView, ucanURL, putBlobURL, receiptsURL *url.URL) { + // ucan handler + ucanPath := fmt.Sprintf("POST %s", ucanURL.Path) + mux.HandleFunc(ucanPath, func(w http.ResponseWriter, r *http.Request) { + res, _ := ucanSrv.Request(uhttp.NewHTTPRequest(r.Body, r.Header)) + + for key, vals := range res.Headers() { + for _, v := range vals { + w.Header().Add(key, v) + } + } + + if res.Status() != 0 { + w.WriteHeader(res.Status()) + } + + _, err := io.Copy(w, res.Body()) + if err != nil { + t.Fatal(err) + } + }) + + // put blob handler + putBlobPath := fmt.Sprintf("PUT %s", putBlobURL.Path) + mux.HandleFunc(putBlobPath, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + // receipts handler + receiptsPath := fmt.Sprintf("GET %s/{cid}", receiptsURL.Path) + mux.HandleFunc(receiptsPath, func(w http.ResponseWriter, r *http.Request) { + cidStr := r.PathValue("cid") + if cidStr == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + + _, err := cid.Parse(cidStr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + issuer, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + space, err := ed25519signer.Generate() + if err != nil { + t.Fatal(err) + } + + // not a valid location claim, but enough for testing + locationClaim, err := assert.Location.Delegate( + issuer, + space.DID(), + space.DID().String(), + assert.LocationCaveats{ + Space: space.DID(), + Content: types.FromHash(randomMultihash(t)), + Location: []url.URL{*putBlobURL}, + }, + delegation.WithNoExpiration(), + ) + if err != nil { + t.Fatal(err) + } + + ok := result.Ok[blobcap.AcceptOk, failure.IPLDBuilderFailure](blobcap.AcceptOk{ + Site: locationClaim.Link(), + }) + + forks := []fx.Effect{fx.FromInvocation(locationClaim)} + + acceptRcpt, err := receipt.Issue(issuer, ok, ran.FromInvocation(acceptInvocation), receipt.WithFork(forks...)) + if err != nil { + t.Fatal(err) + } + + msg, err := message.Build(nil, []receipt.AnyReceipt{acceptRcpt}) + if err != nil { + t.Fatal(err) + } + + resp, err := carresp.Encode(msg) + if err != nil { + t.Fatal(err) + } + + for hdrK, hdrV := range resp.Headers() { + w.Header().Add(hdrK, hdrV[0]) + } + + _, err = io.Copy(w, resp.Body()) + if err != nil { + t.Fatal(err) + } + + w.WriteHeader(resp.Status()) + }) +} + +func randomMultihash(t *testing.T) multihash.Multihash { + bytes := make([]byte, 10) + _, err := rand.Read(bytes) + if err != nil { + t.Fatal(err) + } + + digest, err := multihash.Sum(bytes, multihash.SHA2_256, -1) + if err != nil { + t.Fatal(err) + } + + return digest +} From 9da0fbfe1fa56ce5b4cc748942d9560c8febbbaa Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Fri, 25 Apr 2025 14:29:19 +0200 Subject: [PATCH 12/28] refactor test server code --- client/client_test.go | 112 ++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index 01f3b0e2..a94b6038 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -46,8 +46,6 @@ import ( "github.com/storacha/go-w3up/client" ) -var acceptInvocation invocation.Invocation - func TestBlobAdd(t *testing.T) { issuer, err := ed25519signer.Generate() if err != nil { @@ -74,26 +72,8 @@ func TestBlobAdd(t *testing.T) { t.Fatal(err) } - mux := http.NewServeMux() - httpSrv := httptest.NewServer(mux) - defer httpSrv.Close() - - ucanURL, err := url.Parse(httpSrv.URL + "/ucan") - if err != nil { - t.Fatal(err) - } - putBlobURL, err := url.Parse(httpSrv.URL + "/blob") - if err != nil { - t.Fatal(err) - } - receiptsURL, err := url.Parse(httpSrv.URL + "/receipt") - if err != nil { - t.Fatal(err) - } - - ucanSrv := setupTestUCANServer(t, serviceSigner, putBlobURL) - - setupHTTPHandlers(t, mux, ucanSrv, ucanURL, putBlobURL, receiptsURL) + testSrv, ucanURL, receiptsURL := newTestServer(t, serviceSigner) + defer testSrv.Close() channel := uhttp.NewHTTPChannel(ucanURL) codec := car.NewCAROutboundCodec() @@ -116,6 +96,53 @@ func TestBlobAdd(t *testing.T) { require.NoError(t, err) } +type testServer struct { + httpSrv *httptest.Server + ucanSrv server.ServerView + acceptedBlobs map[string]acceptedBlobData +} + +type acceptedBlobData struct { + AcceptTask invocation.Invocation + StorageProvider principal.Signer + Digest multihash.Multihash + Space did.DID + Location *url.URL +} + +func newTestServer(t *testing.T, serviceSigner principal.Signer) (*testServer, *url.URL, *url.URL) { + acceptedBlobs := make(map[string]acceptedBlobData) + mux := http.NewServeMux() + httpSrv := httptest.NewServer(mux) + + ucanURL, err := url.Parse(httpSrv.URL + "/ucan") + if err != nil { + t.Fatal(err) + } + putBlobURL, err := url.Parse(httpSrv.URL + "/blob") + if err != nil { + t.Fatal(err) + } + receiptsURL, err := url.Parse(httpSrv.URL + "/receipt") + if err != nil { + t.Fatal(err) + } + + ucanSrv := setupTestUCANServer(t, serviceSigner, putBlobURL, acceptedBlobs) + + setupHTTPHandlers(t, mux, ucanSrv, ucanURL, putBlobURL, receiptsURL, acceptedBlobs) + + return &testServer{ + httpSrv: httpSrv, + ucanSrv: ucanSrv, + acceptedBlobs: acceptedBlobs, + }, ucanURL, receiptsURL +} + +func (ts *testServer) Close() { + ts.httpSrv.Close() +} + type httpPutFact struct { id string key []byte @@ -137,7 +164,7 @@ func (hpf httpPutFact) ToIPLD() (map[string]datamodel.Node, error) { }, nil } -func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlobURL *url.URL) server.ServerView { +func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlobURL *url.URL, acceptedBlobs map[string]acceptedBlobData) server.ServerView { // space/blob/add handler mockSPKey, err := ed25519signer.Generate() if err != nil { @@ -258,7 +285,13 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob } acceptInv.Attach(httpPutInv.Root()) - acceptInvocation = acceptInv + acceptedBlobs[acceptInv.Link().String()] = acceptedBlobData{ + AcceptTask: acceptInv, + StorageProvider: mockSPPrincipal, + Digest: blobDigest, + Space: spaceDID, + Location: &allocateResult.Ok().Address.URL, + } forks := []fx.Effect{ fx.FromInvocation(allocateInv), @@ -311,7 +344,7 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob return srv } -func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerView, ucanURL, putBlobURL, receiptsURL *url.URL) { +func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerView, ucanURL, putBlobURL, receiptsURL *url.URL, acceptedBlobs map[string]acceptedBlobData) { // ucan handler ucanPath := fmt.Sprintf("POST %s", ucanURL.Path) mux.HandleFunc(ucanPath, func(w http.ResponseWriter, r *http.Request) { @@ -354,25 +387,20 @@ func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerVi return } - issuer, err := ed25519signer.Generate() - if err != nil { - t.Fatal(err) - } - - space, err := ed25519signer.Generate() - if err != nil { - t.Fatal(err) + acceptedBlobData, ok := acceptedBlobs[cidStr] + if !ok { + w.WriteHeader(http.StatusNotFound) + return } - // not a valid location claim, but enough for testing locationClaim, err := assert.Location.Delegate( - issuer, - space.DID(), - space.DID().String(), + acceptedBlobData.StorageProvider, + acceptedBlobData.Space.DID(), + acceptedBlobData.Space.DID().String(), assert.LocationCaveats{ - Space: space.DID(), - Content: types.FromHash(randomMultihash(t)), - Location: []url.URL{*putBlobURL}, + Space: acceptedBlobData.Space.DID(), + Content: types.FromHash(acceptedBlobData.Digest), + Location: []url.URL{*acceptedBlobData.Location}, }, delegation.WithNoExpiration(), ) @@ -380,13 +408,13 @@ func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerVi t.Fatal(err) } - ok := result.Ok[blobcap.AcceptOk, failure.IPLDBuilderFailure](blobcap.AcceptOk{ + acceptOk := result.Ok[blobcap.AcceptOk, failure.IPLDBuilderFailure](blobcap.AcceptOk{ Site: locationClaim.Link(), }) forks := []fx.Effect{fx.FromInvocation(locationClaim)} - acceptRcpt, err := receipt.Issue(issuer, ok, ran.FromInvocation(acceptInvocation), receipt.WithFork(forks...)) + acceptRcpt, err := receipt.Issue(acceptedBlobData.StorageProvider, acceptOk, ran.FromInvocation(acceptedBlobData.AcceptTask), receipt.WithFork(forks...)) if err != nil { t.Fatal(err) } From 42eaf22a103e1184fcbf9d5188e6ffe1e69dbd84 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Mon, 28 Apr 2025 09:32:46 +0200 Subject: [PATCH 13/28] remove store/add, which is deprecated --- capability/storeadd/capability.go | 26 ----- capability/storeadd/receipt.go | 7 -- capability/storeadd/result.go | 37 ------- capability/storeadd/result.ipldsch | 41 -------- client/client.go | 48 --------- cmd/w3.go | 163 ----------------------------- 6 files changed, 322 deletions(-) delete mode 100644 capability/storeadd/capability.go delete mode 100644 capability/storeadd/receipt.go delete mode 100644 capability/storeadd/result.go delete mode 100644 capability/storeadd/result.ipldsch diff --git a/capability/storeadd/capability.go b/capability/storeadd/capability.go deleted file mode 100644 index 32ef61de..00000000 --- a/capability/storeadd/capability.go +++ /dev/null @@ -1,26 +0,0 @@ -package storeadd - -import ( - "github.com/ipld/go-ipld-prime/datamodel" - "github.com/storacha/go-ucanto/core/ipld" - "github.com/storacha/go-ucanto/did" - "github.com/storacha/go-ucanto/ucan" -) - -const Ability = "store/add" - -type Caveat struct { - Link ipld.Link - Size uint64 - Origin *ipld.Link -} - -var _ ucan.CaveatBuilder = (*Caveat)(nil) - -func (c Caveat) ToIPLD() (datamodel.Node, error) { - return ipld.WrapWithRecovery(&c, nil) -} - -func NewCapability(space did.DID, nb Caveat) ucan.Capability[Caveat] { - return ucan.NewCapability(Ability, space.String(), nb) -} diff --git a/capability/storeadd/receipt.go b/capability/storeadd/receipt.go deleted file mode 100644 index e108872b..00000000 --- a/capability/storeadd/receipt.go +++ /dev/null @@ -1,7 +0,0 @@ -package storeadd - -import "github.com/storacha/go-ucanto/core/receipt" - -func NewReceiptReader() (receipt.ReceiptReader[*Success, *Failure], error) { - return receipt.NewReceiptReader[*Success, *Failure](ResultSchema) -} diff --git a/capability/storeadd/result.go b/capability/storeadd/result.go deleted file mode 100644 index 9f2aaa5e..00000000 --- a/capability/storeadd/result.go +++ /dev/null @@ -1,37 +0,0 @@ -package storeadd - -import ( - _ "embed" - - "github.com/ipld/go-ipld-prime" -) - -//go:embed result.ipldsch -var ResultSchema []byte - -type Success struct { - // Status of the item to store. A "done" status indicates that it is not - // necessary to upload the item. An "upload" status indicates that the item - // should be uploaded to the provided URL. - Status string - // With is the DID of the space this item will be stored in. - With string - // Link is the CID of the item. - Link ipld.Link - Url *string - Headers *Headers - // Allocated is the total bytes allocated in the space to accommodate this - // stored item. May be zero if the item is _already_ stored in _this_ space. - Allocated uint64 -} - -type Headers struct { - Keys []string - Values map[string]string -} - -type Failure struct { - Name *string - Message string - Stack *string -} diff --git a/capability/storeadd/result.ipldsch b/capability/storeadd/result.ipldsch deleted file mode 100644 index eea59429..00000000 --- a/capability/storeadd/result.ipldsch +++ /dev/null @@ -1,41 +0,0 @@ -type Result union { - | Success "ok" - | Failure "error" -} representation keyed - -type Success struct { - status String - with DID - link Link - url optional URL - headers optional {String: String} - allocated Int -} - -# type Success union { -# | SuccessUpload "upload" -# | SuccessDone "done" -# } representation inline { -# discriminantKey "status" -# } - -# type SuccessUpload struct { -# with DID -# link Link -# url URL -# headers {String: String} -# } - -# type SuccessDone struct { -# with DID -# link Link -# } - -type DID string -type URL string - -type Failure struct { - name optional String - message String - stack optional String -} diff --git a/client/client.go b/client/client.go index ea6708d4..e291f017 100644 --- a/client/client.go +++ b/client/client.go @@ -34,58 +34,10 @@ import ( "github.com/storacha/go-ucanto/principal/ed25519/signer" ucanhttp "github.com/storacha/go-ucanto/transport/http" "github.com/storacha/go-ucanto/ucan" - "github.com/storacha/go-w3up/capability/storeadd" "github.com/storacha/go-w3up/capability/uploadadd" "github.com/storacha/go-w3up/capability/uploadlist" ) -// StoreAdd stores a DAG encoded as a CAR file. The issuer needs proof of -// `store/add` delegated capability. -// -// Required delegated capability proofs: `store/add` -// -// The `issuer` is the signing authority that is issuing the UCAN invocation. -// -// The `space` is the resource the invocation applies to. It is typically the -// DID of a space. -// -// The `params` are caveats required to perform a `store/add` invocation. -func StoreAdd(issuer principal.Signer, space did.DID, params storeadd.Caveat, options ...Option) (receipt.Receipt[*storeadd.Success, *storeadd.Failure], error) { - cfg := ClientConfig{conn: DefaultConnection} - for _, opt := range options { - if err := opt(&cfg); err != nil { - return nil, err - } - } - - inv, err := invocation.Invoke( - issuer, - cfg.conn.ID(), - storeadd.NewCapability(space, params), - convertToInvocationOptions(cfg)..., - ) - if err != nil { - return nil, err - } - - resp, err := client.Execute([]invocation.Invocation{inv}, cfg.conn) - if err != nil { - return nil, err - } - - rcptlnk, ok := resp.Get(inv.Link()) - if !ok { - return nil, fmt.Errorf("receipt not found: %s", inv.Link()) - } - - reader, err := storeadd.NewReceiptReader() - if err != nil { - return nil, err - } - - return reader.Read(rcptlnk, resp.Blocks()) -} - // UploadAdd registers an "upload" with the service. The issuer needs proof of // `upload/add` delegated capability. // diff --git a/cmd/w3.go b/cmd/w3.go index 10a879f6..a59e4f3a 100644 --- a/cmd/w3.go +++ b/cmd/w3.go @@ -1,26 +1,13 @@ package main import ( - "bytes" "fmt" - "io" "log" - "net/http" "os" - "github.com/ipfs/go-cid" - "github.com/ipld/go-ipld-prime" - cidlink "github.com/ipld/go-ipld-prime/linking/cid" - "github.com/multiformats/go-multihash" - "github.com/storacha/go-ucanto/core/car" "github.com/storacha/go-ucanto/core/delegation" "github.com/storacha/go-ucanto/core/result" - "github.com/storacha/go-ucanto/did" - "github.com/storacha/go-ucanto/principal" - "github.com/storacha/go-w3up/capability/storeadd" - "github.com/storacha/go-w3up/capability/uploadadd" "github.com/storacha/go-w3up/capability/uploadlist" - "github.com/storacha/go-w3up/car/sharding" "github.com/storacha/go-w3up/client" "github.com/storacha/go-w3up/cmd/util" "github.com/urfave/cli/v2" @@ -130,156 +117,6 @@ func whoami(cCtx *cli.Context) error { return nil } -func up(cCtx *cli.Context) error { - signer := util.MustGetSigner() - conn := util.MustGetConnection() - space := util.MustParseDID(cCtx.String("space")) - proofs := []delegation.Delegation{util.MustGetProof(cCtx.String("proof"))} - - f0, err := os.Open(cCtx.String("car")) - if err != nil { - log.Fatalf("opening file: %s", err) - } - - stat, err := f0.Stat() - if err != nil { - log.Fatalf("stat file: %s", err) - } - - var shdlnks []ipld.Link - - defer f0.Close() - if stat.Size() < sharding.ShardSize { - link := storeShard(signer, space, f0, proofs) - fmt.Println(link.String()) - shdlnks = append(shdlnks, link) - } else { - _, blocks, err := car.Decode(f0) - if err != nil { - log.Fatalf("decoding CAR: %s", err) - } - shds, err := sharding.NewSharder([]ipld.Link{}, blocks) - if err != nil { - log.Fatalf("sharding CAR: %s", err) - } - - for shd, err := range shds { - if err != nil { - if err == io.EOF { - break - } - log.Fatal(err) - } - link := storeShard(signer, space, shd, proofs) - fmt.Println(link.String()) - shdlnks = append(shdlnks, link) - } - } - - f3, err := os.Open(cCtx.String("car")) - if err != nil { - log.Fatalf("opening file: %s", err) - } - roots, _, err := car.Decode(f3) - if err != nil { - log.Fatalf("reading roots: %s", err) - } - err = f3.Close() - if err != nil { - log.Fatalf("closing file: %s", err) - } - if len(roots) > 0 { - rcpt, err := client.UploadAdd( - signer, - space, - uploadadd.Caveat{ - Root: roots[0], - Shards: shdlnks, - }, - client.WithConnection(conn), - client.WithProofs(proofs), - ) - if err != nil { - return err - } - - _, upFailure := result.Unwrap(rcpt.Out()) - if upFailure != nil { - log.Fatalf("%+v\n", upFailure) - } - - fmt.Printf("⁂ https://w3s.link/ipfs/%s\n", roots[0]) - } - - return nil -} - -func storeShard(issuer principal.Signer, space did.DID, shard io.Reader, proofs []delegation.Delegation) ipld.Link { - buf := new(bytes.Buffer) - _, err := buf.ReadFrom(shard) - if err != nil { - log.Fatalf("reading CAR: %s", err) - } - - mh, err := multihash.Sum(buf.Bytes(), multihash.SHA2_256, -1) - if err != nil { - log.Fatalf("hashing CAR: %s", err) - } - - link := cidlink.Link{Cid: cid.NewCidV1(0x0202, mh)} - - rcpt, err := client.StoreAdd( - issuer, - space, - storeadd.Caveat{ - Link: link, - Size: uint64(buf.Len()), - }, - client.WithConnection(util.MustGetConnection()), - client.WithProofs(proofs), - ) - if err != nil { - log.Fatalf("store/add %s: %s", link, err) - } - - storeSuccess, storeFailure := result.Unwrap(rcpt.Out()) - if storeFailure != nil { - log.Fatalf("%+v\n", storeFailure) - } - - if storeSuccess.Status == "upload" { - hr, err := http.NewRequest("PUT", *storeSuccess.Url, bytes.NewReader(buf.Bytes())) - if err != nil { - log.Fatalf("creating HTTP request: %s", err) - } - - hdr := map[string][]string{} - for k, v := range storeSuccess.Headers.Values { - if k == "content-length" { - continue - } - hdr[k] = []string{v} - } - - hr.Header = hdr - hr.ContentLength = int64(buf.Len()) - httpClient := http.Client{} - res, err := httpClient.Do(hr) - if err != nil { - log.Fatalf("doing HTTP request: %s", err) - } - if res.StatusCode != 200 { - log.Fatalf("non-200 status code while uploading file: %d", res.StatusCode) - } - err = res.Body.Close() - if err != nil { - log.Fatalf("closing request body: %s", err) - } - } - - return link -} - func ls(cCtx *cli.Context) error { signer := util.MustGetSigner() conn := util.MustGetConnection() From 046be5101020a169894b6ffc7f765b8baeeda112 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Tue, 29 Apr 2025 16:30:09 +0200 Subject: [PATCH 14/28] feedback: BlobAdd should not assume CARs --- client/client.go | 8 ++------ cmd/upload.go | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/client/client.go b/client/client.go index e291f017..0843bbcc 100644 --- a/client/client.go +++ b/client/client.go @@ -9,8 +9,6 @@ import ( "net/url" "time" - "github.com/ipfs/go-cid" - cidlink "github.com/ipld/go-ipld-prime/linking/cid" "github.com/multiformats/go-multihash" "github.com/storacha/go-libstoracha/capabilities/blob" httpcap "github.com/storacha/go-libstoracha/capabilities/http" @@ -140,7 +138,7 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat // // The `space` is the resource the invocation applies to. It is typically the // DID of a space. -func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (ipld.Link, delegation.Delegation, error) { +func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (multihash.Multihash, delegation.Delegation, error) { cfg := ClientConfig{conn: DefaultConnection} for _, opt := range options { if err := opt(&cfg); err != nil { @@ -158,8 +156,6 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts return nil, nil, fmt.Errorf("computing content multihash: %w", err) } - contentLink := cidlink.Link{Cid: cid.NewCidV1(0x0202, contentHash)} - caveats := spaceblob.AddCaveats{ Blob: spaceblob.Blob{ Digest: contentHash, @@ -397,7 +393,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts return nil, nil, fmt.Errorf("creating location delegation: %w", err) } - return contentLink, location, nil + return contentHash, location, nil } func getConcludeReceipt(concludeFx invocation.Invocation) (receipt.AnyReceipt, error) { diff --git a/cmd/upload.go b/cmd/upload.go index c0cb4af8..5acc0ec4 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -7,6 +7,10 @@ import ( "net/url" "os" + "github.com/ipfs/go-cid" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/multiformats/go-multicodec" + "github.com/multiformats/go-multihash" captypes "github.com/storacha/go-libstoracha/capabilities/types" uploadcap "github.com/storacha/go-libstoracha/capabilities/upload" uclient "github.com/storacha/go-ucanto/client" @@ -94,11 +98,13 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp } if stat.Size() < sharding.ShardSize { - link, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) + hash, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, err } + link := cidlink.Link{Cid: cid.NewCidV1(uint64(multicodec.Car), hash)} + shdlnks = append(shdlnks, link) } else { _, blocks, err := car.Decode(f0) @@ -115,11 +121,13 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp log.Fatal(err) } - link, err := addBlob(shd, signer, conn, space, proofs, receiptsURL) + hash, err := addBlob(shd, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, err } + link := cidlink.Link{Cid: cid.NewCidV1(uint64(multicodec.Car), hash)} + shdlnks = append(shdlnks, link) } } @@ -200,11 +208,11 @@ func uploadDirectory(paths []string, signer principal.Signer, conn uclient.Conne return nil, nil } -func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { - contentLink, _, err := client.BlobAdd(content, signer, space, receiptsURL, client.WithConnection(conn), client.WithProofs(proofs)) +func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (multihash.Multihash, error) { + contentHash, _, err := client.BlobAdd(content, signer, space, receiptsURL, client.WithConnection(conn), client.WithProofs(proofs)) if err != nil { return nil, err } - return contentLink, nil + return contentHash, nil } From fc7e520a9d7ab90278ca74f5b54ff61514981f35 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Tue, 29 Apr 2025 18:20:08 +0200 Subject: [PATCH 15/28] feedback: add comment about what BlobAdd returns --- client/client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/client.go b/client/client.go index 0843bbcc..1be15a89 100644 --- a/client/client.go +++ b/client/client.go @@ -138,6 +138,9 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat // // The `space` is the resource the invocation applies to. It is typically the // DID of a space. +// +// Returns the multihash of the added blob and the location commitment that contains details about where the +// blob can be located, or an error if something went wrong. func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (multihash.Multihash, delegation.Delegation, error) { cfg := ClientConfig{conn: DefaultConnection} for _, opt := range options { From a3cf50da5dcf597ad8df002cb5e5a6b9d2277570 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Tue, 29 Apr 2025 18:26:23 +0200 Subject: [PATCH 16/28] feedback: better param name in pollAccept --- client/client.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/client.go b/client/client.go index 1be15a89..e6b737d0 100644 --- a/client/client.go +++ b/client/client.go @@ -581,8 +581,8 @@ func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience return nil } -func pollAccept(link ucan.Link, conn client.Connection, receiptsURL *url.URL) (receipt.AnyReceipt, error) { - receiptURL := receiptsURL.JoinPath(link.String()) +func pollAccept(acceptTaskLink ucan.Link, conn client.Connection, receiptsURL *url.URL) (receipt.AnyReceipt, error) { + receiptURL := receiptsURL.JoinPath(acceptTaskLink.String()) req, err := http.NewRequest(http.MethodGet, receiptURL.String(), nil) if err != nil { return nil, fmt.Errorf("creating get request: %w", err) @@ -620,12 +620,12 @@ func pollAccept(link ucan.Link, conn client.Connection, receiptsURL *url.URL) (r } if msg == nil { - return nil, fmt.Errorf("accept receipt not found: %s", link) + return nil, fmt.Errorf("accept receipt not found: %s", acceptTaskLink) } - rcptlnk, ok := msg.Get(link) + rcptlnk, ok := msg.Get(acceptTaskLink) if !ok { - return nil, fmt.Errorf("accept receipt not found: %s", link) + return nil, fmt.Errorf("accept receipt not found: %s", acceptTaskLink) } reader := receipt.NewAnyReceiptReader(captypes.Converters...) From 009c23ae6047c73b0eb7fa4e5f63194b9a3127f5 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Tue, 29 Apr 2025 18:26:49 +0200 Subject: [PATCH 17/28] feedback: use STORACHA as prefix for env vars --- cmd/util/util.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/util/util.go b/cmd/util/util.go index ad6b2ef8..83ac5819 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -97,7 +97,7 @@ func mustReadConfig() *configurationModel { func MustGetConnection() client.Connection { // service URL & DID - serviceURLStr := os.Getenv("RACHA_SERVICE_URL") // use env var preferably + serviceURLStr := os.Getenv("STORACHA_SERVICE_URL") // use env var preferably if serviceURLStr == "" { serviceURLStr = fmt.Sprintf("https://%s", defaultServiceName) } @@ -107,7 +107,7 @@ func MustGetConnection() client.Connection { log.Fatal(err) } - serviceDIDStr := os.Getenv("RACHA_SERVICE_DID") + serviceDIDStr := os.Getenv("STORACHA_SERVICE_DID") if serviceDIDStr == "" { serviceDIDStr = fmt.Sprintf("did:web:%s", defaultServiceName) } @@ -130,7 +130,7 @@ func MustGetConnection() client.Connection { } func MustGetReceiptsURL() *url.URL { - receiptsURLStr := os.Getenv("RACHA_RECEIPTS_URL") + receiptsURLStr := os.Getenv("STORACHA_RECEIPTS_URL") if receiptsURLStr == "" { receiptsURLStr = fmt.Sprintf("https://%s/receipt", defaultServiceName) } From 1d7a458be9ae7700121249593c23f4f2959ad0e4 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 11:49:54 +0200 Subject: [PATCH 18/28] feedback: wrap errors and avoid log.Fatal where inappropriate --- car/sharding/sharding.go | 6 +++--- cmd/upload.go | 17 ++++++++--------- cmd/util/util.go | 2 +- cmd/w3.go | 2 +- delegation/proof.go | 10 +++++----- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/car/sharding/sharding.go b/car/sharding/sharding.go index 8809404f..e22575f7 100644 --- a/car/sharding/sharding.go +++ b/car/sharding/sharding.go @@ -36,7 +36,7 @@ func WithShardSize(size int) Option { func NewSharderFromCAR(reader io.Reader) (iter.Seq2[io.Reader, error], error) { roots, blocks, err := car.Decode(reader) if err != nil { - return nil, fmt.Errorf("decoding CAR: %s", err) + return nil, fmt.Errorf("decoding CAR: %w", err) } return NewSharder(roots, blocks) } @@ -51,7 +51,7 @@ func NewSharder(roots []ipld.Link, blocks iter.Seq2[ipld.Block, error], options hdrlen, err := headerEncodingLength(roots) if err != nil { - return nil, fmt.Errorf("encoding header: %s", err) + return nil, fmt.Errorf("encoding header: %w", err) } maxblklen := cfg.shdsize - hdrlen @@ -150,7 +150,7 @@ func NewSharder(roots []ipld.Link, blocks iter.Seq2[ipld.Block, error], options // hdrlen, err := headerEncodingLength(roots) // if err != nil { -// return nil, fmt.Errorf("encoding header: %s", err) +// return nil, fmt.Errorf("encoding header: %w", err) // } // // if adding CAR root overflows the shard limit we move overflowing diff --git a/cmd/upload.go b/cmd/upload.go index 5acc0ec4..b4caf3b3 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -3,7 +3,6 @@ package main import ( "fmt" "io" - "log" "net/url" "os" @@ -86,7 +85,7 @@ func upload(cCtx *cli.Context) error { func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { f0, err := os.Open(path) if err != nil { - return nil, fmt.Errorf("opening file: %s", err) + return nil, fmt.Errorf("opening file: %w", err) } defer f0.Close() @@ -94,7 +93,7 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp stat, err := f0.Stat() if err != nil { - return nil, fmt.Errorf("stat file: %s", err) + return nil, fmt.Errorf("stat file: %w", err) } if stat.Size() < sharding.ShardSize { @@ -109,21 +108,21 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp } else { _, blocks, err := car.Decode(f0) if err != nil { - log.Fatalf("decoding CAR: %s", err) + return nil, fmt.Errorf("decoding CAR: %w", err) } shds, err := sharding.NewSharder([]ipld.Link{}, blocks) if err != nil { - log.Fatalf("sharding CAR: %s", err) + return nil, fmt.Errorf("sharding CAR: %w", err) } for shd, err := range shds { if err != nil { - log.Fatal(err) + return nil, fmt.Errorf("ranging shards: %w", err) } hash, err := addBlob(shd, signer, conn, space, proofs, receiptsURL) if err != nil { - return nil, err + return nil, fmt.Errorf("uploading shard: %w", err) } link := cidlink.Link{Cid: cid.NewCidV1(uint64(multicodec.Car), hash)} @@ -136,13 +135,13 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp f1, err := os.Open(path) if err != nil { - return nil, fmt.Errorf("opening file: %s", err) + return nil, fmt.Errorf("opening file: %w", err) } defer f1.Close() roots, _, err := car.Decode(f1) if err != nil { - return nil, fmt.Errorf("reading roots: %s", err) + return nil, fmt.Errorf("reading roots: %w", err) } if len(roots) == 0 { diff --git a/cmd/util/util.go b/cmd/util/util.go index 83ac5819..23e04094 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -159,7 +159,7 @@ func MustGetProof(path string) delegation.Delegation { proof, err := cdg.ExtractProof(b) if err != nil { - log.Fatal(err) + log.Fatalf("extracting proof: %s", err) } return proof } diff --git a/cmd/w3.go b/cmd/w3.go index a59e4f3a..0082d964 100644 --- a/cmd/w3.go +++ b/cmd/w3.go @@ -136,7 +136,7 @@ func ls(cCtx *cli.Context) error { lsSuccess, lsFailure := result.Unwrap(rcpt.Out()) if lsFailure != nil { - log.Fatalf("%+v\n", lsFailure) + return fmt.Errorf("%+v", lsFailure) } for _, r := range lsSuccess.Results { diff --git a/delegation/proof.go b/delegation/proof.go index 80c4a5ca..d07f1488 100644 --- a/delegation/proof.go +++ b/delegation/proof.go @@ -23,13 +23,13 @@ func ExtractProof(b []byte) (delegation.Delegation, error) { // try decode legacy format _, blocks, err := car.Decode(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("extracting proof: %s", err) + return nil, fmt.Errorf("extracting proof: %w", err) } var rt block.Block bs, err := blockstore.NewBlockStore() if err != nil { - return nil, fmt.Errorf("creating blockstore: %s", err) + return nil, fmt.Errorf("creating blockstore: %w", err) } for bl, err := range blocks { @@ -38,11 +38,11 @@ func ExtractProof(b []byte) (delegation.Delegation, error) { break } - return nil, fmt.Errorf("reading block: %s", err) + return nil, fmt.Errorf("reading block: %w", err) } if err := bs.Put(bl); err != nil { - return nil, fmt.Errorf("putting block: %s", err) + return nil, fmt.Errorf("putting block: %w", err) } rt = bl @@ -50,7 +50,7 @@ func ExtractProof(b []byte) (delegation.Delegation, error) { proof, err = delegation.NewDelegation(rt, bs) if err != nil { - return nil, fmt.Errorf("creating delegation: %s", err) + return nil, fmt.Errorf("creating delegation: %w", err) } } From 4b3b616afbeecb5a669da8bf900dedcd2f76448f Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 12:04:00 +0200 Subject: [PATCH 19/28] feedback: check if path is a directory when uploading CARs --- cmd/upload.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/upload.go b/cmd/upload.go index b4caf3b3..1d8f8575 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -96,6 +96,10 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return nil, fmt.Errorf("stat file: %w", err) } + if stat.IsDir() { + return nil, fmt.Errorf("%s is a directory, expected a car file", path) + } + if stat.Size() < sharding.ShardSize { hash, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) if err != nil { From cef4ddd8ebf51507eaa7fe59c5d588ec633b46d0 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 12:10:22 +0200 Subject: [PATCH 20/28] feedback: fail fast if CAR decoding fails --- cmd/upload.go | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/cmd/upload.go b/cmd/upload.go index 1d8f8575..06b20087 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -100,6 +100,15 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return nil, fmt.Errorf("%s is a directory, expected a car file", path) } + roots, blocks, err := car.Decode(f0) + if err != nil { + return nil, fmt.Errorf("decoding CAR: %w", err) + } + + if len(roots) == 0 { + return nil, fmt.Errorf("missing root CID") + } + if stat.Size() < sharding.ShardSize { hash, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) if err != nil { @@ -110,10 +119,6 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp shdlnks = append(shdlnks, link) } else { - _, blocks, err := car.Decode(f0) - if err != nil { - return nil, fmt.Errorf("decoding CAR: %w", err) - } shds, err := sharding.NewSharder([]ipld.Link{}, blocks) if err != nil { return nil, fmt.Errorf("sharding CAR: %w", err) @@ -137,21 +142,6 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp // TODO: build, add and register index - f1, err := os.Open(path) - if err != nil { - return nil, fmt.Errorf("opening file: %w", err) - } - defer f1.Close() - - roots, _, err := car.Decode(f1) - if err != nil { - return nil, fmt.Errorf("reading roots: %w", err) - } - - if len(roots) == 0 { - return nil, fmt.Errorf("missing root CID") - } - // rcpt, err := client.UploadAdd( // signer, // space, From a42c94ca1525f8c3f61e32557eb4ea02ebe088cc Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 12:18:57 +0200 Subject: [PATCH 21/28] feedback: alias capability packages consistently --- client/client.go | 48 +++++++++++++++++++++---------------------- client/client_test.go | 18 ++++++++-------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/client/client.go b/client/client.go index e6b737d0..b163e32d 100644 --- a/client/client.go +++ b/client/client.go @@ -10,12 +10,12 @@ import ( "time" "github.com/multiformats/go-multihash" - "github.com/storacha/go-libstoracha/capabilities/blob" + blobcap "github.com/storacha/go-libstoracha/capabilities/blob" httpcap "github.com/storacha/go-libstoracha/capabilities/http" - spaceblob "github.com/storacha/go-libstoracha/capabilities/space/blob" + spaceblobcap "github.com/storacha/go-libstoracha/capabilities/space/blob" captypes "github.com/storacha/go-libstoracha/capabilities/types" ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" - w3sBlob "github.com/storacha/go-libstoracha/capabilities/web3.storage/blob" + w3sblobcap "github.com/storacha/go-libstoracha/capabilities/web3.storage/blob" "github.com/storacha/go-ucanto/client" "github.com/storacha/go-ucanto/core/dag/blockstore" "github.com/storacha/go-ucanto/core/delegation" @@ -159,14 +159,14 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts return nil, nil, fmt.Errorf("computing content multihash: %w", err) } - caveats := spaceblob.AddCaveats{ - Blob: spaceblob.Blob{ + caveats := spaceblobcap.AddCaveats{ + Blob: spaceblobcap.Blob{ Digest: contentHash, Size: uint64(len(contentBytes)), }, } - inv, err := spaceblob.Add.Invoke(issuer, cfg.conn.ID(), space.String(), caveats, convertToInvocationOptions(cfg)...) + inv, err := spaceblobcap.Add.Invoke(issuer, cfg.conn.ID(), space.String(), caveats, convertToInvocationOptions(cfg)...) if err != nil { return nil, nil, fmt.Errorf("generating invocation: %w", err) } @@ -205,9 +205,9 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts inv, ok := task.Invocation() if ok { switch inv.Capabilities()[0].Can() { - case blob.AllocateAbility: + case blobcap.AllocateAbility: allocateTask = inv - case w3sBlob.AllocateAbility: + case w3sblobcap.AllocateAbility: if allocateTask == nil { allocateTask = inv } @@ -215,9 +215,9 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts concludeFxs = append(concludeFxs, inv) case httpcap.PutAbility: putTask = inv - case blob.AcceptAbility: + case blobcap.AcceptAbility: acceptTask = inv - case w3sBlob.AcceptAbility: + case w3sblobcap.AcceptAbility: if acceptTask == nil { acceptTask = inv legacyAccept = true @@ -230,11 +230,11 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts return nil, nil, fmt.Errorf("mandatory tasks not received in space/blob/add receipt") } - var allocateRcpt receipt.Receipt[blob.AllocateOk, fdm.FailureModel] - var legacyAllocateRcpt receipt.Receipt[w3sBlob.AllocateOk, fdm.FailureModel] + var allocateRcpt receipt.Receipt[blobcap.AllocateOk, fdm.FailureModel] + var legacyAllocateRcpt receipt.Receipt[w3sblobcap.AllocateOk, fdm.FailureModel] var putRcpt receipt.AnyReceipt - var acceptRcpt receipt.Receipt[blob.AcceptOk, fdm.FailureModel] - var legacyAcceptRcpt receipt.Receipt[w3sBlob.AcceptOk, fdm.FailureModel] + var acceptRcpt receipt.Receipt[blobcap.AcceptOk, fdm.FailureModel] + var legacyAcceptRcpt receipt.Receipt[w3sblobcap.AcceptOk, fdm.FailureModel] for _, concludeFx := range concludeFxs { concludeRcpt, err := getConcludeReceipt(concludeFx) if err != nil { @@ -244,13 +244,13 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts switch concludeRcpt.Ran().Link() { case allocateTask.Link(): switch allocateTask.Capabilities()[0].Can() { - case blob.AllocateAbility: - allocateRcpt, err = receipt.Rebind[blob.AllocateOk, fdm.FailureModel](concludeRcpt, blob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) + case blobcap.AllocateAbility: + allocateRcpt, err = receipt.Rebind[blobcap.AllocateOk, fdm.FailureModel](concludeRcpt, blobcap.AllocateOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) } - case w3sBlob.AllocateAbility: - legacyAllocateRcpt, err = receipt.Rebind[w3sBlob.AllocateOk, fdm.FailureModel](concludeRcpt, w3sBlob.AllocateOkType(), fdm.FailureType(), captypes.Converters...) + case w3sblobcap.AllocateAbility: + legacyAllocateRcpt, err = receipt.Rebind[w3sblobcap.AllocateOk, fdm.FailureModel](concludeRcpt, w3sblobcap.AllocateOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) } @@ -259,13 +259,13 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts putRcpt = concludeRcpt case acceptTask.Link(): switch allocateTask.Capabilities()[0].Can() { - case blob.AcceptAbility: - acceptRcpt, err = receipt.Rebind[blob.AcceptOk, fdm.FailureModel](concludeRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + case blobcap.AcceptAbility: + acceptRcpt, err = receipt.Rebind[blobcap.AcceptOk, fdm.FailureModel](concludeRcpt, blobcap.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) } - case w3sBlob.AcceptAbility: - legacyAcceptRcpt, err = receipt.Rebind[w3sBlob.AcceptOk, fdm.FailureModel](concludeRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + case w3sblobcap.AcceptAbility: + legacyAcceptRcpt, err = receipt.Rebind[w3sblobcap.AcceptOk, fdm.FailureModel](concludeRcpt, w3sblobcap.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) } @@ -358,7 +358,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts if site == nil { if !legacyAccept { - acceptRcpt, err = receipt.Rebind[blob.AcceptOk, fdm.FailureModel](anyAcceptRcpt, blob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + acceptRcpt, err = receipt.Rebind[blobcap.AcceptOk, fdm.FailureModel](anyAcceptRcpt, blobcap.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("fetching accept receipt: %w", err) } @@ -371,7 +371,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts site = acceptOk.Site rcptBlocks = acceptRcpt.Blocks() } else { - legacyAcceptRcpt, err = receipt.Rebind[w3sBlob.AcceptOk, fdm.FailureModel](anyAcceptRcpt, w3sBlob.AcceptOkType(), fdm.FailureType(), captypes.Converters...) + legacyAcceptRcpt, err = receipt.Rebind[w3sblobcap.AcceptOk, fdm.FailureModel](anyAcceptRcpt, w3sblobcap.AcceptOkType(), fdm.FailureType(), captypes.Converters...) if err != nil { return nil, nil, fmt.Errorf("fetching legacy accept receipt: %w", err) } diff --git a/client/client_test.go b/client/client_test.go index a94b6038..e6eb0e99 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -16,11 +16,11 @@ import ( "github.com/ipld/go-ipld-prime/fluent/qp" "github.com/ipld/go-ipld-prime/node/basicnode" "github.com/multiformats/go-multihash" - "github.com/storacha/go-libstoracha/capabilities/assert" + assertcap "github.com/storacha/go-libstoracha/capabilities/assert" blobcap "github.com/storacha/go-libstoracha/capabilities/blob" httpcap "github.com/storacha/go-libstoracha/capabilities/http" spaceblobcap "github.com/storacha/go-libstoracha/capabilities/space/blob" - "github.com/storacha/go-libstoracha/capabilities/types" + captypes "github.com/storacha/go-libstoracha/capabilities/types" ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" uploadcap "github.com/storacha/go-libstoracha/capabilities/upload" uclient "github.com/storacha/go-ucanto/client" @@ -230,13 +230,13 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob // add task for http/put httpPutCaveats := httpcap.PutCaveats{ - URL: types.Promise{ - UcanAwait: types.Await{ + URL: captypes.Promise{ + UcanAwait: captypes.Await{ Selector: ".out.ok.address.url", Link: allocateRcpt.Root().Link()}, }, - Headers: types.Promise{ - UcanAwait: types.Await{ + Headers: captypes.Promise{ + UcanAwait: captypes.Await{ Selector: ".out.ok.address.headers", Link: allocateRcpt.Root().Link()}, }, @@ -393,13 +393,13 @@ func setupHTTPHandlers(t *testing.T, mux *http.ServeMux, ucanSrv server.ServerVi return } - locationClaim, err := assert.Location.Delegate( + locationClaim, err := assertcap.Location.Delegate( acceptedBlobData.StorageProvider, acceptedBlobData.Space.DID(), acceptedBlobData.Space.DID().String(), - assert.LocationCaveats{ + assertcap.LocationCaveats{ Space: acceptedBlobData.Space.DID(), - Content: types.FromHash(acceptedBlobData.Digest), + Content: captypes.FromHash(acceptedBlobData.Digest), Location: []url.URL{*acceptedBlobData.Location}, }, delegation.WithNoExpiration(), From 54ad2c80b89af24e80f10de3f4b9c7ccc4c14245 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 12:40:23 +0200 Subject: [PATCH 22/28] feedback: add default cases to switch statements where appropriate --- client/client.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/client.go b/client/client.go index b163e32d..9f4c8b93 100644 --- a/client/client.go +++ b/client/client.go @@ -222,6 +222,8 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts acceptTask = inv legacyAccept = true } + default: + fmt.Printf("[WARN] ignoring unexpected task: %s\n", inv.Capabilities()[0].Can()) } } } @@ -254,6 +256,8 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts if err != nil { return nil, nil, fmt.Errorf("bad allocate receipt in conclude fx: %w", err) } + default: + return nil, nil, fmt.Errorf("unexpected capability in allocate task: %s", allocateTask.Capabilities()[0].Can()) } case putTask.Link(): putRcpt = concludeRcpt @@ -269,7 +273,11 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts if err != nil { return nil, nil, fmt.Errorf("bad accept receipt in conclude fx: %w", err) } + default: + return nil, nil, fmt.Errorf("unexpected capability in accept task: %s", acceptTask.Capabilities()[0].Can()) } + default: + fmt.Printf("[WARN] ignoring receipt for unexpected task: %s\n", concludeRcpt.Ran().Link()) } } From 435e80776393b3ec3841922e5ab07714e510a13c Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 19:38:24 +0200 Subject: [PATCH 23/28] feedback: add contexts --- client/client.go | 31 ++++++++++++++++--------------- client/client_test.go | 3 ++- cmd/upload.go | 21 +++++++++++---------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/client/client.go b/client/client.go index 9f4c8b93..4b7d4e06 100644 --- a/client/client.go +++ b/client/client.go @@ -2,6 +2,7 @@ package client import ( "bytes" + "context" "fmt" "io" "iter" @@ -16,7 +17,7 @@ import ( captypes "github.com/storacha/go-libstoracha/capabilities/types" ucancap "github.com/storacha/go-libstoracha/capabilities/ucan" w3sblobcap "github.com/storacha/go-libstoracha/capabilities/web3.storage/blob" - "github.com/storacha/go-ucanto/client" + uclient "github.com/storacha/go-ucanto/client" "github.com/storacha/go-ucanto/core/dag/blockstore" "github.com/storacha/go-ucanto/core/delegation" "github.com/storacha/go-ucanto/core/invocation" @@ -65,7 +66,7 @@ func UploadAdd(issuer principal.Signer, space did.DID, params uploadadd.Caveat, return nil, err } - resp, err := client.Execute([]invocation.Invocation{inv}, cfg.conn) + resp, err := uclient.Execute([]invocation.Invocation{inv}, cfg.conn) if err != nil { return nil, err } @@ -111,7 +112,7 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat return nil, err } - resp, err := client.Execute([]invocation.Invocation{inv}, cfg.conn) + resp, err := uclient.Execute([]invocation.Invocation{inv}, cfg.conn) if err != nil { return nil, err } @@ -141,7 +142,7 @@ func UploadList(issuer principal.Signer, space did.DID, params uploadlist.Caveat // // Returns the multihash of the added blob and the location commitment that contains details about where the // blob can be located, or an error if something went wrong. -func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (multihash.Multihash, delegation.Delegation, error) { +func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, space did.DID, receiptsURL *url.URL, options ...Option) (multihash.Multihash, delegation.Delegation, error) { cfg := ClientConfig{conn: DefaultConnection} for _, opt := range options { if err := opt(&cfg); err != nil { @@ -171,7 +172,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts return nil, nil, fmt.Errorf("generating invocation: %w", err) } - resp, err := client.Execute([]invocation.Invocation{inv}, cfg.conn) + resp, err := uclient.Execute([]invocation.Invocation{inv}, cfg.conn) if err != nil { return nil, nil, fmt.Errorf("sending invocation: %w", err) } @@ -315,7 +316,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts headers = address.Headers } - if err := putBlob(url, headers, contentBytes); err != nil { + if err := putBlob(ctx, url, headers, contentBytes); err != nil { return nil, nil, fmt.Errorf("putting blob: %w", err) } @@ -338,13 +339,13 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts var site ucan.Link var rcptBlocks iter.Seq2[ipld.Block, error] if acceptRcpt == nil && legacyAcceptRcpt == nil { - anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + anyAcceptRcpt, err = pollAccept(ctx, acceptTask.Link(), cfg.conn, receiptsURL) if err != nil { return nil, nil, fmt.Errorf("polling accept: %w", err) } } else if acceptRcpt != nil { if acceptRcpt.Out().Ok() == nil { - anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + anyAcceptRcpt, err = pollAccept(ctx, acceptTask.Link(), cfg.conn, receiptsURL) if err != nil { return nil, nil, fmt.Errorf("polling accept: %w", err) } @@ -354,7 +355,7 @@ func BlobAdd(content io.Reader, issuer principal.Signer, space did.DID, receipts } } else if legacyAcceptRcpt != nil { if legacyAcceptRcpt.Out().Ok() == nil { - anyAcceptRcpt, err = pollAccept(acceptTask.Link(), cfg.conn, receiptsURL) + anyAcceptRcpt, err = pollAccept(ctx, acceptTask.Link(), cfg.conn, receiptsURL) if err != nil { return nil, nil, fmt.Errorf("polling accept: %w", err) } @@ -422,8 +423,8 @@ func getConcludeReceipt(concludeFx invocation.Invocation) (receipt.AnyReceipt, e return rcpt, nil } -func putBlob(url url.URL, headers http.Header, body []byte) error { - req, err := http.NewRequest(http.MethodPut, url.String(), bytes.NewReader(body)) +func putBlob(ctx context.Context, url url.URL, headers http.Header, body []byte) error { + req, err := http.NewRequestWithContext(ctx, http.MethodPut, url.String(), bytes.NewReader(body)) if err != nil { return fmt.Errorf("creating upload request: %w", err) } @@ -449,7 +450,7 @@ func putBlob(url url.URL, headers http.Header, body []byte) error { return nil } -func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience ucan.Principal, conn client.Connection) error { +func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience ucan.Principal, conn uclient.Connection) error { if len(putTask.Facts()) != 1 { return fmt.Errorf("invalid put facts, wanted 1 fact but got %d", len(putTask.Facts())) } @@ -561,7 +562,7 @@ func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience httpPutConcludeInvocation.Attach(rcptBlock) } - resp, err := client.Execute([]invocation.Invocation{httpPutConcludeInvocation}, conn) + resp, err := uclient.Execute([]invocation.Invocation{httpPutConcludeInvocation}, conn) if err != nil { return fmt.Errorf("executing conclude invocation: %w", err) } @@ -589,9 +590,9 @@ func sendPutReceipt(putTask invocation.Invocation, issuer ucan.Signer, audience return nil } -func pollAccept(acceptTaskLink ucan.Link, conn client.Connection, receiptsURL *url.URL) (receipt.AnyReceipt, error) { +func pollAccept(ctx context.Context, acceptTaskLink ucan.Link, conn uclient.Connection, receiptsURL *url.URL) (receipt.AnyReceipt, error) { receiptURL := receiptsURL.JoinPath(acceptTaskLink.String()) - req, err := http.NewRequest(http.MethodGet, receiptURL.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, receiptURL.String(), nil) if err != nil { return nil, fmt.Errorf("creating get request: %w", err) } diff --git a/client/client_test.go b/client/client_test.go index e6eb0e99..36eb755c 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -2,6 +2,7 @@ package client_test import ( "bytes" + "context" "crypto/rand" "fmt" "io" @@ -92,7 +93,7 @@ func TestBlobAdd(t *testing.T) { testBlob := bytes.NewReader([]byte("test")) - _, _, err = client.BlobAdd(testBlob, issuer, space.DID(), receiptsURL, client.WithConnection(conn), client.WithProof(proof)) + _, _, err = client.BlobAdd(context.Background(), testBlob, issuer, space.DID(), receiptsURL, client.WithConnection(conn), client.WithProof(proof)) require.NoError(t, err) } diff --git a/cmd/upload.go b/cmd/upload.go index 06b20087..43018943 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "net/url" @@ -53,20 +54,20 @@ func upload(cCtx *cli.Context) error { if isCAR { fmt.Printf("Uploading %s...\n", paths[0]) var err error - root, err = uploadCAR(paths[0], signer, conn, space, proofs, receiptsURL) + root, err = uploadCAR(cCtx.Context, paths[0], signer, conn, space, proofs, receiptsURL) if err != nil { return err } } else { if len(paths) == 1 && !isWrap { var err error - root, err = uploadFile(paths[0], signer, conn, space, proofs, receiptsURL) + root, err = uploadFile(cCtx.Context, paths[0], signer, conn, space, proofs, receiptsURL) if err != nil { return err } } else { var err error - root, err = uploadDirectory(paths, signer, conn, space, proofs, receiptsURL) + root, err = uploadDirectory(cCtx.Context, paths, signer, conn, space, proofs, receiptsURL) if err != nil { return err } @@ -82,7 +83,7 @@ func upload(cCtx *cli.Context) error { return nil } -func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { +func uploadCAR(ctx context.Context, path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { f0, err := os.Open(path) if err != nil { return nil, fmt.Errorf("opening file: %w", err) @@ -110,7 +111,7 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp } if stat.Size() < sharding.ShardSize { - hash, err := addBlob(f0, signer, conn, space, proofs, receiptsURL) + hash, err := addBlob(ctx, f0, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, err } @@ -129,7 +130,7 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return nil, fmt.Errorf("ranging shards: %w", err) } - hash, err := addBlob(shd, signer, conn, space, proofs, receiptsURL) + hash, err := addBlob(ctx, shd, signer, conn, space, proofs, receiptsURL) if err != nil { return nil, fmt.Errorf("uploading shard: %w", err) } @@ -193,16 +194,16 @@ func uploadCAR(path string, signer principal.Signer, conn uclient.Connection, sp return roots[0], nil } -func uploadFile(path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { +func uploadFile(ctx context.Context, path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { return nil, nil } -func uploadDirectory(paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { +func uploadDirectory(ctx context.Context, paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { return nil, nil } -func addBlob(content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (multihash.Multihash, error) { - contentHash, _, err := client.BlobAdd(content, signer, space, receiptsURL, client.WithConnection(conn), client.WithProofs(proofs)) +func addBlob(ctx context.Context, content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (multihash.Multihash, error) { + contentHash, _, err := client.BlobAdd(ctx, content, signer, space, receiptsURL, client.WithConnection(conn), client.WithProofs(proofs)) if err != nil { return nil, err } From 8f5e4741c98bd79f6ad830746733c173b4aa7a34 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Wed, 30 Apr 2025 19:56:16 +0200 Subject: [PATCH 24/28] feedback: assume blob has already been uploaded if allocated address is nil --- client/client.go | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/client/client.go b/client/client.go index 4b7d4e06..d780ba66 100644 --- a/client/client.go +++ b/client/client.go @@ -286,7 +286,7 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp return nil, nil, fmt.Errorf("mandatory receipts not received in space/blob/add receipt") } - var url url.URL + var url *url.URL var headers http.Header if allocateRcpt != nil { allocateOk, err := result.Unwrap(result.MapError(allocateRcpt.Out(), failure.FromFailureModel)) @@ -295,12 +295,10 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp } address := allocateOk.Address - if address == nil { - return nil, nil, fmt.Errorf("blob allocation failed: no address") + if address != nil { + url = &address.URL + headers = address.Headers } - - url = address.URL - headers = address.Headers } else { allocateOk, err := result.Unwrap(result.MapError(legacyAllocateRcpt.Out(), failure.FromFailureModel)) if err != nil { @@ -308,16 +306,16 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp } address := allocateOk.Address - if address == nil { - return nil, nil, fmt.Errorf("blob allocation failed: no address") + if address != nil { + url = &address.URL + headers = address.Headers } - - url = address.URL - headers = address.Headers } - if err := putBlob(ctx, url, headers, contentBytes); err != nil { - return nil, nil, fmt.Errorf("putting blob: %w", err) + if url != nil && headers != nil { + if err := putBlob(ctx, url, headers, contentBytes); err != nil { + return nil, nil, fmt.Errorf("putting blob: %w", err) + } } // invoke `ucan/conclude` with `http/put` receipt @@ -423,7 +421,7 @@ func getConcludeReceipt(concludeFx invocation.Invocation) (receipt.AnyReceipt, e return rcpt, nil } -func putBlob(ctx context.Context, url url.URL, headers http.Header, body []byte) error { +func putBlob(ctx context.Context, url *url.URL, headers http.Header, body []byte) error { req, err := http.NewRequestWithContext(ctx, http.MethodPut, url.String(), bytes.NewReader(body)) if err != nil { return fmt.Errorf("creating upload request: %w", err) From 7e92922a4114ec28e747b40a9694c3e1c5e5922c Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Thu, 1 May 2025 14:50:41 +0200 Subject: [PATCH 25/28] feedback: remove concurrent-requests flag, which is unused --- cmd/upload.go | 1 - cmd/w3.go | 5 ----- 2 files changed, 6 deletions(-) diff --git a/cmd/upload.go b/cmd/upload.go index 43018943..b261b474 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -41,7 +41,6 @@ func upload(cCtx *cli.Context) error { // isVerbose := cCtx.Bool("verbose") isWrap := cCtx.Bool("wrap") // shardSize := cCtx.Int("shard-size") - // concurrentRequests := cCtx.Int("concurrent-requests") var paths []string if isCAR { diff --git a/cmd/w3.go b/cmd/w3.go index 0082d964..ce9bbb6b 100644 --- a/cmd/w3.go +++ b/cmd/w3.go @@ -72,11 +72,6 @@ func main() { Value: 0, Usage: "Shard uploads into CAR files of approximately this size in bytes.", }, - &cli.IntFlag{ - Name: "concurrent-requests", - Value: 5, - Usage: "Send up to this many CAR shards concurrently.", - }, }, Action: upload, }, From b864f3dc9e7c60511f5fa3d70756a2f1dd0a5b08 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Thu, 1 May 2025 14:54:17 +0200 Subject: [PATCH 26/28] feedback: pass CAR roots to sharder --- cmd/upload.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/upload.go b/cmd/upload.go index b261b474..0a7aa778 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -119,7 +119,7 @@ func uploadCAR(ctx context.Context, path string, signer principal.Signer, conn u shdlnks = append(shdlnks, link) } else { - shds, err := sharding.NewSharder([]ipld.Link{}, blocks) + shds, err := sharding.NewSharder(roots, blocks) if err != nil { return nil, fmt.Errorf("sharding CAR: %w", err) } From 7285d193e1b7add1ca6db0a3ca05f40bc0137dd2 Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Thu, 1 May 2025 15:00:59 +0200 Subject: [PATCH 27/28] feedback: unimplemented functions return errors --- cmd/upload.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/upload.go b/cmd/upload.go index 0a7aa778..3f8616e8 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "fmt" "io" "net/url" @@ -194,11 +195,11 @@ func uploadCAR(ctx context.Context, path string, signer principal.Signer, conn u } func uploadFile(ctx context.Context, path string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { - return nil, nil + return nil, errors.New("not implemented") } func uploadDirectory(ctx context.Context, paths []string, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (ipld.Link, error) { - return nil, nil + return nil, errors.New("not implemented") } func addBlob(ctx context.Context, content io.Reader, signer principal.Signer, conn uclient.Connection, space did.DID, proofs []delegation.Delegation, receiptsURL *url.URL) (multihash.Multihash, error) { From 919c416fc9bd58e6bdff906f6c14ab8cde14131d Mon Sep 17 00:00:00 2001 From: Vicente Olmedo Date: Mon, 12 May 2025 10:36:26 +0200 Subject: [PATCH 28/28] use proper releases of go-ucanto and go-libstoracha --- client/client.go | 28 ++++++++++++++-------------- client/client_test.go | 6 +++--- cmd/upload.go | 6 ++++-- go.mod | 10 +++------- go.sum | 6 ++++++ 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/client/client.go b/client/client.go index d780ba66..5bf31216 100644 --- a/client/client.go +++ b/client/client.go @@ -161,7 +161,7 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp } caveats := spaceblobcap.AddCaveats{ - Blob: spaceblobcap.Blob{ + Blob: captypes.Blob{ Digest: contentHash, Size: uint64(len(contentBytes)), }, @@ -182,21 +182,19 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp return nil, nil, fmt.Errorf("receipt not found: %s", inv.Link()) } - // reader, err := receipt.NewReceiptReaderFromTypes[spaceblob.AddOk, fdm.FailureModel](spaceblob.AddOkType(), fdm.FailureType()) - // if err != nil { - // return nil, nil, fmt.Errorf("generating receipt reader: %w", err) - // } - reader := receipt.NewAnyReceiptReader(captypes.Converters...) + reader, err := receipt.NewReceiptReaderFromTypes[spaceblobcap.AddOk, fdm.FailureModel](spaceblobcap.AddOkType(), fdm.FailureType()) + if err != nil { + return nil, nil, fmt.Errorf("generating receipt reader: %w", err) + } rcpt, err := reader.Read(rcptlnk, resp.Blocks()) if err != nil { return nil, nil, fmt.Errorf("reading receipt: %w", err) } - //_, err = result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) - _, fail := result.Unwrap(rcpt.Out()) - if fail != nil { - return nil, nil, fmt.Errorf("blob add failed: %v", fail) + _, failErr := result.Unwrap(result.MapError(rcpt.Out(), failure.FromFailureModel)) + if failErr != nil { + return nil, nil, fmt.Errorf("blob add failed: %+v", failErr) } var allocateTask, putTask, acceptTask invocation.Invocation @@ -342,23 +340,25 @@ func BlobAdd(ctx context.Context, content io.Reader, issuer principal.Signer, sp return nil, nil, fmt.Errorf("polling accept: %w", err) } } else if acceptRcpt != nil { - if acceptRcpt.Out().Ok() == nil { + acceptOk, failErr := result.Unwrap(result.MapError(acceptRcpt.Out(), failure.FromFailureModel)) + if failErr != nil { anyAcceptRcpt, err = pollAccept(ctx, acceptTask.Link(), cfg.conn, receiptsURL) if err != nil { return nil, nil, fmt.Errorf("polling accept: %w", err) } } else { - site = acceptRcpt.Out().Ok().Site + site = acceptOk.Site rcptBlocks = acceptRcpt.Blocks() } } else if legacyAcceptRcpt != nil { - if legacyAcceptRcpt.Out().Ok() == nil { + acceptOk, failErr := result.Unwrap(result.MapError(legacyAcceptRcpt.Out(), failure.FromFailureModel)) + if failErr != nil { anyAcceptRcpt, err = pollAccept(ctx, acceptTask.Link(), cfg.conn, receiptsURL) if err != nil { return nil, nil, fmt.Errorf("polling accept: %w", err) } } else { - site = legacyAcceptRcpt.Out().Ok().Site + site = acceptOk.Site rcptBlocks = legacyAcceptRcpt.Blocks() } } diff --git a/client/client_test.go b/client/client_test.go index 36eb755c..6e89d59f 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -195,7 +195,7 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob } allocateCaveats := blobcap.AllocateCaveats{ Space: spaceDID, - Blob: blobcap.Blob{ + Blob: captypes.Blob{ Digest: blobDigest, Size: blobSize, }, @@ -269,7 +269,7 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob // add task for blob/accept acceptCaveats := blobcap.AcceptCaveats{ Space: spaceDID, - Blob: blobcap.Blob{ + Blob: captypes.Blob{ Digest: blobDigest, Size: blobSize, }, @@ -291,7 +291,7 @@ func setupTestUCANServer(t *testing.T, serverPrincipal principal.Signer, putBlob StorageProvider: mockSPPrincipal, Digest: blobDigest, Space: spaceDID, - Location: &allocateResult.Ok().Address.URL, + Location: putBlobURL, } forks := []fx.Effect{ diff --git a/cmd/upload.go b/cmd/upload.go index 3f8616e8..3b870d0b 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -20,6 +20,7 @@ import ( "github.com/storacha/go-ucanto/core/invocation" "github.com/storacha/go-ucanto/core/ipld" "github.com/storacha/go-ucanto/core/receipt" + "github.com/storacha/go-ucanto/core/result" "github.com/storacha/go-ucanto/did" "github.com/storacha/go-ucanto/principal" "github.com/storacha/go-w3up/car/sharding" @@ -185,8 +186,9 @@ func uploadCAR(ctx context.Context, path string, signer principal.Signer, conn u return nil, err } - if rcpt.Out().Err() != nil { - return nil, fmt.Errorf("%+v", rcpt.Out().Err()) + _, failErr := result.Unwrap(rcpt.Out()) + if failErr != nil { + return nil, fmt.Errorf("%+v", failErr) } fmt.Printf("Uploaded %d bytes\n", stat.Size()) diff --git a/go.mod b/go.mod index eb4f1b00..e34a01a2 100644 --- a/go.mod +++ b/go.mod @@ -2,17 +2,14 @@ module github.com/storacha/go-w3up go 1.23.3 -replace github.com/storacha/go-libstoracha => ../go-libstoracha - -replace github.com/storacha/go-ucanto => ../go-ucanto - require ( github.com/ipfs/go-cid v0.5.0 github.com/ipld/go-ipld-prime v0.21.1-0.20240917223228-6148356a4c2e + github.com/multiformats/go-multicodec v0.9.0 github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-varint v0.0.7 - github.com/storacha/go-libstoracha v0.0.0-00010101000000-000000000000 - github.com/storacha/go-ucanto v0.3.0 + github.com/storacha/go-libstoracha v0.0.3 + github.com/storacha/go-ucanto v0.3.2 github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.25.7 ) @@ -60,7 +57,6 @@ require ( github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr v0.14.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/onsi/ginkgo/v2 v2.23.3 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pion/datachannel v1.5.10 // indirect diff --git a/go.sum b/go.sum index a0151782..445a58ac 100644 --- a/go.sum +++ b/go.sum @@ -100,6 +100,8 @@ github.com/filecoin-project/go-data-segment v0.0.1 h1:1wmDxOG4ubWQm3ZC1XI5nCon5q github.com/filecoin-project/go-data-segment v0.0.1/go.mod h1:H0/NKbsRxmRFBcLibmABv+yFNHdmtl5AyplYLnb0Zv4= github.com/filecoin-project/go-fil-commcid v0.2.0 h1:B+5UX8XGgdg/XsdUpST4pEBviKkFOw+Fvl2bLhSKGpI= github.com/filecoin-project/go-fil-commcid v0.2.0/go.mod h1:8yigf3JDIil+/WpqR5zoKyP0jBPCOGtEqq/K1CcMy9Q= +github.com/filecoin-project/go-fil-commp-hashhash v0.2.0 h1:HYIUugzjq78YvV3vC6rL95+SfC/aSTVSnZSZiDV5pCk= +github.com/filecoin-project/go-fil-commp-hashhash v0.2.0/go.mod h1:VH3fAFOru4yyWar4626IoS5+VGE8SfZiBODJLUigEo4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -530,6 +532,10 @@ github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t6 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/storacha/go-libstoracha v0.0.3 h1:/nJVZqLpVNzOFDA6N4061PrZdDHmY2imSr0xy1yp6aI= +github.com/storacha/go-libstoracha v0.0.3/go.mod h1:WboSjSw0DspzpVF4PhHev2fEF9wdChyP0f6wIRJInRs= +github.com/storacha/go-ucanto v0.3.2 h1:oIymV1eOkw+k2ot2MFbBj3oNwIDi3L4KJ/DUJNZGpjs= +github.com/storacha/go-ucanto v0.3.2/go.mod h1:kslS8xldf12d2D4kj0wBfOvAP1gftzMjTxBdJwGKwZE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=