From 494fbce2f7dad1b6ffff6c247afd30793b9f5619 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sun, 31 Aug 2025 05:12:56 +0200 Subject: [PATCH 1/5] feat: add SessionExchange support and optimize blocking checks - implement BlockedBlockstore wrapper for blockstore operations - implement BlockedExchange with SessionExchange support - add BlockedFetcher for session-level blocking - optimize BlockService to delegate checks to wrapped components - add compile-time type assertions for all interfaces fixes ipfs-shipyard/nopfs#34 --- ipfs/blockservice.go | 56 ++++++----- ipfs/blockstore.go | 123 ++++++++++++++++++++++++ ipfs/exchange.go | 218 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+), 23 deletions(-) create mode 100644 ipfs/blockstore.go create mode 100644 ipfs/exchange.go diff --git a/ipfs/blockservice.go b/ipfs/blockservice.go index 02ab518..df5a4d4 100644 --- a/ipfs/blockservice.go +++ b/ipfs/blockservice.go @@ -15,8 +15,10 @@ var _ blockservice.BlockService = (*BlockService)(nil) // BlockService implements a blocking BlockService. type BlockService struct { - blocker *nopfs.Blocker - bs blockservice.BlockService + blocker *nopfs.Blocker + bs blockservice.BlockService + wrappedBlockstore blockstore.Blockstore + wrappedExchange exchange.Interface } // WrapBlockService wraps the given BlockService with a content-blocking layer @@ -24,10 +26,27 @@ type BlockService struct { func WrapBlockService(bs blockservice.BlockService, blocker *nopfs.Blocker) blockservice.BlockService { logger.Debug("BlockService wrapped with content blocker") - return &BlockService{ + wrapped := &BlockService{ blocker: blocker, bs: bs, } + + // Create wrapped blockstore and exchange + if bstore := bs.Blockstore(); bstore != nil { + wrapped.wrappedBlockstore = &BlockedBlockstore{ + Blockstore: bstore, + blocker: blocker, + } + } + + if exch := bs.Exchange(); exch != nil { + wrapped.wrappedExchange = &BlockedExchange{ + Interface: exch, + blocker: blocker, + } + } + + return wrapped } // Closes the BlockService and the Blocker. @@ -36,37 +55,28 @@ func (nbs *BlockService) Close() error { return nbs.bs.Close() } -// Gets a block unless CID has been blocked. +// GetBlock gets a block from the wrapped blockservice. +// The wrapped blockstore and exchange handle blocking checks. func (nbs *BlockService) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { - if err := nbs.blocker.IsCidBlocked(c).ToError(); err != nil { - logger.Warn(err.Response) - return nil, err - } + // No check needed here - wrapped blockstore/exchange will check return nbs.bs.GetBlock(ctx, c) } -// GetsBlocks reads several blocks. Blocked CIDs are filtered out of ks. +// GetBlocks gets multiple blocks from the wrapped blockservice. +// The wrapped exchange handles filtering of blocked CIDs. func (nbs *BlockService) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { - var filtered []cid.Cid - for _, c := range ks { - if err := nbs.blocker.IsCidBlocked(c).ToError(); err != nil { - logger.Warn(err.Response) - logger.Warnf("GetBlocks dropped blocked block: %s", err) - } else { - filtered = append(filtered, c) - } - } - return nbs.bs.GetBlocks(ctx, filtered) + // No filtering needed here - wrapped exchange will filter + return nbs.bs.GetBlocks(ctx, ks) } -// Blockstore returns the underlying Blockstore. +// Blockstore returns the wrapped Blockstore with blocking checks. func (nbs *BlockService) Blockstore() blockstore.Blockstore { - return nbs.bs.Blockstore() + return nbs.wrappedBlockstore } -// Exchange returns the underlying Exchange. +// Exchange returns the wrapped Exchange with blocking checks. func (nbs *BlockService) Exchange() exchange.Interface { - return nbs.bs.Exchange() + return nbs.wrappedExchange } // AddBlock adds a block unless the CID is blocked. diff --git a/ipfs/blockstore.go b/ipfs/blockstore.go new file mode 100644 index 0000000..75b8a67 --- /dev/null +++ b/ipfs/blockstore.go @@ -0,0 +1,123 @@ +package ipfs + +import ( + "context" + + "github.com/ipfs-shipyard/nopfs" + "github.com/ipfs/boxo/blockstore" + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" +) + +var blockstoreLogger = logging.Logger("nopfs/blockstore") + +var _ blockstore.Blockstore = (*BlockedBlockstore)(nil) + +// BlockedBlockstore wraps a Blockstore and filters blocked content. +type BlockedBlockstore struct { + blockstore.Blockstore + blocker *nopfs.Blocker +} + +// Get returns a block only if it's not blocked. +func (bs *BlockedBlockstore) Get(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { + blockstoreLogger.Warnf("Get blocked block: %s", c) + return nil, err + } + return bs.Blockstore.Get(ctx, c) +} + +// GetSize returns the size of a block only if it's not blocked. +func (bs *BlockedBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) { + if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { + blockstoreLogger.Warnf("GetSize blocked block: %s", c) + return 0, err + } + return bs.Blockstore.GetSize(ctx, c) +} + +// Has returns whether a block exists only if it's not blocked. +// If a block is blocked, it returns false (as if it doesn't exist). +func (bs *BlockedBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) { + if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { + blockstoreLogger.Debugf("Has blocked block: %s", c) + // Return false for blocked content, as if it doesn't exist + return false, nil + } + return bs.Blockstore.Has(ctx, c) +} + +// Put adds a block to the blockstore if it's not blocked. +func (bs *BlockedBlockstore) Put(ctx context.Context, b blocks.Block) error { + if err := bs.blocker.IsCidBlocked(b.Cid()).ToError(); err != nil { + blockstoreLogger.Warnf("Put blocked block: %s", b.Cid()) + return err + } + return bs.Blockstore.Put(ctx, b) +} + +// PutMany adds multiple blocks to the blockstore, filtering out blocked ones. +func (bs *BlockedBlockstore) PutMany(ctx context.Context, blks []blocks.Block) error { + var filtered []blocks.Block + for _, b := range blks { + if err := bs.blocker.IsCidBlocked(b.Cid()).ToError(); err != nil { + blockstoreLogger.Warnf("PutMany dropped blocked block: %s", b.Cid()) + // Skip blocked blocks but continue with others + } else { + filtered = append(filtered, b) + } + } + if len(filtered) == 0 { + return nil + } + return bs.Blockstore.PutMany(ctx, filtered) +} + +// DeleteBlock removes a block from the blockstore. +func (bs *BlockedBlockstore) DeleteBlock(ctx context.Context, c cid.Cid) error { + // Allow deletion even for blocked CIDs + return bs.Blockstore.DeleteBlock(ctx, c) +} + +// AllKeysChan returns a channel of all CIDs in the blockstore, filtering out blocked ones. +func (bs *BlockedBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + in, err := bs.Blockstore.AllKeysChan(ctx) + if err != nil { + return nil, err + } + + out := make(chan cid.Cid) + go func() { + defer close(out) + for { + select { + case c, ok := <-in: + if !ok { + return + } + if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { + blockstoreLogger.Debugf("AllKeysChan filtered blocked CID: %s", c) + continue // Skip blocked CIDs + } + select { + case out <- c: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + + return out, nil +} + +// HashOnRead calls the underlying blockstore's HashOnRead method if it implements it. +func (bs *BlockedBlockstore) HashOnRead(enabled bool) { + if hor, ok := bs.Blockstore.(interface{ HashOnRead(bool) }); ok { + hor.HashOnRead(enabled) + } +} diff --git a/ipfs/exchange.go b/ipfs/exchange.go new file mode 100644 index 0000000..536332e --- /dev/null +++ b/ipfs/exchange.go @@ -0,0 +1,218 @@ +package ipfs + +import ( + "context" + + "github.com/ipfs-shipyard/nopfs" + "github.com/ipfs/boxo/exchange" + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" +) + +var exchangeLogger = logging.Logger("nopfs/exchange") + +// Compile-time type checks +var ( + _ exchange.Interface = (*BlockedExchange)(nil) + _ exchange.SessionExchange = (*BlockedExchange)(nil) + _ exchange.Fetcher = (*BlockedExchange)(nil) + _ exchange.Fetcher = (*BlockedFetcher)(nil) +) + +// BlockedExchange wraps an Exchange and filters blocked content. +type BlockedExchange struct { + exchange.Interface + blocker *nopfs.Blocker +} + +// GetBlock gets a block from the exchange only if it's not blocked. +func (ex *BlockedExchange) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if err := ex.blocker.IsCidBlocked(c).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock blocked: %s", c) + return nil, err + } + + // Get the block from the underlying exchange + blk, err := ex.Interface.GetBlock(ctx, c) + if err != nil { + return nil, err + } + + // Double-check the returned block (in case exchange returns different CID) + if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) + return nil, err + } + + return blk, nil +} + +// GetBlocks gets multiple blocks from the exchange, filtering out blocked ones. +func (ex *BlockedExchange) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + // Filter the input CIDs + var filtered []cid.Cid + for _, c := range ks { + if err := ex.blocker.IsCidBlocked(c).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked CID from request: %s", c) + } else { + filtered = append(filtered, c) + } + } + + // If all CIDs are blocked, return empty channel + if len(filtered) == 0 { + ch := make(chan blocks.Block) + close(ch) + return ch, nil + } + + // Get blocks from underlying exchange + in, err := ex.Interface.GetBlocks(ctx, filtered) + if err != nil { + return nil, err + } + + // Filter the output blocks + out := make(chan blocks.Block) + go func() { + defer close(out) + for { + select { + case blk, ok := <-in: + if !ok { + return + } + // Check if the returned block is blocked + if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) + continue + } + select { + case out <- blk: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + + return out, nil +} + +// NotifyNewBlocks notifies the exchange about new blocks. +// We allow this even for blocked blocks as they might be needed for pinning/gc decisions. +func (ex *BlockedExchange) NotifyNewBlocks(ctx context.Context, blocks ...blocks.Block) error { + // Pass through to underlying exchange + // The exchange is only notified about blocks we already have, + // and blocking decisions should be made on retrieval, not notification + return ex.Interface.NotifyNewBlocks(ctx, blocks...) +} + +// Close closes the exchange. +func (ex *BlockedExchange) Close() error { + return ex.Interface.Close() +} + +// NewSession creates a new exchange session that also enforces blocking. +// If the underlying exchange supports sessions, it creates a wrapped session. +// Otherwise, it returns the BlockedExchange itself as a Fetcher. +func (ex *BlockedExchange) NewSession(ctx context.Context) exchange.Fetcher { + // Check if underlying exchange supports sessions + if sesEx, ok := ex.Interface.(exchange.SessionExchange); ok { + // Create a session from the underlying exchange and wrap it + underlyingSession := sesEx.NewSession(ctx) + return &BlockedFetcher{ + Fetcher: underlyingSession, + blocker: ex.blocker, + } + } + + // If no session support, return self as fetcher + // BlockedExchange already implements Fetcher interface + return ex +} + +// BlockedFetcher wraps a Fetcher and filters blocked content. +type BlockedFetcher struct { + exchange.Fetcher + blocker *nopfs.Blocker +} + +// GetBlock gets a block from the fetcher only if it's not blocked. +func (bf *BlockedFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if err := bf.blocker.IsCidBlocked(c).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock blocked: %s", c) + return nil, err + } + + // Get the block from the underlying fetcher + blk, err := bf.Fetcher.GetBlock(ctx, c) + if err != nil { + return nil, err + } + + // Double-check the returned block (in case fetcher returns different CID) + if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) + return nil, err + } + + return blk, nil +} + +// GetBlocks gets multiple blocks from the fetcher, filtering out blocked ones. +func (bf *BlockedFetcher) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + // Filter the input CIDs + var filtered []cid.Cid + for _, c := range ks { + if err := bf.blocker.IsCidBlocked(c).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked CID from request: %s", c) + } else { + filtered = append(filtered, c) + } + } + + // If all CIDs are blocked, return empty channel + if len(filtered) == 0 { + ch := make(chan blocks.Block) + close(ch) + return ch, nil + } + + // Get blocks from underlying fetcher + in, err := bf.Fetcher.GetBlocks(ctx, filtered) + if err != nil { + return nil, err + } + + // Filter the output blocks + out := make(chan blocks.Block) + go func() { + defer close(out) + for { + select { + case blk, ok := <-in: + if !ok { + return + } + // Check if the returned block is blocked + if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) + continue + } + select { + case out <- blk: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + + return out, nil +} From 8d2b62fbab7527a99e25e7c0ae4773b37c30eb8f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 1 Sep 2025 02:29:29 +0200 Subject: [PATCH 2/5] fix: noop if no denylist --- ipfs/blockservice.go | 19 +++++++++++------- ipfs/blockstore.go | 21 ++++++++++++++++++- ipfs/exchange.go | 48 +++++++++++++++++++++++++++++++++----------- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/ipfs/blockservice.go b/ipfs/blockservice.go index df5a4d4..798ed82 100644 --- a/ipfs/blockservice.go +++ b/ipfs/blockservice.go @@ -22,9 +22,8 @@ type BlockService struct { } // WrapBlockService wraps the given BlockService with a content-blocking layer -// for Get and Add operations. +// for Get and Add operations. This is the fx.Decorate compatible version. func WrapBlockService(bs blockservice.BlockService, blocker *nopfs.Blocker) blockservice.BlockService { - logger.Debug("BlockService wrapped with content blocker") wrapped := &BlockService{ blocker: blocker, @@ -45,13 +44,14 @@ func WrapBlockService(bs blockservice.BlockService, blocker *nopfs.Blocker) bloc blocker: blocker, } } - return wrapped } // Closes the BlockService and the Blocker. func (nbs *BlockService) Close() error { - nbs.blocker.Close() + if nbs.blocker != nil { + nbs.blocker.Close() + } return nbs.bs.Close() } @@ -81,15 +81,20 @@ func (nbs *BlockService) Exchange() exchange.Interface { // AddBlock adds a block unless the CID is blocked. func (nbs *BlockService) AddBlock(ctx context.Context, o blocks.Block) error { - if err := nbs.blocker.IsCidBlocked(o.Cid()).ToError(); err != nil { - logger.Warn(err.Response) - return err + if nbs.blocker != nil { + if err := nbs.blocker.IsCidBlocked(o.Cid()).ToError(); err != nil { + logger.Warn(err.Response) + return err + } } return nbs.bs.AddBlock(ctx, o) } // AddBlocks adds multiple blocks. Blocks with blocked CIDs are dropped. func (nbs *BlockService) AddBlocks(ctx context.Context, bs []blocks.Block) error { + if nbs.blocker == nil { + return nbs.bs.AddBlocks(ctx, bs) + } var filtered []blocks.Block for _, o := range bs { if err := nbs.blocker.IsCidBlocked(o.Cid()).ToError(); err != nil { diff --git a/ipfs/blockstore.go b/ipfs/blockstore.go index 75b8a67..9b57753 100644 --- a/ipfs/blockstore.go +++ b/ipfs/blockstore.go @@ -22,8 +22,11 @@ type BlockedBlockstore struct { // Get returns a block only if it's not blocked. func (bs *BlockedBlockstore) Get(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if bs.blocker == nil { + return bs.Blockstore.Get(ctx, c) + } if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { - blockstoreLogger.Warnf("Get blocked block: %s", c) + blockstoreLogger.Debugf("Get blocked block: %s", c) return nil, err } return bs.Blockstore.Get(ctx, c) @@ -31,6 +34,9 @@ func (bs *BlockedBlockstore) Get(ctx context.Context, c cid.Cid) (blocks.Block, // GetSize returns the size of a block only if it's not blocked. func (bs *BlockedBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) { + if bs.blocker == nil { + return bs.Blockstore.GetSize(ctx, c) + } if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { blockstoreLogger.Warnf("GetSize blocked block: %s", c) return 0, err @@ -41,6 +47,9 @@ func (bs *BlockedBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error // Has returns whether a block exists only if it's not blocked. // If a block is blocked, it returns false (as if it doesn't exist). func (bs *BlockedBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) { + if bs.blocker == nil { + return bs.Blockstore.Has(ctx, c) + } if err := bs.blocker.IsCidBlocked(c).ToError(); err != nil { blockstoreLogger.Debugf("Has blocked block: %s", c) // Return false for blocked content, as if it doesn't exist @@ -51,6 +60,9 @@ func (bs *BlockedBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) { // Put adds a block to the blockstore if it's not blocked. func (bs *BlockedBlockstore) Put(ctx context.Context, b blocks.Block) error { + if bs.blocker == nil { + return bs.Blockstore.Put(ctx, b) + } if err := bs.blocker.IsCidBlocked(b.Cid()).ToError(); err != nil { blockstoreLogger.Warnf("Put blocked block: %s", b.Cid()) return err @@ -60,6 +72,9 @@ func (bs *BlockedBlockstore) Put(ctx context.Context, b blocks.Block) error { // PutMany adds multiple blocks to the blockstore, filtering out blocked ones. func (bs *BlockedBlockstore) PutMany(ctx context.Context, blks []blocks.Block) error { + if bs.blocker == nil { + return bs.Blockstore.PutMany(ctx, blks) + } var filtered []blocks.Block for _, b := range blks { if err := bs.blocker.IsCidBlocked(b.Cid()).ToError(); err != nil { @@ -88,6 +103,10 @@ func (bs *BlockedBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, e return nil, err } + if bs.blocker == nil { + return in, nil + } + out := make(chan cid.Cid) go func() { defer close(out) diff --git a/ipfs/exchange.go b/ipfs/exchange.go index 536332e..50e6420 100644 --- a/ipfs/exchange.go +++ b/ipfs/exchange.go @@ -28,6 +28,9 @@ type BlockedExchange struct { // GetBlock gets a block from the exchange only if it's not blocked. func (ex *BlockedExchange) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if ex.blocker == nil { + return ex.Interface.GetBlock(ctx, c) + } if err := ex.blocker.IsCidBlocked(c).ToError(); err != nil { exchangeLogger.Warnf("GetBlock blocked: %s", c) return nil, err @@ -40,9 +43,11 @@ func (ex *BlockedExchange) GetBlock(ctx context.Context, c cid.Cid) (blocks.Bloc } // Double-check the returned block (in case exchange returns different CID) - if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { - exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) - return nil, err + if ex.blocker != nil { + if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) + return nil, err + } } return blk, nil @@ -50,6 +55,9 @@ func (ex *BlockedExchange) GetBlock(ctx context.Context, c cid.Cid) (blocks.Bloc // GetBlocks gets multiple blocks from the exchange, filtering out blocked ones. func (ex *BlockedExchange) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + if ex.blocker == nil { + return ex.Interface.GetBlocks(ctx, ks) + } // Filter the input CIDs var filtered []cid.Cid for _, c := range ks { @@ -84,9 +92,11 @@ func (ex *BlockedExchange) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan return } // Check if the returned block is blocked - if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { - exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) - continue + if ex.blocker != nil { + if err := ex.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) + continue + } } select { case out <- blk: @@ -124,6 +134,10 @@ func (ex *BlockedExchange) NewSession(ctx context.Context) exchange.Fetcher { if sesEx, ok := ex.Interface.(exchange.SessionExchange); ok { // Create a session from the underlying exchange and wrap it underlyingSession := sesEx.NewSession(ctx) + if ex.blocker == nil { + // If no blocker, return the session directly + return underlyingSession + } return &BlockedFetcher{ Fetcher: underlyingSession, blocker: ex.blocker, @@ -143,6 +157,9 @@ type BlockedFetcher struct { // GetBlock gets a block from the fetcher only if it's not blocked. func (bf *BlockedFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + if bf.blocker == nil { + return bf.Fetcher.GetBlock(ctx, c) + } if err := bf.blocker.IsCidBlocked(c).ToError(); err != nil { exchangeLogger.Warnf("GetBlock blocked: %s", c) return nil, err @@ -155,9 +172,11 @@ func (bf *BlockedFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block } // Double-check the returned block (in case fetcher returns different CID) - if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { - exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) - return nil, err + if bf.blocker != nil { + if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Warnf("GetBlock returned blocked block: %s", blk.Cid()) + return nil, err + } } return blk, nil @@ -165,6 +184,9 @@ func (bf *BlockedFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block // GetBlocks gets multiple blocks from the fetcher, filtering out blocked ones. func (bf *BlockedFetcher) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + if bf.blocker == nil { + return bf.Fetcher.GetBlocks(ctx, ks) + } // Filter the input CIDs var filtered []cid.Cid for _, c := range ks { @@ -199,9 +221,11 @@ func (bf *BlockedFetcher) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan b return } // Check if the returned block is blocked - if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { - exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) - continue + if bf.blocker != nil { + if err := bf.blocker.IsCidBlocked(blk.Cid()).ToError(); err != nil { + exchangeLogger.Debugf("GetBlocks filtered blocked block from response: %s", blk.Cid()) + continue + } } select { case out <- blk: From c690cc6ac8e9c0db082466063110080f7b17e678 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 1 Sep 2025 03:32:47 +0200 Subject: [PATCH 3/5] test: add tests for nopfs ipfs wrappers - test blockstore, exchange, and blockservice wrappers - add test helpers and mocks --- go.mod | 22 +- go.sum | 92 ++------ ipfs/blockservice_test.go | 267 ++++++++++++++++++++++ ipfs/blockstore_test.go | 275 +++++++++++++++++++++++ ipfs/exchange_test.go | 282 +++++++++++++++++++++++ ipfs/go.mod | 94 ++++---- ipfs/go.sum | 455 +++++++++++++------------------------- ipfs/test_helpers.go | 362 ++++++++++++++++++++++++++++++ 8 files changed, 1421 insertions(+), 428 deletions(-) create mode 100644 ipfs/blockservice_test.go create mode 100644 ipfs/blockstore_test.go create mode 100644 ipfs/exchange_test.go create mode 100644 ipfs/test_helpers.go diff --git a/go.mod b/go.mod index 872fa12..6dbd640 100644 --- a/go.mod +++ b/go.mod @@ -1,30 +1,30 @@ module github.com/ipfs-shipyard/nopfs -go 1.18 +go 1.24.0 require ( github.com/fsnotify/fsnotify v1.6.0 - github.com/ipfs/boxo v0.15.0 - github.com/ipfs/go-cid v0.4.1 - github.com/ipfs/go-log/v2 v2.5.1 - github.com/multiformats/go-multicodec v0.9.0 + github.com/ipfs/boxo v0.34.0 + github.com/ipfs/go-cid v0.5.0 + github.com/ipfs/go-log/v2 v2.8.1 + github.com/multiformats/go-multibase v0.2.0 + github.com/multiformats/go-multicodec v0.9.2 github.com/multiformats/go-multihash v0.2.3 go.uber.org/multierr v1.11.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // 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-multibase v0.2.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/sys v0.13.0 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/sys v0.35.0 // indirect + lukechampine.com/blake3 v1.4.1 // indirect ) diff --git a/go.sum b/go.sum index 34f7ff8..57a941f 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,15 @@ -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ipfs/boxo v0.15.0 h1:BriLydj2nlK1nKeJQHxcKSuG5ZXcoutzhBklOtxC5pk= -github.com/ipfs/boxo v0.15.0/go.mod h1:X5ulcbR5Nh7sm3Db8+08AApUo6FsGC5mb23QDKAoB/M= -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-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/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/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= +github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= +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-log/v2 v2.8.1 h1:Y/X36z7ASoLJaYIJAL4xITXgwf7RVeqb1+/25aq/Xk0= +github.com/ipfs/go-log/v2 v2.8.1/go.mod h1:NyhTBcZmh2Y55eWVjOeKf8M7e4pnJYM3yDZNxQBWEEY= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= 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/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= @@ -30,71 +22,33 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.2 h1:YrlXCuqxjqm3bXl+vBq5LKz5pz4mvAsugdqy78k0pXQ= +github.com/multiformats/go-multicodec v0.9.2/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= 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-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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= diff --git a/ipfs/blockservice_test.go b/ipfs/blockservice_test.go new file mode 100644 index 0000000..5422b5d --- /dev/null +++ b/ipfs/blockservice_test.go @@ -0,0 +1,267 @@ +package ipfs + +import ( + "context" + "testing" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestBlockService_WrapBlockService(t *testing.T) { + t.Run("wraps with blocker", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1, blockedCID2) + + require.NotNil(t, wrappedService) + assert.NotNil(t, wrappedService.blocker) + assert.NotNil(t, wrappedService.wrappedBlockstore) + assert.NotNil(t, wrappedService.wrappedExchange) + mockBS.AssertExpectations(t) + }) + + t.Run("handles nil blockstore", func(t *testing.T) { + mockBS := NewMockBlockService() + mockBS.On("Blockstore").Return(nil) + mockBS.On("Exchange").Return(NewMockExchange()) + + blocker := createTestBlocker(blockedCID1) + wrapped := WrapBlockService(mockBS, blocker) + + require.NotNil(t, wrapped) + bs := wrapped.(*BlockService) + assert.Nil(t, bs.wrappedBlockstore) + assert.NotNil(t, bs.wrappedExchange) + }) + + t.Run("handles nil exchange", func(t *testing.T) { + mockBS := NewMockBlockService() + mockBS.On("Blockstore").Return(NewMockBlockstore()) + mockBS.On("Exchange").Return(nil) + + blocker := createTestBlocker(blockedCID1) + wrapped := WrapBlockService(mockBS, blocker) + + require.NotNil(t, wrapped) + bs := wrapped.(*BlockService) + assert.NotNil(t, bs.wrappedBlockstore) + assert.Nil(t, bs.wrappedExchange) + }) + + t.Run("handles nil blocker", func(t *testing.T) { + mockBS := NewMockBlockService() + mockBS.On("Blockstore").Return(nil) + mockBS.On("Exchange").Return(nil) + + wrapped := WrapBlockService(mockBS, nil) + + require.NotNil(t, wrapped) + bs := wrapped.(*BlockService) + assert.Nil(t, bs.blocker) + assert.Nil(t, bs.wrappedBlockstore) + assert.Nil(t, bs.wrappedExchange) + }) +} + +func TestBlockService_Close(t *testing.T) { + t.Run("closes both blocker and underlying service", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + mockBS.On("Close").Return(nil) + + err := wrappedService.Close() + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockService_GetBlock(t *testing.T) { + ctx := context.Background() + + t.Run("delegates to wrapped blockservice", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + mockBS.On("GetBlock", ctx, testCID1).Return(testBlock1, nil) + + blk, err := wrappedService.GetBlock(ctx, testCID1) + + require.NoError(t, err) + assert.Equal(t, testBlock1, blk) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockService_GetBlocks(t *testing.T) { + ctx := context.Background() + + t.Run("delegates to wrapped blockservice", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + + blockChan := makeBlockChannel(testBlock1, testBlock2) + cids := []cid.Cid{testCID1, testCID2} + mockBS.On("GetBlocks", ctx, cids).Return(blockChan) + + outChan := wrappedService.GetBlocks(ctx, cids) + results := collectBlocks(outChan) + + assert.Len(t, results, 2) + assert.Contains(t, results, testBlock1) + assert.Contains(t, results, testBlock2) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockService_Blockstore(t *testing.T) { + t.Run("returns wrapped blockstore", func(t *testing.T) { + _, wrappedService := setupBlockedService(t, blockedCID1) + + bs := wrappedService.Blockstore() + + require.NotNil(t, bs) + _, ok := bs.(*BlockedBlockstore) + assert.True(t, ok, "should return BlockedBlockstore") + }) +} + +func TestBlockService_Exchange(t *testing.T) { + t.Run("returns wrapped exchange", func(t *testing.T) { + _, wrappedService := setupBlockedService(t, blockedCID1) + + ex := wrappedService.Exchange() + + require.NotNil(t, ex) + _, ok := ex.(*BlockedExchange) + assert.True(t, ok, "should return BlockedExchange") + }) +} + +func TestBlockService_AddBlock(t *testing.T) { + ctx := context.Background() + + t.Run("allows non-blocked block", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + mockBS.On("AddBlock", ctx, testBlock1).Return(nil) + + err := wrappedService.AddBlock(ctx, testBlock1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) + + t.Run("blocks denied block", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + + err := wrappedService.AddBlock(ctx, blockedBlock1) + + assertBlocked(t, err) + mockBS.AssertNotCalled(t, "AddBlock", mock.Anything, blockedBlock1) + }) + + t.Run("handles nil blocker", func(t *testing.T) { + mockBS := NewMockBlockService() + mockBS.On("Blockstore").Return(NewMockBlockstore()).Maybe() + mockBS.On("Exchange").Return(NewMockExchange()).Maybe() + mockBS.On("AddBlock", ctx, blockedBlock1).Return(nil) + + wrapped := WrapBlockService(mockBS, nil) + + err := wrapped.AddBlock(ctx, blockedBlock1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockService_AddBlocks(t *testing.T) { + ctx := context.Background() + + testCases := []struct { + name string + inputBlocks []blocks.Block + expectedBlocks []blocks.Block + blockedCIDs []cid.Cid + nilBlocker bool + }{ + { + name: "filters out blocked blocks", + inputBlocks: []blocks.Block{testBlock1, blockedBlock1, testBlock2, blockedBlock2}, + expectedBlocks: []blocks.Block{testBlock1, testBlock2}, + blockedCIDs: []cid.Cid{blockedCID1, blockedCID2}, + }, + { + name: "handles all blocked blocks", + inputBlocks: []blocks.Block{blockedBlock1, blockedBlock2}, + expectedBlocks: nil, + blockedCIDs: []cid.Cid{blockedCID1, blockedCID2}, + }, + { + name: "passes all blocks with nil blocker", + inputBlocks: []blocks.Block{testBlock1, blockedBlock1, testBlock2}, + expectedBlocks: []blocks.Block{testBlock1, blockedBlock1, testBlock2}, + nilBlocker: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockBS := NewMockBlockService() + mockBS.On("Blockstore").Return(NewMockBlockstore()).Maybe() + mockBS.On("Exchange").Return(NewMockExchange()).Maybe() + + var wrapped *BlockService + if tc.nilBlocker { + wrapped = WrapBlockService(mockBS, nil).(*BlockService) + } else { + _, wrapped = setupBlockedService(t, tc.blockedCIDs...) + mockBS = wrapped.bs.(*MockBlockService) + } + + // Set expectation based on what should be passed through + mockBS.On("AddBlocks", ctx, mock.MatchedBy(func(bs []blocks.Block) bool { + if tc.expectedBlocks == nil { + return bs == nil || len(bs) == 0 + } + if len(bs) != len(tc.expectedBlocks) { + return false + } + for i, b := range bs { + if b != tc.expectedBlocks[i] { + return false + } + } + return true + })).Return(nil) + + err := wrapped.AddBlocks(ctx, tc.inputBlocks) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) + } +} + +func TestBlockService_DeleteBlock(t *testing.T) { + ctx := context.Background() + + t.Run("delegates deletion for allowed CID", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + mockBS.On("DeleteBlock", ctx, testCID1).Return(nil) + + err := wrappedService.DeleteBlock(ctx, testCID1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) + + t.Run("allows deletion of blocked CID", func(t *testing.T) { + mockBS, wrappedService := setupBlockedService(t, blockedCID1) + mockBS.On("DeleteBlock", ctx, blockedCID1).Return(nil) + + err := wrappedService.DeleteBlock(ctx, blockedCID1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) +} + diff --git a/ipfs/blockstore_test.go b/ipfs/blockstore_test.go new file mode 100644 index 0000000..f739e7b --- /dev/null +++ b/ipfs/blockstore_test.go @@ -0,0 +1,275 @@ +package ipfs + +import ( + "context" + "testing" + "time" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestBlockedBlockstore_Get(t *testing.T) { + ctx := context.Background() + + t.Run("allows non-blocked CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1, blockedCID2) + mockBS.On("Get", ctx, testCID1).Return(testBlock1, nil) + + blk, err := blockedBS.Get(ctx, testCID1) + + require.NoError(t, err) + assert.Equal(t, testBlock1, blk) + mockBS.AssertExpectations(t) + }) + + t.Run("blocks denied CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1, blockedCID2) + + blk, err := blockedBS.Get(ctx, blockedCID1) + + assertBlocked(t, err) + assert.Nil(t, blk) + mockBS.AssertNotCalled(t, "Get", mock.Anything, blockedCID1) + }) + + t.Run("handles nil blocker", func(t *testing.T) { + mockBS := NewMockBlockstore() + blockedBS := &BlockedBlockstore{ + Blockstore: mockBS, + blocker: nil, + } + mockBS.On("Get", ctx, blockedCID1).Return(blockedBlock1, nil) + + blk, err := blockedBS.Get(ctx, blockedCID1) + + require.NoError(t, err) + assert.Equal(t, blockedBlock1, blk) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockedBlockstore_Has(t *testing.T) { + ctx := context.Background() + + t.Run("returns false for blocked CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + + has, err := blockedBS.Has(ctx, blockedCID1) + + require.NoError(t, err) + assert.False(t, has) + mockBS.AssertNotCalled(t, "Has", mock.Anything, blockedCID1) + }) + + t.Run("checks underlying store for allowed CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + mockBS.On("Has", ctx, testCID1).Return(true, nil) + + has, err := blockedBS.Has(ctx, testCID1) + + require.NoError(t, err) + assert.True(t, has) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockedBlockstore_Put(t *testing.T) { + ctx := context.Background() + + t.Run("rejects blocked block", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + + err := blockedBS.Put(ctx, blockedBlock1) + + assertBlocked(t, err) + mockBS.AssertNotCalled(t, "Put", mock.Anything, blockedBlock1) + }) + + t.Run("allows non-blocked block", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + mockBS.On("Put", ctx, testBlock1).Return(nil) + + err := blockedBS.Put(ctx, testBlock1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockedBlockstore_PutMany(t *testing.T) { + ctx := context.Background() + + t.Run("filters out blocked blocks", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + expectedBlocks := []blocks.Block{testBlock1, testBlock2} + mockBS.On("PutMany", ctx, expectedBlocks).Return(nil) + + inputBlocks := []blocks.Block{testBlock1, blockedBlock1, testBlock2} + err := blockedBS.PutMany(ctx, inputBlocks) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) + + t.Run("returns nil for all blocked blocks", func(t *testing.T) { + _, blockedBS := setupBlockedBlockstore(t, blockedCID1, blockedCID2) + + inputBlocks := []blocks.Block{blockedBlock1, blockedBlock2} + err := blockedBS.PutMany(ctx, inputBlocks) + + require.NoError(t, err) + }) +} + +func TestBlockedBlockstore_AllKeysChan(t *testing.T) { + ctx := context.Background() + + t.Run("filters blocked CIDs from channel", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + + // Create input channel with mix of CIDs + inChan := make(chan cid.Cid, 3) + inChan <- testCID1 + inChan <- blockedCID1 // Should be filtered + inChan <- testCID2 + close(inChan) + + mockBS.On("AllKeysChan", ctx).Return((<-chan cid.Cid)(inChan), nil) + + outChan, err := blockedBS.AllKeysChan(ctx) + require.NoError(t, err) + + // Collect results + var results []cid.Cid + for c := range outChan { + results = append(results, c) + } + + assert.Len(t, results, 2) + assert.Contains(t, results, testCID1) + assert.Contains(t, results, testCID2) + assert.NotContains(t, results, blockedCID1) + }) + + t.Run("handles context cancellation", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t) + + // Create input channel that blocks + inChan := make(chan cid.Cid) + mockBS.On("AllKeysChan", mock.Anything).Return((<-chan cid.Cid)(inChan), nil) + + // Test with cancellable context + cancelCtx, cancel := context.WithCancel(ctx) + outChan, err := blockedBS.AllKeysChan(cancelCtx) + require.NoError(t, err) + + // Start reading in goroutine + done := make(chan bool) + go func() { + for range outChan { + // Drain channel + } + done <- true + }() + + // Cancel context + cancel() + + // Verify goroutine exits + select { + case <-done: + // Good - goroutine exited + case <-time.After(100 * time.Millisecond): + t.Fatal("goroutine did not exit after context cancellation") + } + + close(inChan) + }) + + t.Run("handles nil blocker", func(t *testing.T) { + mockBS := NewMockBlockstore() + blockedBS := &BlockedBlockstore{ + Blockstore: mockBS, + blocker: nil, + } + + // Create input channel + inChan := make(chan cid.Cid, 2) + inChan <- blockedCID1 + inChan <- testCID1 + close(inChan) + + mockBS.On("AllKeysChan", ctx).Return((<-chan cid.Cid)(inChan), nil) + + outChan, err := blockedBS.AllKeysChan(ctx) + require.NoError(t, err) + + // With nil blocker, should return input channel directly + assert.Equal(t, (<-chan cid.Cid)(inChan), outChan) + }) +} + +func TestBlockedBlockstore_GetSize(t *testing.T) { + ctx := context.Background() + + t.Run("returns error for blocked CID", func(t *testing.T) { + _, blockedBS := setupBlockedBlockstore(t, blockedCID1) + + size, err := blockedBS.GetSize(ctx, blockedCID1) + + assertBlocked(t, err) + assert.Equal(t, 0, size) + }) + + t.Run("returns size for allowed CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + expectedSize := 42 + mockBS.On("GetSize", ctx, testCID1).Return(expectedSize, nil) + + size, err := blockedBS.GetSize(ctx, testCID1) + + require.NoError(t, err) + assert.Equal(t, expectedSize, size) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockedBlockstore_DeleteBlock(t *testing.T) { + ctx := context.Background() + + t.Run("allows deletion of blocked CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + mockBS.On("DeleteBlock", ctx, blockedCID1).Return(nil) + + err := blockedBS.DeleteBlock(ctx, blockedCID1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) + + t.Run("allows deletion of non-blocked CID", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t, blockedCID1) + mockBS.On("DeleteBlock", ctx, testCID1).Return(nil) + + err := blockedBS.DeleteBlock(ctx, testCID1) + + require.NoError(t, err) + mockBS.AssertExpectations(t) + }) +} + +func TestBlockedBlockstore_HashOnRead(t *testing.T) { + t.Run("delegates to underlying blockstore", func(t *testing.T) { + mockBS, blockedBS := setupBlockedBlockstore(t) + mockBS.On("HashOnRead", true).Return() + + blockedBS.HashOnRead(true) + + mockBS.AssertExpectations(t) + }) +} + diff --git a/ipfs/exchange_test.go b/ipfs/exchange_test.go new file mode 100644 index 0000000..7f76586 --- /dev/null +++ b/ipfs/exchange_test.go @@ -0,0 +1,282 @@ +package ipfs + +import ( + "context" + "testing" + "time" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestBlockedExchange_GetBlock(t *testing.T) { + ctx := context.Background() + + t.Run("allows non-blocked CID", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1, blockedCID2) + mockEx.On("GetBlock", ctx, testCID1).Return(testBlock1, nil) + + blk, err := blockedEx.GetBlock(ctx, testCID1) + + require.NoError(t, err) + assert.Equal(t, testBlock1, blk) + mockEx.AssertExpectations(t) + }) + + t.Run("blocks denied CID", func(t *testing.T) { + _, blockedEx := setupBlockedExchange(t, blockedCID1, blockedCID2) + + blk, err := blockedEx.GetBlock(ctx, blockedCID1) + + assertBlocked(t, err) + assert.Nil(t, blk) + }) + + t.Run("handles nil blocker", func(t *testing.T) { + mockEx := NewMockExchange() + blockedEx := &BlockedExchange{ + Interface: mockEx, + blocker: nil, + } + mockEx.On("GetBlock", ctx, blockedCID1).Return(blockedBlock1, nil) + + blk, err := blockedEx.GetBlock(ctx, blockedCID1) + + require.NoError(t, err) + assert.Equal(t, blockedBlock1, blk) + mockEx.AssertExpectations(t) + }) +} + +func TestBlockedExchange_GetBlocks(t *testing.T) { + ctx := context.Background() + + t.Run("filters blocked CIDs from request and response", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1, blockedCID2) + + // Create channel with mixed blocks + blockChan := makeBlockChannel(testBlock1, blockedBlock1, testBlock2) + + // Only non-blocked CIDs should be requested + requestedCIDs := []cid.Cid{testCID1, testCID2} + mockEx.On("GetBlocks", ctx, requestedCIDs).Return(blockChan, nil) + + // Test with mix of blocked and allowed CIDs + cids := []cid.Cid{testCID1, blockedCID1, testCID2} + outChan, err := blockedEx.GetBlocks(ctx, cids) + + require.NoError(t, err) + results := collectBlocks(outChan) + + // Verify - blocked block should be filtered out + assert.Len(t, results, 2) + assert.Contains(t, results, testBlock1) + assert.Contains(t, results, testBlock2) + mockEx.AssertExpectations(t) + }) + + t.Run("returns empty channel for all blocked CIDs", func(t *testing.T) { + _, blockedEx := setupBlockedExchange(t, blockedCID1, blockedCID2) + + cids := []cid.Cid{blockedCID1, blockedCID2} + outChan, err := blockedEx.GetBlocks(ctx, cids) + + require.NoError(t, err) + + // Channel should be closed immediately + select { + case _, ok := <-outChan: + assert.False(t, ok, "channel should be closed") + case <-time.After(100 * time.Millisecond): + t.Fatal("channel not closed") + } + }) + + t.Run("handles context cancellation", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1) + + // Create blocking channel + blockChan := make(chan blocks.Block) + defer close(blockChan) + + mockEx.On("GetBlocks", mock.Anything, []cid.Cid{testCID1}).Return((<-chan blocks.Block)(blockChan), nil) + + // Test with cancellable context + cancelCtx, cancel := context.WithCancel(ctx) + outChan, err := blockedEx.GetBlocks(cancelCtx, []cid.Cid{testCID1}) + require.NoError(t, err) + + // Start reading in goroutine + done := make(chan bool) + go func() { + for range outChan { + // Drain channel + } + done <- true + }() + + // Cancel context + cancel() + + // Verify goroutine exits + select { + case <-done: + // Good - goroutine exited + case <-time.After(100 * time.Millisecond): + t.Fatal("goroutine did not exit after context cancellation") + } + }) +} + +func TestBlockedExchange_NotifyNewBlocks(t *testing.T) { + ctx := context.Background() + + t.Run("passes through all blocks including blocked", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1) + + testBlocks := []blocks.Block{testBlock1, blockedBlock1} + mockEx.On("NotifyNewBlocks", ctx, testBlocks).Return(nil) + + err := blockedEx.NotifyNewBlocks(ctx, testBlocks...) + + require.NoError(t, err) + mockEx.AssertExpectations(t) + }) +} + +func TestBlockedExchange_Close(t *testing.T) { + t.Run("delegates to underlying exchange", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1) + mockEx.On("Close").Return(nil) + + err := blockedEx.Close() + + require.NoError(t, err) + mockEx.AssertExpectations(t) + }) +} + +func TestBlockedExchange_NewSession(t *testing.T) { + ctx := context.Background() + + t.Run("wraps session when exchange supports sessions", func(t *testing.T) { + blocker := createTestBlocker(blockedCID1) + mockSessEx := NewMockSessionExchange() + mockFetcher := NewMockFetcher() + + blockedEx := &BlockedExchange{ + Interface: mockSessEx, + blocker: blocker, + } + + mockSessEx.On("NewSession", ctx).Return(mockFetcher) + + fetcher := blockedEx.NewSession(ctx) + + require.NotNil(t, fetcher) + blockedFetcher, ok := fetcher.(*BlockedFetcher) + require.True(t, ok) + assert.Equal(t, mockFetcher, blockedFetcher.Fetcher) + assert.Equal(t, blocker, blockedFetcher.blocker) + mockSessEx.AssertExpectations(t) + }) + + t.Run("returns self when exchange doesn't support sessions", func(t *testing.T) { + mockEx, blockedEx := setupBlockedExchange(t, blockedCID1) + + fetcher := blockedEx.NewSession(ctx) + + require.NotNil(t, fetcher) + assert.Equal(t, blockedEx, fetcher) + mockEx.AssertExpectations(t) + }) + + t.Run("returns unwrapped fetcher with nil blocker", func(t *testing.T) { + mockSessEx := NewMockSessionExchange() + mockFetcher := NewMockFetcher() + + blockedEx := &BlockedExchange{ + Interface: mockSessEx, + blocker: nil, + } + + mockSessEx.On("NewSession", ctx).Return(mockFetcher) + + fetcher := blockedEx.NewSession(ctx) + + require.NotNil(t, fetcher) + assert.Equal(t, mockFetcher, fetcher) + mockSessEx.AssertExpectations(t) + }) +} + +func TestBlockedFetcher_GetBlock(t *testing.T) { + ctx := context.Background() + + t.Run("allows non-blocked CID", func(t *testing.T) { + blocker := createTestBlocker(blockedCID1, blockedCID2) + mockFetcher := NewMockFetcher() + blockedFetch := &BlockedFetcher{ + Fetcher: mockFetcher, + blocker: blocker, + } + + mockFetcher.On("GetBlock", ctx, testCID1).Return(testBlock1, nil) + + blk, err := blockedFetch.GetBlock(ctx, testCID1) + + require.NoError(t, err) + assert.Equal(t, testBlock1, blk) + mockFetcher.AssertExpectations(t) + }) + + t.Run("blocks denied CID", func(t *testing.T) { + blocker := createTestBlocker(blockedCID1) + mockFetcher := NewMockFetcher() + blockedFetch := &BlockedFetcher{ + Fetcher: mockFetcher, + blocker: blocker, + } + + blk, err := blockedFetch.GetBlock(ctx, blockedCID1) + + assertBlocked(t, err) + assert.Nil(t, blk) + mockFetcher.AssertNotCalled(t, "GetBlock", mock.Anything, blockedCID1) + }) +} + +func TestBlockedFetcher_GetBlocks(t *testing.T) { + ctx := context.Background() + + t.Run("filters blocked CIDs", func(t *testing.T) { + blocker := createTestBlocker(blockedCID1) + mockFetcher := NewMockFetcher() + blockedFetch := &BlockedFetcher{ + Fetcher: mockFetcher, + blocker: blocker, + } + + // Create channel with test blocks + blockChan := makeBlockChannel(testBlock1, testBlock2) + + // Only non-blocked CIDs should be requested + requestedCIDs := []cid.Cid{testCID1, testCID2} + mockFetcher.On("GetBlocks", ctx, requestedCIDs).Return(blockChan, nil) + + // Test with mix of blocked and allowed CIDs + cids := []cid.Cid{testCID1, blockedCID1, testCID2} + outChan, err := blockedFetch.GetBlocks(ctx, cids) + + require.NoError(t, err) + results := collectBlocks(outChan) + + assert.Len(t, results, 2) + assert.Contains(t, results, testBlock1) + assert.Contains(t, results, testBlock2) + mockFetcher.AssertExpectations(t) + }) +} diff --git a/ipfs/go.mod b/ipfs/go.mod index 95be096..8935392 100644 --- a/ipfs/go.mod +++ b/ipfs/go.mod @@ -1,88 +1,84 @@ module github.com/ipfs-shipyard/nopfs/ipfs -go 1.22.0 - -toolchain go1.23.3 +go 1.24.0 require ( github.com/ipfs-shipyard/nopfs v0.0.13 - github.com/ipfs/boxo v0.25.0 - github.com/ipfs/go-block-format v0.2.0 - github.com/ipfs/go-cid v0.4.1 - github.com/ipfs/go-log/v2 v2.5.1 + github.com/ipfs/boxo v0.34.0 + github.com/ipfs/go-block-format v0.2.2 + github.com/ipfs/go-cid v0.5.0 + github.com/ipfs/go-log/v2 v2.8.1 github.com/ipld/go-ipld-prime v0.21.0 - github.com/libp2p/go-libp2p v0.37.2 + github.com/libp2p/go-libp2p v0.43.0 + github.com/multiformats/go-multihash v0.2.3 + github.com/stretchr/testify v1.10.0 ) require ( + github.com/Jorropo/jsync v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/go-datastore v0.6.0 // indirect - github.com/ipfs/go-ipfs-util v0.0.3 // indirect - github.com/ipfs/go-ipld-format v0.6.0 // indirect - github.com/ipfs/go-metrics-interface v0.0.1 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/ipfs/go-datastore v0.8.3 // indirect + github.com/ipfs/go-ipld-format v0.6.2 // indirect + github.com/ipfs/go-metrics-interface v0.3.0 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.27.0 // indirect - github.com/libp2p/go-libp2p-kbucket v0.6.4 // indirect - github.com/libp2p/go-libp2p-record v0.2.0 // indirect - github.com/libp2p/go-libp2p-routing-helpers v0.7.4 // indirect + github.com/libp2p/go-libp2p-kad-dht v0.34.0 // indirect + github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect + github.com/libp2p/go-libp2p-record v0.3.1 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.68 // 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.13.0 // indirect + github.com/multiformats/go-multiaddr v0.16.1 // indirect github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect - github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.6.0 // indirect + github.com/multiformats/go-multicodec v0.9.2 // indirect + github.com/multiformats/go-multistream v0.6.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.60.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/samber/lo v1.47.0 // indirect + github.com/prometheus/client_golang v1.23.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.31.0 // indirect - go.opentelemetry.io/otel/metric v1.31.0 // indirect - go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - golang.org/x/tools v0.26.0 // indirect - gonum.org/v1/gonum v0.15.0 // indirect - google.golang.org/protobuf v1.35.1 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect + golang.org/x/mod v0.27.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/tools v0.36.0 // indirect + gonum.org/v1/gonum v0.16.0 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.3.0 // indirect + lukechampine.com/blake3 v1.4.1 // indirect ) diff --git a/ipfs/go.sum b/ipfs/go.sum index b16ee57..e129a98 100644 --- a/ipfs/go.sum +++ b/ipfs/go.sum @@ -1,19 +1,12 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU= +github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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/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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/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/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= @@ -22,18 +15,12 @@ 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/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/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -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/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= -github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -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= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= +github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs= 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= @@ -42,48 +29,20 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gammazero/chanqueue v1.0.0 h1:FER/sMailGFA3DDvFooEkipAMU+3c9Bg3bheloPSz6o= -github.com/gammazero/chanqueue v1.0.0/go.mod h1:fMwpwEiuUgpab0sH4VHiVcEoji1pSi+EIzeG4TPeKPc= -github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= -github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= +github.com/gammazero/chanqueue v1.1.1 h1:n9Y+zbBxw2f7uUE9wpgs0rOSkP/I/yhDLiNuhyVjojQ= +github.com/gammazero/chanqueue v1.1.1/go.mod h1:fMwpwEiuUgpab0sH4VHiVcEoji1pSi+EIzeG4TPeKPc= +github.com/gammazero/deque v1.1.0 h1:OyiyReBbnEG2PP0Bnv1AASLIYvyKqIFN5xfl1t8oGLo= +github.com/gammazero/deque v1.1.0/go.mod h1:JVrR+Bj1NMQbPnYclvDlvSX0nVGReLrQZ0aUMuWLctg= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -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/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/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/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -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-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/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/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/uuid v1.1.2/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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -91,11 +50,6 @@ github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRid github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -106,103 +60,90 @@ github.com/ipfs-shipyard/nopfs v0.0.13 h1:eXyI5x0+Y/dgjHl3RgSrVqg+1YwwybhEuRgo3B github.com/ipfs-shipyard/nopfs v0.0.13/go.mod h1:mQyd0BElYI2gB/kq/Oue97obP4B3os4eBmgfPZ+hnrE= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.25.0 h1:FNZaKVirUDafGz3Y9sccztynAUazs9GfSapLk/5c7is= -github.com/ipfs/boxo v0.25.0/go.mod h1:MQVkL3V8RfuIsn+aajCR0MXLl8nRlz+5uGlHMWFVyuE= +github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= +github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= -github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= -github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= -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-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-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= +github.com/ipfs/go-block-format v0.2.2/go.mod h1:vmuefuWU6b+9kIU0vZJgpiJt1yicQz9baHXE8qR+KB8= +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.8.3 h1:z391GsQyGKUIUof2tPoaZVeDknbt7fNHs6Gqjcw5Jo4= +github.com/ipfs/go-datastore v0.8.3/go.mod h1:raxQ/CreIy9L6MxT71ItfMX12/ASN6EhXJoUFjICQ2M= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4= -github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= -github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= -github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= -github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= -github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= -github.com/ipfs/go-ipld-legacy v0.2.1/go.mod h1:782MOUghNzMO2DER0FlBR94mllfdCJCkTtDtPM51otM= -github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= -github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= -github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= -github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU= -github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew= -github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI= -github.com/ipfs/go-unixfsnode v1.9.2 h1:0A12BYs4XOtDPJTMlwmNPlllDfqcc4yie4e919hcUXk= -github.com/ipfs/go-unixfsnode v1.9.2/go.mod h1:v1nuMFHf4QTIhFUdPMvg1nQu7AqDLvIdwyvJ531Ot1U= -github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= -github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s= +github.com/ipfs/go-ipld-format v0.6.2 h1:bPZQ+A05ol0b3lsJSl0bLvwbuQ+HQbSsdGTy4xtYUkU= +github.com/ipfs/go-ipld-format v0.6.2/go.mod h1:nni2xFdHKx5lxvXJ6brt/pndtGxKAE+FPR1rg4jTkyk= +github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ= +github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU= +github.com/ipfs/go-log/v2 v2.8.1 h1:Y/X36z7ASoLJaYIJAL4xITXgwf7RVeqb1+/25aq/Xk0= +github.com/ipfs/go-log/v2 v2.8.1/go.mod h1:NyhTBcZmh2Y55eWVjOeKf8M7e4pnJYM3yDZNxQBWEEY= +github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= +github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= +github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU= +github.com/ipfs/go-peertaskqueue v0.8.2/go.mod h1:L6QPvou0346c2qPJNiJa6BvOibxDfaiPlqHInmzg0FA= +github.com/ipfs/go-test v0.2.2 h1:1yjYyfbdt1w93lVzde6JZ2einh3DIV40at4rVoyEcE8= +github.com/ipfs/go-test v0.2.2/go.mod h1:cmLisgVwkdRCnKu/CFZOk2DdhOcwghr5GsHeqwexoRA= +github.com/ipfs/go-unixfsnode v1.10.1 h1:hGKhzuH6NSzZ4y621wGuDspkjXRNG3B+HqhlyTjSwSM= +github.com/ipfs/go-unixfsnode v1.10.1/go.mod h1:eguv/otvacjmfSbYvmamc9ssNAzLvRk0+YN30EYeOOY= +github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0= +github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM= github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= 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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 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/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -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/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= +github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= 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/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= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= 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-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= -github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= -github.com/libp2p/go-libp2p v0.37.2 h1:Irh+n9aDPTLt9wJYwtlHu6AhMUipbC1cGoJtOiBqI9c= -github.com/libp2p/go-libp2p v0.37.2/go.mod h1:M8CRRywYkqC6xKHdZ45hmqVckBj5z4mRLIMLWReypz8= +github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784= +github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo= +github.com/libp2p/go-libp2p v0.43.0 h1:b2bg2cRNmY4HpLK8VHYQXLX2d3iND95OjodLFymvqXU= +github.com/libp2p/go-libp2p v0.43.0/go.mod h1:IiSqAXDyP2sWH+J2gs43pNmB/y4FOi2XQPbsb+8qvzc= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= -github.com/libp2p/go-libp2p-kad-dht v0.27.0 h1:1Ea32tVTPiAfaLpPMbaBWFJgbsi/JpMqC2YBuFdf32o= -github.com/libp2p/go-libp2p-kad-dht v0.27.0/go.mod h1:ixhjLuzaXSGtWsKsXTj7erySNuVC4UP7NO015cRrF14= -github.com/libp2p/go-libp2p-kbucket v0.6.4 h1:OjfiYxU42TKQSB8t8WYd8MKhYhMJeO2If+NiuKfb6iQ= -github.com/libp2p/go-libp2p-kbucket v0.6.4/go.mod h1:jp6w82sczYaBsAypt5ayACcRJi0lgsba7o4TzJKEfWA= -github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= -github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= -github.com/libp2p/go-libp2p-routing-helpers v0.7.4 h1:6LqS1Bzn5CfDJ4tzvP9uwh42IB7TJLNFJA6dEeGBv84= -github.com/libp2p/go-libp2p-routing-helpers v0.7.4/go.mod h1:we5WDj9tbolBXOuF1hGOkR+r7Uh1408tQbAKaT5n1LE= +github.com/libp2p/go-libp2p-kad-dht v0.34.0 h1:yvJ/Vrt36GVjsqPxiGcuuwOloKuZLV9Aa7awIKyNXy0= +github.com/libp2p/go-libp2p-kad-dht v0.34.0/go.mod h1:JNbkES4W5tajS6uYivw6MPs0842cPHAwhgaPw8sQG4o= +github.com/libp2p/go-libp2p-kbucket v0.7.0 h1:vYDvRjkyJPeWunQXqcW2Z6E93Ywx7fX0jgzb/dGOKCs= +github.com/libp2p/go-libp2p-kbucket v0.7.0/go.mod h1:blOINGIj1yiPYlVEX0Rj9QwEkmVnz3EP8LK1dRKBC6g= +github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= +github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5 h1:HdwZj9NKovMx0vqq6YNPTh6aaNzey5zHD7HeLJtq6fI= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5/go.mod h1:3YaxrwP0OBPDD7my3D0KxfR89FlcX/IEbxDEDfAmj98= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= -github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-yamux/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg= +github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -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/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= +github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= @@ -215,91 +156,85 @@ 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.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= -github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw= +github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= 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= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.2 h1:YrlXCuqxjqm3bXl+vBq5LKz5pz4mvAsugdqy78k0pXQ= +github.com/multiformats/go-multicodec v0.9.2/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= 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.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= -github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= +github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= 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/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +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.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.36 h1:SopeXiVbbcooUg2EIR8sq4b13RQ8gzrkkldOVg+bBsc= -github.com/pion/ice/v2 v2.3.36/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= -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 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -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/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= +github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= +github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= +github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +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/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.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= -github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= -github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +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.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c= +github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= +github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4= +github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4= +github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= 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.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.3.4 h1:v2heQVnXTSqNRXcaFQVOhIOYkLMxOu1iJG8uy1djvkk= -github.com/pion/webrtc/v3 v3.3.4/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= -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= +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/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps= +github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= +github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= +github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -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.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= 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.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= -github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= -github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= -github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= -github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= -github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= +github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= -github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= @@ -308,16 +243,11 @@ github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= @@ -329,144 +259,71 @@ github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdz github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= 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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= -go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= -go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= +go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= 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.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -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= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= -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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -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/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= 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= -gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= -gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= -lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= diff --git a/ipfs/test_helpers.go b/ipfs/test_helpers.go new file mode 100644 index 0000000..2ce38b8 --- /dev/null +++ b/ipfs/test_helpers.go @@ -0,0 +1,362 @@ +package ipfs + +import ( + "context" + "errors" + "sync" + "testing" + + "github.com/ipfs-shipyard/nopfs" + "github.com/ipfs/boxo/blockstore" + "github.com/ipfs/boxo/exchange" + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +// Test CIDs and blocks for testing +var ( + // Test CIDs + testCID1 = mustParseCID("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi") + testCID2 = mustParseCID("bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4") + blockedCID1 = mustParseCID("bafkreihubvg2gobtafahmkqrrcqsernhdprw2pumiana3ombkhckfl5ztq") + blockedCID2 = mustParseCID("bafybeihsf4562gmmyoya2eh4fimpgzpjkh5jistrscvcfpxuznbknufwtq") + + // Test blocks + testBlock1 = mustCreateBlock(testCID1, []byte("test content 1")) + testBlock2 = mustCreateBlock(testCID2, []byte("test content 2")) + blockedBlock1 = mustCreateBlock(blockedCID1, []byte("blocked content 1")) + blockedBlock2 = mustCreateBlock(blockedCID2, []byte("blocked content 2")) +) + +func mustParseCID(cidStr string) cid.Cid { + c, err := cid.Parse(cidStr) + if err != nil { + panic(err) + } + return c +} + +func mustCreateBlock(c cid.Cid, data []byte) blocks.Block { + // Create a basic block with the given CID and data + // Note: In real scenarios, the CID should match the hash of the data + blk, err := blocks.NewBlockWithCid(data, c) + if err != nil { + panic(err) + } + return blk +} + +// createTestBlock creates a proper block where CID matches the data hash +func createTestBlock(data []byte) (blocks.Block, error) { + mh, err := multihash.Sum(data, multihash.SHA2_256, -1) + if err != nil { + return nil, err + } + c := cid.NewCidV1(cid.Raw, mh) + return blocks.NewBlockWithCid(data, c) +} + +// createTestBlocker creates a test Blocker with predefined blocked CIDs +func createTestBlocker(blockedCIDs ...cid.Cid) *nopfs.Blocker { + blocker := &nopfs.Blocker{ + Denylists: make(map[string]*nopfs.Denylist), + } + + // Create a simple denylist with the blocked CIDs + dl := &nopfs.Denylist{ + Entries: make(nopfs.Entries, 0, len(blockedCIDs)), + IPFSBlocksDB: &nopfs.BlocksDB{}, + DoubleHashBlocksDB: make(map[uint64]*nopfs.BlocksDB), + } + + for i, c := range blockedCIDs { + mh := c.Hash() + entry := nopfs.Entry{ + Line: uint64(i + 1), + Multihash: mh, + } + dl.Entries = append(dl.Entries, entry) + // Also store in the BlocksDB for efficient lookup + dl.IPFSBlocksDB.Store(mh.B58String(), entry) + + // Initialize double hash blocks DB for this multihash code if needed + mhCode := uint64(mh[0]) + if _, ok := dl.DoubleHashBlocksDB[mhCode]; !ok { + dl.DoubleHashBlocksDB[mhCode] = &nopfs.BlocksDB{} + } + } + + blocker.Denylists["test"] = dl + return blocker +} + +// MockBlockstore is a mock implementation of blockstore.Blockstore +type MockBlockstore struct { + mock.Mock + blocks map[string]blocks.Block + mu sync.RWMutex +} + +func NewMockBlockstore() *MockBlockstore { + return &MockBlockstore{ + blocks: make(map[string]blocks.Block), + } +} + +func (m *MockBlockstore) Get(ctx context.Context, c cid.Cid) (blocks.Block, error) { + args := m.Called(ctx, c) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(blocks.Block), args.Error(1) +} + +func (m *MockBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) { + args := m.Called(ctx, c) + return args.Int(0), args.Error(1) +} + +func (m *MockBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) { + args := m.Called(ctx, c) + return args.Bool(0), args.Error(1) +} + +func (m *MockBlockstore) Put(ctx context.Context, b blocks.Block) error { + args := m.Called(ctx, b) + return args.Error(0) +} + +func (m *MockBlockstore) PutMany(ctx context.Context, bs []blocks.Block) error { + args := m.Called(ctx, bs) + return args.Error(0) +} + +func (m *MockBlockstore) DeleteBlock(ctx context.Context, c cid.Cid) error { + args := m.Called(ctx, c) + return args.Error(0) +} + +func (m *MockBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + args := m.Called(ctx) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(<-chan cid.Cid), args.Error(1) +} + +func (m *MockBlockstore) HashOnRead(enabled bool) { + m.Called(enabled) +} + +// MockExchange is a mock implementation of exchange.Interface +type MockExchange struct { + mock.Mock +} + +func NewMockExchange() *MockExchange { + return &MockExchange{} +} + +func (m *MockExchange) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + args := m.Called(ctx, c) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(blocks.Block), args.Error(1) +} + +func (m *MockExchange) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + args := m.Called(ctx, ks) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(<-chan blocks.Block), args.Error(1) +} + +func (m *MockExchange) NotifyNewBlocks(ctx context.Context, bs ...blocks.Block) error { + args := m.Called(ctx, bs) + return args.Error(0) +} + +func (m *MockExchange) Close() error { + args := m.Called() + return args.Error(0) +} + +// MockSessionExchange is a mock that also implements SessionExchange +type MockSessionExchange struct { + MockExchange +} + +func NewMockSessionExchange() *MockSessionExchange { + return &MockSessionExchange{} +} + +func (m *MockSessionExchange) NewSession(ctx context.Context) exchange.Fetcher { + args := m.Called(ctx) + if args.Get(0) == nil { + return nil + } + return args.Get(0).(exchange.Fetcher) +} + +// MockFetcher is a mock implementation of exchange.Fetcher +type MockFetcher struct { + mock.Mock +} + +func NewMockFetcher() *MockFetcher { + return &MockFetcher{} +} + +func (m *MockFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + args := m.Called(ctx, c) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(blocks.Block), args.Error(1) +} + +func (m *MockFetcher) GetBlocks(ctx context.Context, ks []cid.Cid) (<-chan blocks.Block, error) { + args := m.Called(ctx, ks) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(<-chan blocks.Block), args.Error(1) +} + +// MockBlockService is a mock implementation of blockservice.BlockService +type MockBlockService struct { + mock.Mock + mockBlockstore *MockBlockstore + mockExchange *MockExchange +} + +func NewMockBlockService() *MockBlockService { + return &MockBlockService{ + mockBlockstore: NewMockBlockstore(), + mockExchange: NewMockExchange(), + } +} + +func (m *MockBlockService) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + args := m.Called(ctx, c) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(blocks.Block), args.Error(1) +} + +func (m *MockBlockService) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { + args := m.Called(ctx, ks) + if args.Get(0) == nil { + return nil + } + return args.Get(0).(<-chan blocks.Block) +} + +func (m *MockBlockService) Blockstore() blockstore.Blockstore { + args := m.Called() + if args.Get(0) == nil { + return nil + } + return args.Get(0).(blockstore.Blockstore) +} + +func (m *MockBlockService) Exchange() exchange.Interface { + args := m.Called() + if args.Get(0) == nil { + return nil + } + return args.Get(0).(exchange.Interface) +} + +func (m *MockBlockService) AddBlock(ctx context.Context, b blocks.Block) error { + args := m.Called(ctx, b) + return args.Error(0) +} + +func (m *MockBlockService) AddBlocks(ctx context.Context, bs []blocks.Block) error { + args := m.Called(ctx, bs) + return args.Error(0) +} + +func (m *MockBlockService) DeleteBlock(ctx context.Context, c cid.Cid) error { + args := m.Called(ctx, c) + return args.Error(0) +} + +func (m *MockBlockService) Close() error { + args := m.Called() + return args.Error(0) +} + +// Helper error for testing +var ErrTestNotFound = errors.New("block not found") + +// Test setup helpers + +// setupBlockedBlockstore creates a BlockedBlockstore with mock and blocker configured +func setupBlockedBlockstore(t *testing.T, blockedCIDs ...cid.Cid) (*MockBlockstore, *BlockedBlockstore) { + mockBS := NewMockBlockstore() + blocker := createTestBlocker(blockedCIDs...) + blockedBS := &BlockedBlockstore{ + Blockstore: mockBS, + blocker: blocker, + } + return mockBS, blockedBS +} + +// setupBlockedExchange creates a BlockedExchange with mock and blocker configured +func setupBlockedExchange(t *testing.T, blockedCIDs ...cid.Cid) (*MockExchange, *BlockedExchange) { + mockEx := NewMockExchange() + blocker := createTestBlocker(blockedCIDs...) + blockedEx := &BlockedExchange{ + Interface: mockEx, + blocker: blocker, + } + return mockEx, blockedEx +} + +// setupBlockedService creates a BlockService with mock and blocker configured +func setupBlockedService(t *testing.T, blockedCIDs ...cid.Cid) (*MockBlockService, *BlockService) { + mockBS := NewMockBlockService() + blocker := createTestBlocker(blockedCIDs...) + + // Setup default mock expectations for Blockstore and Exchange + mockBS.On("Blockstore").Return(mockBS.mockBlockstore).Maybe() + mockBS.On("Exchange").Return(mockBS.mockExchange).Maybe() + + wrapped := WrapBlockService(mockBS, blocker) + return mockBS, wrapped.(*BlockService) +} + +// assertBlocked checks that an error indicates blocked content +func assertBlocked(t *testing.T, err error) { + t.Helper() + require.Error(t, err, "expected blocked error") + assert.Contains(t, err.Error(), "blocked", "error should indicate content is blocked") +} + +// collectBlocks collects all blocks from a channel into a slice +func collectBlocks(ch <-chan blocks.Block) []blocks.Block { + var results []blocks.Block + for blk := range ch { + results = append(results, blk) + } + return results +} + +// makeBlockChannel creates a channel with the given blocks and closes it +func makeBlockChannel(blks ...blocks.Block) <-chan blocks.Block { + ch := make(chan blocks.Block, len(blks)) + for _, blk := range blks { + ch <- blk + } + close(ch) + return ch +} From 9275aff97bae84a7036914695ab0ca4670dfa0a5 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 1 Sep 2025 04:12:05 +0200 Subject: [PATCH 4/5] chore: deprecate nopfs-kubo-plugin plugin is now built into kubo v0.24.0+ --- .github/workflows/{release.yml => legacy-plugin.yml} | 9 +++++++-- nopfs-kubo-plugin/README.md | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) rename .github/workflows/{release.yml => legacy-plugin.yml} (90%) diff --git a/.github/workflows/release.yml b/.github/workflows/legacy-plugin.yml similarity index 90% rename from .github/workflows/release.yml rename to .github/workflows/legacy-plugin.yml index 6612873..79eb611 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/legacy-plugin.yml @@ -1,7 +1,12 @@ -name: Kubo plugin +# This workflow builds the legacy nopfs-kubo-plugin which is now deprecated. +# Content blocking (nopfs) is built into Kubo v0.24.0 and later. +# - See the built-in plugin at https://github.com/ipfs/kubo/tree/master/plugin/plugins/nopfs +# - See the documentation at https://github.com/ipfs/kubo/blob/master/docs/content-blocking.md + +name: Legacy Kubo plugin on: - push: + workflow_dispatch: # Manual trigger only - plugin is deprecated env: diff --git a/nopfs-kubo-plugin/README.md b/nopfs-kubo-plugin/README.md index c31f5d0..454486b 100644 --- a/nopfs-kubo-plugin/README.md +++ b/nopfs-kubo-plugin/README.md @@ -1,5 +1,10 @@ # nopfs-kubo-plugin +> [!WARNING] +> This plugin is deprecated. Content blocking (nopfs) is now built into Kubo v0.24.0 and later. +> - See the built-in plugin at https://github.com/ipfs/kubo/tree/master/plugin/plugins/nopfs +> - See the documentation at https://github.com/ipfs/kubo/blob/master/docs/content-blocking.md + ## Installation 1. Copy the binary `nopfs-kubo-plugin` to `~/.ipfs/plugins`. From 16ea529c1d382308a22309449fa53397e357a780 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 1 Sep 2025 04:15:30 +0200 Subject: [PATCH 5/5] test: run tests in all subdirectories - include ipfs/ tests in CI workflow - update to go 1.24 for compatibility --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 87f6bbe..b624373 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: branches: [ master, dependency-upgrades ] env: - GO_VERSION: "1.23.3" + GO_VERSION: "1.24" jobs: tests: @@ -24,7 +24,7 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Tests - run: go test -v -timeout 15m -coverprofile=coverage.txt -covermode=atomic . + run: go test -v -timeout 15m -coverprofile=coverage.txt -covermode=atomic ./... - name: Coverage uses: codecov/codecov-action@v4