@cryptotaxi247 / kubo / commits / c2bf0f951

feat(provider): resume cycle (#11031)

* bump kad-dht: resume reprovide cycle * daemon: --provide-fresh-start flag * changelog * docs * go-fmt * chore: latest go-libp2p-kad-dht#1170 after conflict resolution, to confirm CI is still green * kad-dht: depend on latest master * move daemon flag to Provider.DHT.ResumeEnabled config * refactor: sweep provider datastore * bump kad-dht * bump kad-dht * bump kad-dht * make datastore keys constant * use kad-dht master * add emoji to changelog entry * go-fmt * bump kad-dht * test(provider): add tests for resume cycle feature validates Provide.DHT.ResumeEnabled behavior: - preserves cycle state when enabled (default) - resets cycle when disabled tests verify current_time_offset across restarts using JSON output --------- Co-authored-by: Marcin Rataj <lidel@lidel.org>

Guillaume Michel committed Oct 29, 2025 at 11:07 UTC c2bf0f9515040b83c09072f30032390c8fa6b5f1
11 files changed +233 -20
config/provide.go
+7
@@ -16,6 +16,7 @@ const (
16 DefaultProvideDHTInterval = 22 * time.Hour // https://github.com/ipfs/kubo/pull/9326
17 DefaultProvideDHTMaxWorkers = 16 // Unified default for both sweep and legacy providers
18 DefaultProvideDHTSweepEnabled = false
19 + DefaultProvideDHTResumeEnabled = true
20 DefaultProvideDHTDedicatedPeriodicWorkers = 2
21 DefaultProvideDHTDedicatedBurstWorkers = 1
22 DefaultProvideDHTMaxProvideConnsPerWorker = 20
@@ -86,6 +87,12 @@ type ProvideDHT struct {
87 // OfflineDelay sets the delay after which the provider switches from Disconnected to Offline state (sweep mode only).
88 // Default: DefaultProvideDHTOfflineDelay
89 OfflineDelay *OptionalDuration `json:",omitempty"`
90 +
91 + // ResumeEnabled controls whether the provider resumes from its previous state on restart.
92 + // When enabled, the provider persists its reprovide cycle state and provide queue to the datastore,
93 + // and restores them on restart. When disabled, the provider starts fresh on each restart.
94 + // Default: true
95 + ResumeEnabled Flag `json:",omitempty"`
96 }
97
98 func ParseProvideStrategy(s string) ProvideStrategy {
core/node/provider.go
+22 -10
@@ -14,6 +14,7 @@ import (
14 "github.com/ipfs/boxo/provider"
15 "github.com/ipfs/go-cid"
16 "github.com/ipfs/go-datastore"
17 + "github.com/ipfs/go-datastore/namespace"
18 "github.com/ipfs/go-datastore/query"
19 "github.com/ipfs/kubo/config"
20 "github.com/ipfs/kubo/repo"
@@ -36,14 +37,21 @@ import (
37 "go.uber.org/fx"
38 )
39
39 -// The size of a batch that will be used for calculating average announcement
40 -// time per CID, inside of boxo/provider.ThroughputReport
41 -// and in 'ipfs stats provide' report.
42 -// Used when Provide.DHT.SweepEnabled=false
43 -const sampledBatchSize = 1000
40 +const (
41 + // The size of a batch that will be used for calculating average announcement
42 + // time per CID, inside of boxo/provider.ThroughputReport
43 + // and in 'ipfs stats provide' report.
44 + // Used when Provide.DHT.SweepEnabled=false
45 + sampledBatchSize = 1000
46
45 -// Datastore key used to store previous reprovide strategy.
46 -const reprovideStrategyKey = "/reprovideStrategy"
47 + // Datastore key used to store previous reprovide strategy.
48 + reprovideStrategyKey = "/reprovideStrategy"
49 +
50 + // Datastore namespace prefix for provider data.
51 + providerDatastorePrefix = "provider"
52 + // Datastore path for the provider keystore.
53 + keystoreDatastorePath = "keystore"
54 +)
55
56 // Interval between reprovide queue monitoring checks for slow reprovide alerts.
57 // Used when Provide.DHT.SweepEnabled=true
@@ -324,10 +332,10 @@ func SweepingProviderOpt(cfg *config.Config) fx.Option {
332 Repo repo.Repo
333 }
334 sweepingReprovider := fx.Provide(func(in providerInput) (DHTProvider, *keystore.ResettableKeystore, error) {
327 - ds := in.Repo.Datastore()
335 + ds := namespace.Wrap(in.Repo.Datastore(), datastore.NewKey(providerDatastorePrefix))
336 ks, err := keystore.NewResettableKeystore(ds,
337 keystore.WithPrefixBits(16),
330 - keystore.WithDatastorePath("/provider/keystore"),
338 + keystore.WithDatastorePath(keystoreDatastorePath),
339 keystore.WithBatchSize(int(cfg.Provide.DHT.KeystoreBatchSize.WithDefault(config.DefaultProvideDHTKeystoreBatchSize))),
340 )
341 if err != nil {
@@ -370,6 +378,8 @@ func SweepingProviderOpt(cfg *config.Config) fx.Option {
378 if inDht != nil {
379 prov, err := ddhtprovider.New(inDht,
380 ddhtprovider.WithKeystore(ks),
381 + ddhtprovider.WithDatastore(ds),
382 + ddhtprovider.WithResumeCycle(cfg.Provide.DHT.ResumeEnabled.WithDefault(config.DefaultProvideDHTResumeEnabled)),
383
384 ddhtprovider.WithReprovideInterval(reprovideInterval),
385 ddhtprovider.WithMaxReprovideDelay(time.Hour),
@@ -403,6 +413,8 @@ func SweepingProviderOpt(cfg *config.Config) fx.Option {
413 }
414 opts := []dhtprovider.Option{
415 dhtprovider.WithKeystore(ks),
416 + dhtprovider.WithDatastore(ds),
417 + dhtprovider.WithResumeCycle(cfg.Provide.DHT.ResumeEnabled.WithDefault(config.DefaultProvideDHTResumeEnabled)),
418 dhtprovider.WithPeerID(impl.Host().ID()),
419 dhtprovider.WithRouter(impl),
420 dhtprovider.WithMessageSender(impl.MessageSender()),
@@ -576,7 +588,7 @@ func SweepingProviderOpt(cfg *config.Config) fx.Option {
588
589 stats := prov.Stats()
590 queuedWorkers = stats.Workers.QueuedPeriodic > 0
579 - queueSize = stats.Queues.PendingRegionReprovides
591 + queueSize = int64(stats.Queues.PendingRegionReprovides)
592
593 // Alert if reprovide queue keeps growing and all periodic workers are busy.
594 // Requires consecutiveAlertsThreshold intervals of sustained growth.
docs/changelogs/v0.39.md
+25
@@ -11,6 +11,7 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
11 - [Overview](#overview)
12 - [🔦 Highlights](#-highlights)
13 - [📊 Detailed statistics for Sweep provider with `ipfs provide stat`](#-detailed-statistics-for-sweep-provider-with-ipfs-provide-stat)
14 + - [⏯️ Provider resume cycle for improved reproviding reliability](#provider-resume-cycle-for-improved-reproviding-reliability)
15 - [🔔 Sweep provider slow reprovide warnings](#-sweep-provider-slow-reprovide-warnings)
16 - [🔧 Fixed UPnP port forwarding after router restarts](#-fixed-upnp-port-forwarding-after-router-restarts)
17 - [🖥️ RISC-V support with prebuilt binaries](#️-risc-v-support-with-prebuilt-binaries)
@@ -64,6 +65,30 @@ provider statistics instead of the default WAN DHT stats.
65 > [`Provide.DHT.SweepEnabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providedhtsweepenabled)).
66 > Legacy provider shows basic statistics without flag support.
67
68 +#### ⏯️ Provider resume cycle for improved reproviding reliability
69 +
70 +When using the sweeping provider (`Provide.DHT.SweepEnabled`), Kubo now
71 +persists the reprovide cycle state and automatically resumes where it left off
72 +after a restart. This brings several improvements:
73 +
74 +- **Persistent progress**: The provider now saves its position in the reprovide
75 +cycle to the datastore. On restart, it continues from where it stopped instead
76 +of starting from scratch.
77 +- **Catch-up reproviding**: If the node was offline for an extended period, all
78 +CIDs that haven't been reprovided within the configured reprovide interval are
79 +immediately queued for reproviding when the node starts up. This ensures
80 +content availability is maintained even after downtime.
81 +- **Persistent provide queue**: The provide queue is now persisted to the
82 +datastore on shutdown. When the node restarts, queued CIDs are restored and
83 +provided as expected, preventing loss of pending provide operations.
84 +- **Resume control**: The resume behavior is now controlled via the
85 +`Provide.DHT.ResumeEnabled` config option (default: `true`). If you don't want
86 +to keep the persisted provider state from a previous run, you can set
87 +`Provide.DHT.ResumeEnabled=false` in your config.
88 +
89 +This feature significantly improves the reliability of content providing,
90 +especially for nodes that experience intermittent connectivity or restarts.
91 +
92 #### 🔔 Sweep provider slow reprovide warnings
93
94 Kubo now monitors DHT reprovide operations when `Provide.DHT.SweepEnabled=true`
docs/config.md
+46 -1
@@ -132,6 +132,7 @@ config file at runtime.
132 - [`Provide.DHT.MaxWorkers`](#providedhtmaxworkers)
133 - [`Provide.DHT.Interval`](#providedhtinterval)
134 - [`Provide.DHT.SweepEnabled`](#providedhtsweepenabled)
135 + - [`Provide.DHT.ResumeEnabled`](#providedhtresumeenabled)
136 - [`Provide.DHT.DedicatedPeriodicWorkers`](#providedhtdedicatedperiodicworkers)
137 - [`Provide.DHT.DedicatedBurstWorkers`](#providedhtdedicatedburstworkers)
138 - [`Provide.DHT.MaxProvideConnsPerWorker`](#providedhtmaxprovideconnsperworker)
@@ -2139,6 +2140,17 @@ gets batched by keyspace region. The keystore is periodically refreshed at each
2140 [`Provide.Strategy`](#providestrategy) to ensure only current content remains
2141 scheduled. This handles cases where content is unpinned or removed.
2142
2143 +**Persistent reprovide cycle state:** When Provide Sweep is enabled, the
2144 +reprovide cycle state is persisted to the datastore by default. On restart, Kubo
2145 +automatically resumes from where it left off. If the node was offline for an
2146 +extended period, all CIDs that haven't been reprovided within the configured
2147 +[`Provide.DHT.Interval`](#providedhtinterval) are immediately queued for
2148 +reproviding. Additionally, the provide queue is persisted on shutdown and
2149 +restored on startup, ensuring no pending provide operations are lost. If you
2150 +don't want to keep the persisted provider state from a previous run, you can
2151 +disable this behavior by setting [`Provide.DHT.ResumeEnabled`](#providedhtresumeenabled)
2152 +to `false`.
2153 +
2154 > <picture>
2155 > <source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/f6e06b08-7fee-490c-a681-1bf440e16e27">
2156 > <source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/e1662d7c-f1be-4275-a9ed-f2752fcdcabe">
@@ -2163,9 +2175,42 @@ Default: `false`
2175
2176 Type: `flag`
2177
2178 +#### `Provide.DHT.ResumeEnabled`
2179 +
2180 +Controls whether the provider resumes from its previous state on restart. Only
2181 +applies when `Provide.DHT.SweepEnabled` is true.
2182 +
2183 +When enabled (the default), the provider persists its reprovide cycle state and
2184 +provide queue to the datastore, and restores them on restart. This ensures:
2185 +
2186 +- The reprovide cycle continues from where it left off instead of starting over
2187 +- Any CIDs in the provide queue during shutdown are restored and provided after
2188 +restart
2189 +- CIDs that missed their reprovide window while the node was offline are queued
2190 +for immediate reproviding
2191 +
2192 +When disabled, the provider starts fresh on each restart, discarding any
2193 +previous reprovide cycle state and provide queue. On a fresh start, all CIDs
2194 +matching the [`Provide.Strategy`](#providestrategy) will be provided ASAP (as
2195 +burst provides), and then keyspace regions are reprovided according to the
2196 +regular schedule starting from the beginning of the reprovide cycle.
2197 +
2198 +> [!NOTE]
2199 +> Disabling this option means the provider will provide all content matching
2200 +> your strategy on every restart (which can be resource-intensive for large
2201 +> datasets), then start from the beginning of the reprovide cycle. For nodes
2202 +> with large datasets or frequent restarts, keeping this enabled (the default)
2203 +> is recommended for better resource efficiency and more consistent reproviding
2204 +> behavior.
2205 +
2206 +Default: `true`
2207 +
2208 +Type: `flag`
2209 +
2210 #### `Provide.DHT.DedicatedPeriodicWorkers`
2211
2168 -Number of workers dedicated to periodic keyspace region reprovides. Only applies when `Provide.DHT.SweepEnabled` is true.
2212 +Number of workers dedicated to periodic keyspace region reprovides. Only
2213 +applies when `Provide.DHT.SweepEnabled` is true.
2214
2215 Among the [`Provide.DHT.MaxWorkers`](#providedhtmaxworkers), this
2216 number of workers will be dedicated to the periodic region reprovide only. The sum of
docs/examples/kubo-as-a-library/go.mod
+1 -1
@@ -115,7 +115,7 @@ require (
115 github.com/libp2p/go-doh-resolver v0.5.0 // indirect
116 github.com/libp2p/go-flow-metrics v0.3.0 // indirect
117 github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
118 - github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781 // indirect
118 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 // indirect
119 github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect
120 github.com/libp2p/go-libp2p-pubsub v0.14.2 // indirect
121 github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -434,8 +434,8 @@ github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl9
434 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
435 github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
436 github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
437 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781 h1:oTzgZExvlcixPXIXO7Knojv5yYoBB5SMLUmgtNzBGfY=
438 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
437 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 h1:xZj18PsLD157snR/BFo547jwOkGDH7jZjMEkBDOoD4Q=
438 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
439 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
440 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
441 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
go.mod
+1 -1
@@ -53,7 +53,7 @@ require (
53 github.com/libp2p/go-doh-resolver v0.5.0
54 github.com/libp2p/go-libp2p v0.44.0
55 github.com/libp2p/go-libp2p-http v0.5.0
56 - github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781
56 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32
57 github.com/libp2p/go-libp2p-kbucket v0.8.0
58 github.com/libp2p/go-libp2p-pubsub v0.14.2
59 github.com/libp2p/go-libp2p-pubsub-router v0.6.0
go.sum
+2 -2
@@ -518,8 +518,8 @@ github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qk
518 github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA=
519 github.com/libp2p/go-libp2p-http v0.5.0 h1:+x0AbLaUuLBArHubbbNRTsgWz0RjNTy6DJLOxQ3/QBc=
520 github.com/libp2p/go-libp2p-http v0.5.0/go.mod h1:glh87nZ35XCQyFsdzZps6+F4HYI6DctVFY5u1fehwSg=
521 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781 h1:oTzgZExvlcixPXIXO7Knojv5yYoBB5SMLUmgtNzBGfY=
522 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
521 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 h1:xZj18PsLD157snR/BFo547jwOkGDH7jZjMEkBDOoD4Q=
522 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
523 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
524 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
525 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
test/cli/provider_test.go
+124
@@ -3,6 +3,7 @@ package cli
3 import (
4 "bytes"
5 "encoding/json"
6 + "fmt"
7 "net/http"
8 "net/http/httptest"
9 "strings"
@@ -608,6 +609,124 @@ func runProviderSuite(t *testing.T, reprovide bool, apply cfgApplier) {
609 })
610 }
611
612 +// runResumeTests validates Provide.DHT.ResumeEnabled behavior for SweepingProvider.
613 +//
614 +// Background: The provider tracks current_time_offset = (now - cycleStart) % interval
615 +// where cycleStart is the timestamp marking the beginning of the reprovide cycle.
616 +// With ResumeEnabled=true, cycleStart persists in the datastore across restarts.
617 +// With ResumeEnabled=false, cycleStart resets to 'now' on each startup.
618 +func runResumeTests(t *testing.T, apply cfgApplier) {
619 + t.Helper()
620 +
621 + const (
622 + reprovideInterval = 30 * time.Second
623 + initialRuntime = 10 * time.Second // Let cycle progress
624 + downtime = 5 * time.Second // Simulated offline period
625 + restartTime = 2 * time.Second // Daemon restart stabilization
626 +
627 + // Thresholds account for timing jitter (~2-3s margin)
628 + minOffsetBeforeRestart = 8 * time.Second // Expect ~10s
629 + minOffsetAfterResume = 12 * time.Second // Expect ~17s (10s + 5s + 2s)
630 + maxOffsetAfterReset = 5 * time.Second // Expect ~2s (fresh start)
631 + )
632 +
633 + setupNode := func(t *testing.T, resumeEnabled bool) *harness.Node {
634 + node := harness.NewT(t).NewNode().Init()
635 + apply(node) // Sets Provide.DHT.SweepEnabled=true
636 + node.SetIPFSConfig("Provide.DHT.ResumeEnabled", resumeEnabled)
637 + node.SetIPFSConfig("Provide.DHT.Interval", reprovideInterval.String())
638 + node.SetIPFSConfig("Bootstrap", []string{})
639 + node.StartDaemon()
640 + return node
641 + }
642 +
643 + t.Run("preserves cycle state across restart", func(t *testing.T) {
644 + t.Parallel()
645 +
646 + node := setupNode(t, true)
647 + defer node.StopDaemon()
648 +
649 + for i := 0; i < 10; i++ {
650 + node.IPFSAddStr(fmt.Sprintf("resume-test-%d-%d", i, time.Now().UnixNano()))
651 + }
652 +
653 + time.Sleep(initialRuntime)
654 +
655 + beforeRestart := node.IPFS("provide", "stat", "--enc=json")
656 + offsetBeforeRestart, _, err := parseProvideStatJSON(beforeRestart.Stdout.String())
657 + require.NoError(t, err)
658 + require.Greater(t, offsetBeforeRestart, minOffsetBeforeRestart,
659 + "cycle should have progressed")
660 +
661 + node.StopDaemon()
662 + time.Sleep(downtime)
663 + node.StartDaemon()
664 + time.Sleep(restartTime)
665 +
666 + afterRestart := node.IPFS("provide", "stat", "--enc=json")
667 + offsetAfterRestart, _, err := parseProvideStatJSON(afterRestart.Stdout.String())
668 + require.NoError(t, err)
669 +
670 + assert.GreaterOrEqual(t, offsetAfterRestart, minOffsetAfterResume,
671 + "offset should account for downtime")
672 + })
673 +
674 + t.Run("resets cycle when disabled", func(t *testing.T) {
675 + t.Parallel()
676 +
677 + node := setupNode(t, false)
678 + defer node.StopDaemon()
679 +
680 + for i := 0; i < 10; i++ {
681 + node.IPFSAddStr(fmt.Sprintf("no-resume-%d-%d", i, time.Now().UnixNano()))
682 + }
683 +
684 + time.Sleep(initialRuntime)
685 +
686 + beforeRestart := node.IPFS("provide", "stat", "--enc=json")
687 + offsetBeforeRestart, _, err := parseProvideStatJSON(beforeRestart.Stdout.String())
688 + require.NoError(t, err)
689 + require.Greater(t, offsetBeforeRestart, minOffsetBeforeRestart,
690 + "cycle should have progressed")
691 +
692 + node.StopDaemon()
693 + time.Sleep(downtime)
694 + node.StartDaemon()
695 + time.Sleep(restartTime)
696 +
697 + afterRestart := node.IPFS("provide", "stat", "--enc=json")
698 + offsetAfterRestart, _, err := parseProvideStatJSON(afterRestart.Stdout.String())
699 + require.NoError(t, err)
700 +
701 + assert.Less(t, offsetAfterRestart, maxOffsetAfterReset,
702 + "offset should reset to near zero")
703 + })
704 +}
705 +
706 +type provideStatJSON struct {
707 + Sweep struct {
708 + Timing struct {
709 + CurrentTimeOffset int64 `json:"current_time_offset"` // nanoseconds
710 + } `json:"timing"`
711 + Schedule struct {
712 + NextReprovidePrefix string `json:"next_reprovide_prefix"`
713 + } `json:"schedule"`
714 + } `json:"Sweep"`
715 +}
716 +
717 +// parseProvideStatJSON extracts timing and schedule information from
718 +// the JSON output of 'ipfs provide stat --enc=json'.
719 +// Note: prefix is unused in current tests but kept for potential future use.
720 +func parseProvideStatJSON(output string) (offset time.Duration, prefix string, err error) {
721 + var stat provideStatJSON
722 + if err := json.Unmarshal([]byte(output), &stat); err != nil {
723 + return 0, "", err
724 + }
725 + offset = time.Duration(stat.Sweep.Timing.CurrentTimeOffset)
726 + prefix = stat.Sweep.Schedule.NextReprovidePrefix
727 + return offset, prefix, nil
728 +}
729 +
730 func TestProvider(t *testing.T) {
731 t.Parallel()
732
@@ -637,6 +756,11 @@ func TestProvider(t *testing.T) {
756 t.Run(v.name, func(t *testing.T) {
757 // t.Parallel()
758 runProviderSuite(t, v.reprovide, v.apply)
759 +
760 + // Resume tests only apply to SweepingProvider
761 + if v.name == "SweepingProvider" {
762 + runResumeTests(t, v.apply)
763 + }
764 })
765 }
766 }
test/dependencies/go.mod
+1 -1
@@ -184,7 +184,7 @@ require (
184 github.com/libp2p/go-flow-metrics v0.3.0 // indirect
185 github.com/libp2p/go-libp2p v0.44.0 // indirect
186 github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
187 - github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781 // indirect
187 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 // indirect
188 github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect
189 github.com/libp2p/go-libp2p-record v0.3.1 // indirect
190 github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
test/dependencies/go.sum
+2 -2
@@ -468,8 +468,8 @@ github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqA
468 github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
469 github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
470 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
471 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781 h1:oTzgZExvlcixPXIXO7Knojv5yYoBB5SMLUmgtNzBGfY=
472 -github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251028150720-c3f8d33dc781/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
471 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 h1:xZj18PsLD157snR/BFo547jwOkGDH7jZjMEkBDOoD4Q=
472 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
473 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
474 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
475 github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg=