Skip to content

Conversation

@hsanjuan
Copy link
Contributor

@hsanjuan hsanjuan commented Jul 9, 2025

See #963

Refactor the logic to perform Provides, when the component has been given a provider:

  • Remove providing.Exchange
  • Provide directly from Blockstore
  • Provide directly from pinner/merkledag on dag traversal
  • Provide from MFS whenever there is a call to DAGService.Add

As an alternative to providing from MFS, wrapping the DagService as a "providing DAG service", or building a DAGService backed by a providing blockstore, was considered. It was decided that MFS should carry a Provider because it matches how other modules do it and it's quite explicit, MFS calls Provide every time that there is a call to DAGService.Add, which seems enough.

See #963

Refactor the logic to perform Provides:
  * Remove providing Exchange()
  * Provide directly from Blockstore
  * Provide directly from pinner/merkledag on dag traversal
  * (Provides only happen when the component has been given a provider)

One problem I have is that of circular dependencies between the `provider`
module and the `blockstore/pinner/merkledag`. The main issue is that the
provide interfaces are not separate from the reprovider implementation. For
the moment I have copied the interfaces into the several modules to avoid
this.

MFS is untouched, for I believe we need to wrap the DagService as a "providing
DAG service", or build a DAGService backed by a providing blockstore. It seems
these can be done externally though.
@hsanjuan hsanjuan requested a review from a team as a code owner July 9, 2025 18:39
@hsanjuan hsanjuan self-assigned this Jul 9, 2025
Copy link
Contributor Author

@hsanjuan hsanjuan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One problem I have is that of circular dependencies between the provider module and the blockstore/pinner/merkledag. The main issue is that the provide interfaces are not separate from the reprovider implementation. For the moment I have copied the interfaces into the several modules to avoid this.

@codecov
Copy link

codecov bot commented Jul 9, 2025

Codecov Report

❌ Patch coverage is 42.62295% with 140 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.41%. Comparing base (c296626) to head (f2ff3af).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
pinning/pinner/dspinner/pin.go 17.94% 26 Missing and 6 partials ⚠️
blockstore/blockstore.go 28.94% 24 Missing and 3 partials ⚠️
mfs/dir.go 43.90% 17 Missing and 6 partials ⚠️
pinning/pinner/dspinner/pinprovider.go 61.40% 17 Missing and 5 partials ⚠️
ipld/merkledag/merkledag.go 35.71% 14 Missing and 4 partials ⚠️
mfs/root.go 22.22% 6 Missing and 1 partial ⚠️
provider/reprovider.go 50.00% 7 Missing ⚠️
mfs/file.go 76.92% 2 Missing and 1 partial ⚠️
provider/noop.go 0.00% 1 Missing ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #976      +/-   ##
==========================================
- Coverage   61.50%   61.41%   -0.10%     
==========================================
  Files         253      254       +1     
  Lines       31573    31709     +136     
==========================================
+ Hits        19420    19474      +54     
- Misses      10565    10633      +68     
- Partials     1588     1602      +14     
Files with missing lines Coverage Δ
blockservice/blockservice.go 78.15% <ø> (-0.08%) ⬇️
ipld/merkledag/coding.go 77.86% <100.00%> (ø)
provider/provider.go 64.58% <ø> (+4.03%) ⬆️
provider/noop.go 0.00% <0.00%> (ø)
mfs/file.go 62.22% <76.92%> (-0.64%) ⬇️
mfs/root.go 30.68% <22.22%> (-1.85%) ⬇️
provider/reprovider.go 58.85% <50.00%> (-0.65%) ⬇️
ipld/merkledag/merkledag.go 73.35% <35.71%> (-3.82%) ⬇️
pinning/pinner/dspinner/pinprovider.go 61.40% <61.40%> (ø)
mfs/dir.go 51.83% <43.90%> (-1.77%) ⬇️
... and 2 more

... and 11 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@guillaumemichel guillaumemichel self-requested a review July 9, 2025 18:43
@hsanjuan
Copy link
Contributor Author

More problems when trying to integrate in Kubo:

  • In order to have a provider, we need a blockstore, but in order to have a providing blockstore, we need a provider.
  • And so on...

This means we need
* something like blockstore.SetProvider(prov).
* or perhaps in the blockstore case it would work with a blockstore wrapper + decorator.

  • fx gets very complicated as we have providing strategies affecting initialization in multiple places.
  • if we do setters, we have to update interfaces.

Need to think about it, potentially discuss in colo.

@hsanjuan
Copy link
Contributor Author

The routing libp2p package has also Provide interfaces

Copy link
Contributor

@guillaumemichel guillaumemichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done!

MFS is untouched, for I believe we need to wrap the DagService as a "providing DAG service", or build a DAGService backed by a providing blockstore. It seems these can be done externally though.

So it means that this PR will (momentarily) break providing for mfs and pinned+mfs reprovide strategies. IMO it is fine to address this elsewhere.

IIUC the different reprovide strategies would require:

  • all: define Provider() on the blockstore
  • flat define Provider() on the blockstore. Equivalent to all for providing (but different priority during reprovides).
  • roots: define WithRootsProvider() on the pinner
  • pinned: define WithPinnedProvider() on the pinner
  • pinned+mfs: define WithPinnedProvider() on the pinner + TBD
  • mfs: TBD

Is it correct?

@hsanjuan
Copy link
Contributor Author

  • all: define Provider() on the blockstore

    • flat define Provider() on the blockstore. Equivalent to all for providing (but different priority during reprovides).

    • roots: define WithRootsProvider() on the pinner

    • pinned: define WithPinnedProvider() on the pinner

    • pinned+mfs: define WithPinnedProvider() on the pinner + TBD

    • mfs: TBD

Is it correct?

Yes

hsanjuan added 4 commits July 15, 2025 14:26
…rovider.

The purpose here is to break import cycles. These methods forced pulling the pinner and the blockstore dependencies here.

The latter was just a renaming of AllKeysChan and has been removed. The former has been moved to dspinner, along with a test.

Blockstore provider is just a s
The providing strategy needs a blockstore, and the blockstore needs the provider system.

Having a setter allows to break this cycle.
@hsanjuan hsanjuan requested a review from guillaumemichel July 15, 2025 16:40
@hsanjuan
Copy link
Contributor Author

Ok:

  • I have switched to libp2p routing interfaces (better than duplicating them for now)
  • I have added a SetKeyProvider function to the reprovider
  • I have moved NewPinnedProvider to dspinner and removed blockstore/pinner dependencies from the provider module.

With this I can get away with my intentions and I can:
* Create a provider.System without need for a blockstore/pinner in Kubo
* Use the provider.System to set the Provider option for the blockstore/pinner
* SetKeyProvider afterwards to the KeyChanFunc created using blockstore/pinner

Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hsanjuan thoughts on opening a Kubo PR that uses this to see the impact + be a place where we can start adding end-to-end tests for Reprovider.Strategy in Kubo?

Right now we lack test results that:

  • confirm Reprovider.Strategy=all|pinned|roots work as expected
  • show Reprovider.Strategy=mfs|pinned+mfs need to be fixed

@guillaumemichel
Copy link
Contributor

Triage notes:

  • @hsanjuan will take care of the mfs provide strategy in this PR

hsanjuan added 3 commits July 25, 2025 16:46
The provider provides the CID every time something is added to the DAG service.
… any.

Applies to Provide() calls in Blockstore, Merkledag, Pinner. Per PR review.
@hsanjuan
Copy link
Contributor Author

I have addressed comments and I have added a provider param to MFS constructors.

This breaks the API but I don't know if it's worth to avoid that. Seems pretty straightforward to fix (passing nil, or a provider).

In the end I have opted for carrying a Provider around in MFS because it matches how other modules do it and it's quite explicit, rather than doing a magic DAGService wrapper, or a mfs-only-providing-blockstore in Kubo. MFS calls Provide every time that there is a call to DAGService.Add, which seems enough.

hsanjuan added a commit to ipfs/kubo that referenced this pull request Jul 29, 2025
This updates boxo to this PR ipfs/boxo#976, which decentralizes the providing responsibilities.

Then it perfoms the necessary changes in Kubo, which consist in initializing the Pinner, MFS and the blockstore with the provider.System.

Since the provider.System is created first, the reproviding KeyChanFunc is set
later when we can create it.
hsanjuan added a commit to ipfs/kubo that referenced this pull request Jul 29, 2025
This updates boxo to this PR ipfs/boxo#976, which decentralizes the providing responsibilities.

Then it perfoms the necessary changes in Kubo, which consist in initializing the Pinner, MFS and the blockstore with the provider.System.

Since the provider.System is created first, the reproviding KeyChanFunc is set
later when we can create it.
@lidel lidel requested a review from gammazero July 29, 2025 14:29
@hsanjuan
Copy link
Contributor Author

Review: make sure godoc reflects that you can pass nil as the provider.

And fix the tests.

@gammazero
Copy link
Contributor

Review: make sure godoc reflects that you can pass nil as the provider.

And fix the tests.

Done

@hsanjuan
Copy link
Contributor Author

We will merge together with ipfs/kubo#10886

@hsanjuan hsanjuan marked this pull request as draft July 31, 2025 07:47
@hsanjuan hsanjuan marked this pull request as ready for review August 4, 2025 14:20
@hsanjuan
Copy link
Contributor Author

hsanjuan commented Aug 4, 2025

Per my latest advancements with Kubo, I think we're good to merge this here for the moment.

@gammazero gammazero merged commit e5da058 into main Aug 4, 2025
18 checks passed
@gammazero gammazero deleted the fix/963-do-not-provide-everything branch August 4, 2025 22:48
lidel added a commit to ipfs/kubo that referenced this pull request Aug 7, 2025
hsanjuan added a commit to ipfs/kubo that referenced this pull request Aug 8, 2025
* Provide according to strategy

Updates boxo to a version with the changes from ipfs/boxo#976, which decentralize the providing responsibilities (from a central providing.Exchange to blockstore, pinner, mfs).

The changes consist in initializing the Pinner, MFS and the blockstore with the provider.System, which is created first.

Since the provider.System is created first, the reproviding KeyChanFunc is set
later when we can create it once we have the Pinner, MFS and the blockstore.

Some additional work applies to the Add() workflow. Normally, blocks would get provided at the Blockstore or the Pinner, but when adding blocks AND a "pinned" strategy is used, the blockstore does not provide, and the
pinner does not traverse the DAG (and thus doesn't provide either), so we need to provide directly from the Adder. This is resolved by wrapping the DAGService in a "providingDAGService" which provides every added block, when using the "pinned" strategy.

`ipfs --offline add` when the ONLINE daemon is running will now announce blocks per the chosen strategy, where before it did not announce them. This is documented in the changelog. A couple of releases ago, adding with `ipfs --offline add` was faster, but this is no longer the case so we are not incurring in any penalties by sticking to the fact that the daemon is online and has a providing strategy that we follow.

Co-authored-by: gammazero <11790789+gammazero@users.noreply.github.com>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
@hsanjuan hsanjuan linked an issue Aug 8, 2025 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decentralizing new blocks notification (avoid providing everything)

5 participants