From 4f83908b5eef70b1392bb49b4f044d5ed68f4ed1 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 13 May 2025 20:07:58 +0200 Subject: [PATCH 1/5] fix(config): explicit Provider.Enabled flag Adds missing config option described in https://github.com/ipfs/kubo/issues/10803 --- config/provider.go | 5 ++++- core/node/bitswap.go | 7 ++++--- core/node/groups.go | 21 ++++++++++++++------- core/node/provider.go | 4 ++-- docs/config.md | 34 ++++++++++++++++++++++++++++------ 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/config/provider.go b/config/provider.go index a1c44859889..bc6da8fd85d 100644 --- a/config/provider.go +++ b/config/provider.go @@ -1,12 +1,15 @@ package config const ( - DefaultProviderWorkerCount = 64 + DefaultProviderEnabled = true + DefaultProviderWorkerCount = 16 + DefaultProviderWorkerCountAcceleratedDHT = 64 ) // Provider configuration describes how NEW CIDs are announced the moment they are created. // For periodical reprovide configuration, see Reprovider.* type Provider struct { + Enabled Flag `json:",omitempty"` Strategy *OptionalString `json:",omitempty"` // Unused, you are likely looking for Reprovider.Strategy instead WorkerCount *OptionalInteger `json:",omitempty"` // Number of concurrent provides allowed, 0 means unlimited } diff --git a/core/node/bitswap.go b/core/node/bitswap.go index a52b3e75d34..e87464b8a67 100644 --- a/core/node/bitswap.go +++ b/core/node/bitswap.go @@ -83,7 +83,7 @@ type bitswapIn struct { // Bitswap creates the BitSwap server/client instance. // If Bitswap.ServerEnabled is false, the node will act only as a client // using an empty blockstore to prevent serving blocks to other peers. -func Bitswap(serverEnabled bool) interface{} { +func Bitswap(serverEnabled, libp2pEnabled, httpEnabled bool) interface{} { return func(in bitswapIn, lc fx.Lifecycle) (*bitswap.Bitswap, error) { var bitswapNetworks, bitswapLibp2p network.BitSwapNetwork var bitswapBlockstore blockstore.Blockstore = in.Bs @@ -93,7 +93,8 @@ func Bitswap(serverEnabled bool) interface{} { bitswapLibp2p = bsnet.NewFromIpfsHost(in.Host) } - if httpCfg := in.Cfg.HTTPRetrieval; httpCfg.Enabled.WithDefault(config.DefaultHTTPRetrievalEnabled) { + if httpEnabled { + httpCfg := in.Cfg.HTTPRetrieval maxBlockSize, err := humanize.ParseBytes(httpCfg.MaxBlockSize.WithDefault(config.DefaultHTTPRetrievalMaxBlockSize)) if err != nil { return nil, err @@ -136,7 +137,7 @@ func Bitswap(serverEnabled bool) interface{} { return nil, err } - // Explicitly enable/disable server to ensure desired provide mode + // Explicitly enable/disable server in.BitswapOpts = append(in.BitswapOpts, bitswap.WithServerEnabled(serverEnabled)) bs := bitswap.New(helpers.LifecycleCtx(in.Mctx, lc), bitswapNetworks, providerQueryMgr, bitswapBlockstore, in.BitswapOpts...) diff --git a/core/node/groups.go b/core/node/groups.go index e4682f6a6bc..ba75c1362ca 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -337,16 +337,23 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part isBitswapLibp2pEnabled := cfg.Bitswap.Libp2pEnabled.WithDefault(config.DefaultBitswapLibp2pEnabled) isBitswapServerEnabled := cfg.Bitswap.ServerEnabled.WithDefault(config.DefaultBitswapServerEnabled) + isHTTPRetrievalEnabled := cfg.HTTPRetrieval.Enabled.WithDefault(config.DefaultHTTPRetrievalEnabled) - // Don't provide from bitswap when the legacy noop experiment "strategic provider service" is active - isBitswapServerEnabled = isBitswapServerEnabled && !cfg.Experimental.StrategicProviding + isProviderEnabled := cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) && isBitswapServerEnabled && !cfg.Experimental.StrategicProviding + isAcceleratedDHTClient := cfg.Routing.AcceleratedDHTClient.WithDefault(config.DefaultAcceleratedDHTClient) + + // Accelerated DHT client has routing table cached, this able to handle bigger worker pool + defaultProviderWorkerCount := int64(config.DefaultProviderWorkerCount) + if isAcceleratedDHTClient { + defaultProviderWorkerCount = config.DefaultProviderWorkerCountAcceleratedDHT + } return fx.Options( fx.Provide(BitswapOptions(cfg)), - fx.Provide(Bitswap(isBitswapServerEnabled)), + fx.Provide(Bitswap(isBitswapServerEnabled, isBitswapLibp2pEnabled, isHTTPRetrievalEnabled)), fx.Provide(OnlineExchange(isBitswapLibp2pEnabled)), // Replace our Exchange with a Providing exchange! - fx.Decorate(ProvidingExchange(isBitswapServerEnabled)), + fx.Decorate(ProvidingExchange(isProviderEnabled)), fx.Provide(DNSResolver), fx.Provide(Namesys(ipnsCacheSize, cfg.Ipns.MaxCacheTTL.WithDefault(config.DefaultIpnsMaxCacheTTL))), fx.Provide(Peering), @@ -358,11 +365,11 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part LibP2P(bcfg, cfg, userResourceOverrides), OnlineProviders( - cfg.Experimental.StrategicProviding, + isProviderEnabled, cfg.Reprovider.Strategy.WithDefault(config.DefaultReproviderStrategy), cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval), - cfg.Routing.AcceleratedDHTClient.WithDefault(config.DefaultAcceleratedDHTClient), - int(cfg.Provider.WorkerCount.WithDefault(config.DefaultProviderWorkerCount)), + isAcceleratedDHTClient, + int(cfg.Provider.WorkerCount.WithDefault(defaultProviderWorkerCount)), ), ) } diff --git a/core/node/provider.go b/core/node/provider.go index d0081eb0aec..79fed2a4f99 100644 --- a/core/node/provider.go +++ b/core/node/provider.go @@ -132,8 +132,8 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#routingaccelerateddhtcli // ONLINE/OFFLINE // OnlineProviders groups units managing provider routing records online -func OnlineProviders(useStrategicProviding bool, reprovideStrategy string, reprovideInterval time.Duration, acceleratedDHTClient bool, provideWorkerCount int) fx.Option { - if useStrategicProviding { +func OnlineProviders(provide bool, reprovideStrategy string, reprovideInterval time.Duration, acceleratedDHTClient bool, provideWorkerCount int) fx.Option { + if !provide { return OfflineProviders() } diff --git a/docs/config.md b/docs/config.md index 3da157d19ac..53d14da72c3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -110,6 +110,7 @@ config file at runtime. - [`Pinning.RemoteServices: Policies.MFS.PinName`](#pinningremoteservices-policiesmfspinname) - [`Pinning.RemoteServices: Policies.MFS.RepinInterval`](#pinningremoteservices-policiesmfsrepininterval) - [`Provider`](#provider) + - [`Provider.Enabled`](#providerenabled) - [`Provider.Strategy`](#providerstrategy) - [`Provider.WorkerCount`](#providerworkercount) - [`Pubsub`](#pubsub) @@ -962,7 +963,7 @@ We are working on developing a modern replacement. To support our efforts, pleas on specified hostnames that point at your Kubo instance. It is useful when you want to run [Path gateway](https://specs.ipfs.tech/http-gateways/path-gateway/) on `example.com/ipfs/cid`, -and [Subdomain gateway](https://specs.ipfs.tech/http-gateways/subdomain-gateway/) on `cid.ipfs.example.org`, +and [Subdomain gateway](https://specs.ipfs.tech/http-gateways/subdomain-gateway/) on `cid.ipfs.example.org`, or limit `verifiable.example.net` to response types defined in [Trustless Gateway](https://specs.ipfs.tech/http-gateways/trustless-gateway/) specification. > [!CAUTION] @@ -1000,7 +1001,7 @@ Type: `array[string]` #### `Gateway.PublicGateways: UseSubdomains` A boolean to configure whether the gateway at the hostname should be -a [Subdomain Gateway](https://specs.ipfs.tech/http-gateways/subdomain-gateway/) +a [Subdomain Gateway](https://specs.ipfs.tech/http-gateways/subdomain-gateway/) and provide [Origin isolation](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) between content roots. @@ -1503,15 +1504,28 @@ commands. For periodical DHT reprovide settings, see [`Reprovide.*`](#reprovider). +### `Provider.Enabled` + +Controls whether Kubo provider and reprovide systems are enabled. + +> [!CAUTION] +> Disabling this, will disable BOTH `Provider` system for new CIDs +> and the periodical reprovide ([`Reprovider.Interval`](#reprovider)) of old CIDs. + +Default: `true` + +Type: `flag` + ### `Provider.Strategy` Legacy, not used at the moment, see [`Reprovider.Strategy`](#reproviderstrategy) instead. ### `Provider.WorkerCount` -Sets the maximum number of _concurrent_ DHT provide operations. DHT reprovides -operations do **not** count against that limit. A value of `0` allows an -unlimited number of provide workers. +Sets the maximum number of _concurrent_ DHT provide operations (announcement of new CIDs). + +[`Reprovider`](#reprovider) operations do **not** count against this limit. +A value of `0` allows an unlimited number of provide workers. If the [accelerated DHT client](#routingaccelerateddhtclient) is enabled, each provide operation opens ~20 connections in parallel. With the standard DHT @@ -1524,7 +1538,11 @@ For nodes without strict connection limits that need to provide large volumes of content immediately, we recommend enabling the `Routing.AcceleratedDHTClient` and setting `Provider.WorkerCount` to `0` (unlimited). -Default: `64` +> [!CAUTION] +> Raising this value too high may lead to increased load. +> Proceed with caution. + +Default: `16` (`64` if `Routing.AcceleratedDHTClient=true`) Type: `integer` (non-negative; `0` means unlimited number of workers) @@ -1706,6 +1724,10 @@ not being able to discover that you have the objects that you have. If you want to have this disabled and keep the network aware of what you have, you must manually announce your content periodically. +> [!CAUTION] +> Setting `Reprovider.Interval=0` will only disable the periodic reprovides. +> New CIDs will stil lbe announced. To disable both, set [`Provider.Enabled=false`](#providerenabled) as well. + Default: `22h` (`DefaultReproviderInterval`) Type: `optionalDuration` (unset for the default) From f28bc86387fbde35fae72a47c68b4dd6617580b3 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 13 May 2025 21:09:26 +0200 Subject: [PATCH 2/5] refactor: remove Experimental.StrategicProviding removing experiment, replaced with Provider.Enabled --- cmd/ipfs/kubo/daemon.go | 17 ++++++++++++----- config/experiments.go | 2 +- config/profile.go | 8 ++++---- core/node/groups.go | 7 +++++-- docs/changelogs/v0.35.md | 12 ++++++++---- docs/experimental-features.md | 22 ++-------------------- test/cli/provider_test.go | 8 ++++---- 7 files changed, 36 insertions(+), 40 deletions(-) diff --git a/cmd/ipfs/kubo/daemon.go b/cmd/ipfs/kubo/daemon.go index ea6ccfc1dbe..5cdf3fa1dca 100644 --- a/cmd/ipfs/kubo/daemon.go +++ b/cmd/ipfs/kubo/daemon.go @@ -491,6 +491,11 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment if cfg.Provider.Strategy.WithDefault("") != "" && cfg.Reprovider.Strategy.IsDefault() { log.Fatal("Invalid config. Remove unused Provider.Strategy and set Reprovider.Strategy instead. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy") } + if cfg.Experimental.StrategicProviding { + log.Error("Experimental.StrategicProviding was removed. Remove it from your config and set Provider.Enabled=false to remove this message. Documentation: https://github.com/ipfs/kubo/blob/master/docs/experimental-features.md#strategic-providing") + cfg.Experimental.StrategicProviding = false + cfg.Provider.Enabled = config.False + } printLibp2pPorts(node) @@ -625,17 +630,19 @@ take effect. }() if !offline { - // Warn users who were victims of 'lowprofile' footgun (https://github.com/ipfs/kubo/pull/10524) - if cfg.Experimental.StrategicProviding { + // Warn users when provide systems are disabled + if !cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) { fmt.Print(` -⚠️ Reprovide system is disabled due to 'Experimental.StrategicProviding=true' + +⚠️ Provide and Reprovide systems are disabled due to 'Provide.Enabled=false' ⚠️ Local CIDs will not be announced to Amino DHT, making them impossible to retrieve without manual peering -⚠️ If this is not intentional, call 'ipfs config profile apply announce-on' +⚠️ If this is not intentional, call 'ipfs config profile apply announce-on' or set Provide.Enabled=true' `) } else if cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval) == 0 { fmt.Print(` -⚠️ Reprovider system is disabled due to 'Reprovider.Interval=0' + +⚠️ Provide and Reprovide systems are disabled due to 'Reprovider.Interval=0' ⚠️ Local CIDs will not be announced to Amino DHT, making them impossible to retrieve without manual peering ⚠️ If this is not intentional, call 'ipfs config profile apply announce-on', or set 'Reprovider.Interval=22h' diff --git a/config/experiments.go b/config/experiments.go index fab1f953c2e..6c43ac04f07 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -6,7 +6,7 @@ type Experiments struct { ShardingEnabled bool `json:",omitempty"` // deprecated by autosharding: https://github.com/ipfs/kubo/pull/8527 Libp2pStreamMounting bool P2pHttpProxy bool //nolint - StrategicProviding bool + StrategicProviding bool `json:",omitempty"` // removed, use Provider.Enabled instead OptimisticProvide bool OptimisticProvideJobsPoolSize int GatewayOverLibp2p bool `json:",omitempty"` diff --git a/config/profile.go b/config/profile.go index 605af355529..ec2e5a0b7ae 100644 --- a/config/profile.go +++ b/config/profile.go @@ -270,7 +270,7 @@ fetching may be degraded. }, }, "announce-off": { - Description: `Disables Reprovide system (and announcing to Amino DHT). + Description: `Disables Provide and Reprovide systems (announcing to Amino DHT). USE WITH CAUTION: The main use case for this is setups with manual Peering.Peers config. @@ -279,16 +279,16 @@ fetching may be degraded. one hosting it, and other peers are not already connected to it. `, Transform: func(c *Config) error { + c.Provider.Enabled = False c.Reprovider.Interval = NewOptionalDuration(0) // 0 disables periodic reprovide - c.Experimental.StrategicProviding = true // this is not a typo (the name is counter-intuitive) return nil }, }, "announce-on": { - Description: `Re-enables Reprovide system (reverts announce-off profile).`, + Description: `Re-enables Provide and Reprovide systems (reverts announce-off profile).`, Transform: func(c *Config) error { + c.Provider.Enabled = True c.Reprovider.Interval = NewOptionalDuration(DefaultReproviderInterval) // have to apply explicit default because nil would be ignored - c.Experimental.StrategicProviding = false // this is not a typo (the name is counter-intuitive) return nil }, }, diff --git a/core/node/groups.go b/core/node/groups.go index ba75c1362ca..4ef82b5dff8 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -339,7 +339,10 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part isBitswapServerEnabled := cfg.Bitswap.ServerEnabled.WithDefault(config.DefaultBitswapServerEnabled) isHTTPRetrievalEnabled := cfg.HTTPRetrieval.Enabled.WithDefault(config.DefaultHTTPRetrievalEnabled) - isProviderEnabled := cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) && isBitswapServerEnabled && !cfg.Experimental.StrategicProviding + // Right now Provider and Reprovider systems are tied together - disabling Reprovider by setting interval to 0 disables Provider + // and vice versa: Provider.Enabled=false will disable both Provider of new CIDs and the Reprovider of old ones. + isProviderEnabled := cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) && cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval) != 0 + isAcceleratedDHTClient := cfg.Routing.AcceleratedDHTClient.WithDefault(config.DefaultAcceleratedDHTClient) // Accelerated DHT client has routing table cached, this able to handle bigger worker pool @@ -353,7 +356,7 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part fx.Provide(Bitswap(isBitswapServerEnabled, isBitswapLibp2pEnabled, isHTTPRetrievalEnabled)), fx.Provide(OnlineExchange(isBitswapLibp2pEnabled)), // Replace our Exchange with a Providing exchange! - fx.Decorate(ProvidingExchange(isProviderEnabled)), + fx.Decorate(ProvidingExchange(isProviderEnabled && isBitswapServerEnabled)), fx.Provide(DNSResolver), fx.Provide(Namesys(ipnsCacheSize, cfg.Ipns.MaxCacheTTL.WithDefault(config.DefaultIpnsMaxCacheTTL))), fx.Provide(Peering), diff --git a/docs/changelogs/v0.35.md b/docs/changelogs/v0.35.md index 9314390ad88..6dac079b4a4 100644 --- a/docs/changelogs/v0.35.md +++ b/docs/changelogs/v0.35.md @@ -181,12 +181,16 @@ to delays in initial advertisements (provides). Provides and Reprovides now have separate queues, allowing for immediate provide of new CIDs and optimised batching of reprovides. -This change introduces a new configuration option for limiting the number of -concurrent provide operations: -[`Provider.WorkerCount`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providerworkercount). +###### New `Provider` configuration options + +This change introduces a new configuration options: + +- [`Provider.Enabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providerenabled) is a global flag for disabling both [Provider](https://github.com/ipfs/kubo/blob/master/docs/config.md#provider) and [Reprovider](https://github.com/ipfs/kubo/blob/master/docs/config.md#reprovider) systems (announcing new/old CIDs to amino DHT). +- [`Provider.WorkerCount`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providerworkercount) for limiting the number of concurrent provide operations, allows for fine-tuning the trade-off between announcement speed and system load when announcing new CIDs. +- Removed `Experimental.StrategicProviding`. Superseded by `Provider.Enabled`, `Reprovider.Interval` and [`Reprovider.Strategy`](https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy). > [!TIP] -> Users who need to provide large volumes of content immediately should consider removing the cap on concurrent provide operations and also set `Routing.AcceleratedDHTClient` to `true`. +> Users who need to provide large volumes of content immediately should consider setting `Routing.AcceleratedDHTClient` to `true`. If that is not enough, consider adjusting `Provider.WorkerCount` to a higher value. ###### Deprecated `ipfs stats provider` diff --git a/docs/experimental-features.md b/docs/experimental-features.md index 7d0069fc6f7..fbee3d480b1 100644 --- a/docs/experimental-features.md +++ b/docs/experimental-features.md @@ -537,27 +537,9 @@ ipfs config --json Swarm.RelayClient.Enabled true ### State -Experimental, disabled by default. - -Replaces the existing provide mechanism with a robust, strategic provider system. Currently enabling this option will provide nothing. - -### How to enable - -Modify your ipfs config: - -``` -ipfs config --json Experimental.StrategicProviding true -``` - -### Road to being a real feature +`Experimental.StrategicProviding` was removed in Kubo v0.35. -- [ ] needs real-world testing -- [ ] needs adoption -- [ ] needs to support all provider subsystem features - - [X] provide nothing - - [ ] provide roots - - [ ] provide all - - [ ] provide strategic +Replaced by [`Provide.Enabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providerenabled) and [`Reprovider.Strategy`](https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy). ## GraphSync diff --git a/test/cli/provider_test.go b/test/cli/provider_test.go index 81af7814954..c0ca3f03568 100644 --- a/test/cli/provider_test.go +++ b/test/cli/provider_test.go @@ -33,11 +33,11 @@ func TestProvider(t *testing.T) { } } - t.Run("Basic Providing", func(t *testing.T) { + t.Run("Provider.Enabled=true", func(t *testing.T) { t.Parallel() nodes := initNodes(t, 2, func(n *harness.Node) { - n.SetIPFSConfig("Experimental.StrategicProviding", false) + n.SetIPFSConfig("Provider.Enabled", true) }) defer nodes.StopDaemons() @@ -48,11 +48,11 @@ func TestProvider(t *testing.T) { expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...) }) - t.Run("Basic Strategic Providing", func(t *testing.T) { + t.Run("Provider.Enabled=false", func(t *testing.T) { t.Parallel() nodes := initNodes(t, 2, func(n *harness.Node) { - n.SetIPFSConfig("Experimental.StrategicProviding", true) + n.SetIPFSConfig("Provider.Enabled", false) }) defer nodes.StopDaemons() From a63e3998931dca6d44ab1854658db70e1bb049bc Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 13 May 2025 22:52:40 +0200 Subject: [PATCH 3/5] test(cli): routing [re]provide updated and added tests for manually triggering provide and reprovide and making them respect global configuration flag to avoid inconsistent behaviors --- core/commands/routing.go | 21 +++++++++ test/cli/provider_test.go | 90 +++++++++++++++++++++++++++++++-------- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/core/commands/routing.go b/core/commands/routing.go index 3528a94f5ea..0804b1f44c3 100644 --- a/core/commands/routing.go +++ b/core/commands/routing.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/ipfs/kubo/config" cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" dag "github.com/ipfs/boxo/ipld/merkledag" @@ -158,6 +159,14 @@ var provideRefRoutingCmd = &cmds.Command{ if !nd.IsOnline { return ErrNotOnline } + // respect global config + cfg, err := nd.Repo.Config() + if err != nil { + return err + } + if !cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) { + return errors.New("invalid configuration: Provider.Enabled is set to 'false'") + } if len(nd.PeerHost.Network().Conns()) == 0 { return errors.New("cannot provide, no connected peers") @@ -254,6 +263,18 @@ Trigger reprovider to announce our data to network. return ErrNotOnline } + // respect global config + cfg, err := nd.Repo.Config() + if err != nil { + return err + } + if !cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) { + return errors.New("invalid configuration: Provider.Enabled is set to 'false'") + } + if cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval) == 0 { + return errors.New("invalid configuration: Reprovider.Interval is set to '0'") + } + err = nd.Provider.Reprovide(req.Context) if err != nil { return err diff --git a/test/cli/provider_test.go b/test/cli/provider_test.go index c0ca3f03568..7e2bee411c0 100644 --- a/test/cli/provider_test.go +++ b/test/cli/provider_test.go @@ -7,6 +7,7 @@ import ( "github.com/ipfs/kubo/test/cli/harness" "github.com/ipfs/kubo/test/cli/testutils" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -33,7 +34,7 @@ func TestProvider(t *testing.T) { } } - t.Run("Provider.Enabled=true", func(t *testing.T) { + t.Run("Provider.Enabled=true announces new CIDs created by ipfs add", func(t *testing.T) { t.Parallel() nodes := initNodes(t, 2, func(n *harness.Node) { @@ -48,7 +49,7 @@ func TestProvider(t *testing.T) { expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...) }) - t.Run("Provider.Enabled=false", func(t *testing.T) { + t.Run("Provider.Enabled=false disables announcement of new CID from ipfs add", func(t *testing.T) { t.Parallel() nodes := initNodes(t, 2, func(n *harness.Node) { @@ -60,6 +61,75 @@ func TestProvider(t *testing.T) { expectNoProviders(t, cid, nodes[1:]...) }) + t.Run("Provider.Enabled=false disables manual announcement via RPC command", func(t *testing.T) { + t.Parallel() + + nodes := initNodes(t, 2, func(n *harness.Node) { + n.SetIPFSConfig("Provider.Enabled", false) + }) + defer nodes.StopDaemons() + + cid := nodes[0].IPFSAddStr(time.Now().String()) + res := nodes[0].RunIPFS("routing", "provide", cid) + assert.Contains(t, res.Stderr.Trimmed(), "invalid configuration: Provider.Enabled is set to 'false'") + assert.Equal(t, 1, res.ExitCode()) + + expectNoProviders(t, cid, nodes[1:]...) + }) + + // Right now Provide and Reprovide are tied together + t.Run("Reprovide.Interval=0 disables announcement of new CID too", func(t *testing.T) { + t.Parallel() + + nodes := initNodes(t, 2, func(n *harness.Node) { + n.SetIPFSConfig("Reprovider.Interval", "0") + }) + defer nodes.StopDaemons() + + cid := nodes[0].IPFSAddStr(time.Now().String()) + expectNoProviders(t, cid, nodes[1:]...) + }) + + // It is a lesser evil - forces users to fix their config and have some sort of interval + t.Run("Manual Reprovider trigger does not work when periodic Reprovider is disabled", func(t *testing.T) { + t.Parallel() + + nodes := initNodes(t, 2, func(n *harness.Node) { + n.SetIPFSConfig("Reprovider.Interval", "0") + }) + defer nodes.StopDaemons() + + cid := nodes[0].IPFSAddStr(time.Now().String(), "--offline") + + expectNoProviders(t, cid, nodes[1:]...) + + res := nodes[0].RunIPFS("routing", "reprovide") + assert.Contains(t, res.Stderr.Trimmed(), "invalid configuration: Reprovider.Interval is set to '0'") + assert.Equal(t, 1, res.ExitCode()) + + expectNoProviders(t, cid, nodes[1:]...) + }) + + // It is a lesser evil - forces users to fix their config and have some sort of interval + t.Run("Manual Reprovider trigger does not work when Provider system is disabled", func(t *testing.T) { + t.Parallel() + + nodes := initNodes(t, 2, func(n *harness.Node) { + n.SetIPFSConfig("Provider.Enabled", false) + }) + defer nodes.StopDaemons() + + cid := nodes[0].IPFSAddStr(time.Now().String(), "--offline") + + expectNoProviders(t, cid, nodes[1:]...) + + res := nodes[0].RunIPFS("routing", "reprovide") + assert.Contains(t, res.Stderr.Trimmed(), "invalid configuration: Provider.Enabled is set to 'false'") + assert.Equal(t, 1, res.ExitCode()) + + expectNoProviders(t, cid, nodes[1:]...) + }) + t.Run("Reprovides with 'all' strategy", func(t *testing.T) { t.Parallel() @@ -149,20 +219,4 @@ func TestProvider(t *testing.T) { expectProviders(t, cidBarDir, nodes[0].PeerID().String(), nodes[1:]...) }) - t.Run("Providing works without ticking", func(t *testing.T) { - t.Parallel() - - nodes := initNodes(t, 2, func(n *harness.Node) { - n.SetIPFSConfig("Reprovider.Interval", "0") - }) - defer nodes.StopDaemons() - - cid := nodes[0].IPFSAddStr(time.Now().String(), "--offline") - - expectNoProviders(t, cid, nodes[1:]...) - - nodes[0].IPFS("routing", "reprovide") - - expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...) - }) } From 605fc762225e4f67b27f22e01203033af8fefc89 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 15 May 2025 18:14:03 +0200 Subject: [PATCH 4/5] docs: improve DelegatedRouters --- config/routing.go | 3 ++- docs/config.md | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/config/routing.go b/config/routing.go index 3fe501ee410..aea60c3bd24 100644 --- a/config/routing.go +++ b/config/routing.go @@ -48,10 +48,11 @@ type Routing struct { IgnoreProviders []string `json:",omitempty"` + // Simplified configuration used by default when Routing.Type=auto|autoclient DelegatedRouters []string `json:",omitempty"` + // Advanced configuration used when Routing.Type=custom Routers Routers `json:",omitempty"` - Methods Methods `json:",omitempty"` } diff --git a/docs/config.md b/docs/config.md index 53d14da72c3..616bde290a7 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1890,12 +1890,13 @@ Type: `array[string]` ### `Routing.DelegatedRouters` -This is an array of URL hostnames that support the [Delegated Routing V1 HTTP API](https://specs.ipfs.tech/routing/http-routing-v1/) which are used alongside the DHT when [`Routing.Type`](#routingtype) is set to `auto` or `autoclient`. +An array of URL hostnames for delegated routers to be queried in addition to the Amino DHT when `Routing.Type` is set to `auto` (default) or `autoclient`. +These endpoints must support the [Delegated Routing V1 HTTP API](https://specs.ipfs.tech/routing/http-routing-v1/). > [!TIP] > Delegated routing allows IPFS implementations to offload tasks like content routing, peer routing, and naming to a separate process or server while also benefiting from HTTP caching. > -> One can run their own delegated router either by implementing the [Delegated Routing V1 HTTP API](https://specs.ipfs.tech/routing/http-routing-v1/) themselves, or by using [Someguy](https://github.com/ipfs/someguy), a turn-key implementation that proxies requests to the Amino DHT and other delegated routing servers, such as the Network Indexer at `cid.contact`. Public utility instance of Someguy is hosted at [`https://delegated-ipfs.dev`](https://docs.ipfs.tech/concepts/public-utilities/#delegated-routing). +> One can run their own delegated router either by implementing the [Delegated Routing V1 HTTP API](https://specs.ipfs.tech/routing/http-routing-v1/) themselves, or by using [Someguy](https://github.com/ipfs/someguy), a turn-key implementation that proxies requests to other routing systems. A public utility instance of Someguy is hosted at [`https://delegated-ipfs.dev`](https://docs.ipfs.tech/concepts/public-utilities/#delegated-routing). Default: `["https://cid.contact"]` (empty or `nil` will also use this default; to disable delegated routing, set `Routing.Type` to `dht` or `dhtclient`) @@ -1903,11 +1904,14 @@ Type: `array[string]` ### `Routing.Routers` -**EXPERIMENTAL: `Routing.Routers` configuration may change in future release** +Alternative configuration used when `Routing.Type=custom`. -Map of additional Routers. +> [!WARNING] +> **EXPERIMENTAL: `Routing.Routers` configuration may change in future release** +> +> Consider this advanced low-level config: Most users can simply use `Routing.Type=auto` or `autoclient` and set up basic config in user-friendly [`Routing.DelegatedRouters`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingdelegatedrouters). -Allows for extending the default routing (Amino DHT) with alternative Router +Allows for replacing the default routing (Amino DHT) with alternative Router implementations. The map key is a name of a Router, and the value is its configuration. @@ -1967,7 +1971,14 @@ Type: `object[string->string]` ### `Routing: Methods` -`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. +`Methods:map` will define which routers will be executed per method used when `Routing.Type=custom`. + +> [!WARNING] +> **EXPERIMENTAL: `Routing.Routers` configuration may change in future release** +> +> Consider this advanced low-level config: Most users can simply use `Routing.Type=auto` or `autoclient` and set up basic config in user-friendly [`Routing.DelegatedRouters`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingdelegatedrouters). + +The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. The value will contain: - `RouterName:string`: Name of the router. It should be one of the previously added to `Routing.Routers` list. From e8ec3fde17c14a192866dbc9637c18c27e0c734c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 15 May 2025 18:32:57 +0200 Subject: [PATCH 5/5] refactor: default DefaultProviderWorkerCount=16 - simplified default for both - 16 is safer for non-accelerated DHT client - acceletated DHT performs better without limit anyway - updated docs --- config/provider.go | 5 ++--- core/node/groups.go | 12 ++---------- docs/config.md | 26 ++++++++++++++------------ 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/config/provider.go b/config/provider.go index bc6da8fd85d..4a2243acb07 100644 --- a/config/provider.go +++ b/config/provider.go @@ -1,9 +1,8 @@ package config const ( - DefaultProviderEnabled = true - DefaultProviderWorkerCount = 16 - DefaultProviderWorkerCountAcceleratedDHT = 64 + DefaultProviderEnabled = true + DefaultProviderWorkerCount = 16 ) // Provider configuration describes how NEW CIDs are announced the moment they are created. diff --git a/core/node/groups.go b/core/node/groups.go index 4ef82b5dff8..3a952ccfe10 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -343,14 +343,6 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part // and vice versa: Provider.Enabled=false will disable both Provider of new CIDs and the Reprovider of old ones. isProviderEnabled := cfg.Provider.Enabled.WithDefault(config.DefaultProviderEnabled) && cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval) != 0 - isAcceleratedDHTClient := cfg.Routing.AcceleratedDHTClient.WithDefault(config.DefaultAcceleratedDHTClient) - - // Accelerated DHT client has routing table cached, this able to handle bigger worker pool - defaultProviderWorkerCount := int64(config.DefaultProviderWorkerCount) - if isAcceleratedDHTClient { - defaultProviderWorkerCount = config.DefaultProviderWorkerCountAcceleratedDHT - } - return fx.Options( fx.Provide(BitswapOptions(cfg)), fx.Provide(Bitswap(isBitswapServerEnabled, isBitswapLibp2pEnabled, isHTTPRetrievalEnabled)), @@ -371,8 +363,8 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part isProviderEnabled, cfg.Reprovider.Strategy.WithDefault(config.DefaultReproviderStrategy), cfg.Reprovider.Interval.WithDefault(config.DefaultReproviderInterval), - isAcceleratedDHTClient, - int(cfg.Provider.WorkerCount.WithDefault(defaultProviderWorkerCount)), + cfg.Routing.AcceleratedDHTClient.WithDefault(config.DefaultAcceleratedDHTClient), + int(cfg.Provider.WorkerCount.WithDefault(config.DefaultProviderWorkerCount)), ), ) } diff --git a/docs/config.md b/docs/config.md index 616bde290a7..4b8d66ac02c 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1111,7 +1111,7 @@ $ ipfs config --json Gateway.PublicGateways '{"localhost": null }' ### `Gateway` recipes -Below is a list of the most common public gateway setups. +Below is a list of the most common gateway setups. * Public [subdomain gateway](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway) at `http://{cid}.ipfs.dweb.link` (each content root gets its own Origin) ```console @@ -1122,6 +1122,7 @@ Below is a list of the most common public gateway setups. } }' ``` + - **Performance:** consider running with `Routing.AcceleratedDHTClient=true` and either `Provider.Enabled=false` (avoid providing newly retrieved blocks) or `Provider.WorkerCount=0` (provide as fast as possible, at the cost of increased load) - **Backward-compatible:** this feature enables automatic redirects from content paths to subdomains: `http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.dweb.link` @@ -1146,6 +1147,7 @@ Below is a list of the most common public gateway setups. } }' ``` + - **Performance:** when running an open, recursive gateway consider running with `Routing.AcceleratedDHTClient=true` and either `Provider.Enabled=false` (avoid providing newly retrieved blocks) or `Provider.WorkerCount=0` (provide as fast as possible, at the cost of increased load) * Public [DNSLink](https://dnslink.io/) gateway resolving every hostname passed in `Host` header. ```console @@ -1534,17 +1536,17 @@ connections, with at most 10 active at once. Provides complete more quickly when using the accelerated client. Be mindful of how many simultaneous connections this setting can generate. -For nodes without strict connection limits that need to provide large volumes -of content immediately, we recommend enabling the `Routing.AcceleratedDHTClient` and -setting `Provider.WorkerCount` to `0` (unlimited). - > [!CAUTION] -> Raising this value too high may lead to increased load. -> Proceed with caution. +> For nodes without strict connection limits that need to provide large volumes +> of content immediately, we recommend enabling the `Routing.AcceleratedDHTClient` and +> setting `Provider.WorkerCount` to `0` (unlimited). +> +> At the same time, mind that raising this value too high may lead to increased load. +> Proceed with caution, ensure proper hardware and networking are in place. -Default: `16` (`64` if `Routing.AcceleratedDHTClient=true`) +Default: `16` -Type: `integer` (non-negative; `0` means unlimited number of workers) +Type: `optionalInteger` (non-negative; `0` means unlimited number of workers) ## `Pubsub` @@ -1722,11 +1724,11 @@ system. Note: disabling content reproviding will result in other nodes on the network not being able to discover that you have the objects that you have. If you want to have this disabled and keep the network aware of what you have, you must -manually announce your content periodically. +manually announce your content periodically or run your own routing system +and convince users to add it to [`Routing.DelegatedRouters`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingdelegatedrouters). > [!CAUTION] -> Setting `Reprovider.Interval=0` will only disable the periodic reprovides. -> New CIDs will stil lbe announced. To disable both, set [`Provider.Enabled=false`](#providerenabled) as well. +> To maintain backward-compatibility, setting `Reprovider.Interval=0` will also disable Provider system (equivalent of `Provider.Enabled=false`) Default: `22h` (`DefaultReproviderInterval`)