feat: Better self-service commands for DHT providing (#10677)
* Add lastRun, NextRun, move reprovide cmd to routing. * acceleratedDHT logic * changelog * depend on latest boxo --------- Co-authored-by: guillaumemichel <guillaume@michel.id> Co-authored-by: Guillaume Michel <guillaumemichel@users.noreply.github.com>
Sergey Gorbunov committed
Jan 31, 2025 at 18:33 UTC
b35555978d670f81f2996f63a7a92362d65cb6df
15 files changed
+80
-53
core/commands/bitswap.go
+3
-30
@@ -21,10 +21,9 @@ var BitswapCmd = &cmds.Command{
21
},
22
23
Subcommands: map[string]*cmds.Command{
24
- "stat": bitswapStatCmd,
25
- "wantlist": showWantlistCmd,
26
- "ledger": ledgerCmd,
27
- "reprovide": reprovideCmd,
24
+ "stat": bitswapStatCmd,
25
+ "wantlist": showWantlistCmd,
26
+ "ledger": ledgerCmd,
27
},
28
}
29
@@ -200,29 +199,3 @@ prints the ledger associated with a given peer.
199
}),
200
},
201
}
203
-
204
-var reprovideCmd = &cmds.Command{
205
- Helptext: cmds.HelpText{
206
- Tagline: "Trigger reprovider.",
207
- ShortDescription: `
208
-Trigger reprovider to announce our data to network.
209
-`,
210
- },
211
- Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
212
- nd, err := cmdenv.GetNode(env)
213
- if err != nil {
214
- return err
215
- }
216
-
217
- if !nd.IsOnline {
218
- return ErrNotOnline
219
- }
220
-
221
- err = nd.Provider.Reprovide(req.Context)
222
- if err != nil {
223
- return err
224
- }
225
-
226
- return nil
227
- },
228
-}
core/commands/commands_test.go
+1
-1
@@ -20,7 +20,6 @@ func TestCommands(t *testing.T) {
20
"/add",
21
"/bitswap",
22
"/bitswap/ledger",
23
- "/bitswap/reprovide",
23
"/bitswap/stat",
24
"/bitswap/wantlist",
25
"/block",
@@ -72,6 +71,7 @@ func TestCommands(t *testing.T) {
71
"/routing/findpeer",
72
"/routing/findprovs",
73
"/routing/provide",
74
+ "/routing/reprovide",
75
"/diag",
76
"/diag/cmds",
77
"/diag/cmds/clear",
core/commands/routing.go
+28
@@ -42,6 +42,7 @@ var RoutingCmd = &cmds.Command{
42
"get": getValueRoutingCmd,
43
"put": putValueRoutingCmd,
44
"provide": provideRefRoutingCmd,
45
+ "reprovide": reprovideRoutingCmd,
46
},
47
}
48
@@ -235,6 +236,33 @@ var provideRefRoutingCmd = &cmds.Command{
236
Type: routing.QueryEvent{},
237
}
238
239
+var reprovideRoutingCmd = &cmds.Command{
240
+ Status: cmds.Experimental,
241
+ Helptext: cmds.HelpText{
242
+ Tagline: "Trigger reprovider.",
243
+ ShortDescription: `
244
+Trigger reprovider to announce our data to network.
245
+`,
246
+ },
247
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
248
+ nd, err := cmdenv.GetNode(env)
249
+ if err != nil {
250
+ return err
251
+ }
252
+
253
+ if !nd.IsOnline {
254
+ return ErrNotOnline
255
+ }
256
+
257
+ err = nd.Provider.Reprovide(req.Context)
258
+ if err != nil {
259
+ return err
260
+ }
261
+
262
+ return nil
263
+ },
264
+}
265
+
266
func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
267
for _, c := range cids {
268
err := r.Provide(ctx, c, true)
core/commands/stat_provide.go
+20
-4
@@ -10,9 +10,15 @@ import (
10
"github.com/ipfs/boxo/provider"
11
cmds "github.com/ipfs/go-ipfs-cmds"
12
"github.com/ipfs/kubo/core/commands/cmdenv"
13
+ "github.com/libp2p/go-libp2p-kad-dht/fullrt"
14
"golang.org/x/exp/constraints"
15
)
16
17
+type reprovideStats struct {
18
+ provider.ReproviderStats
19
+ fullRT bool
20
+}
21
+
22
var statProvideCmd = &cmds.Command{
23
Helptext: cmds.HelpText{
24
Tagline: "Returns statistics about the node's (re)provider system.",
@@ -38,32 +44,42 @@ This interface is not stable and may change from release to release.
44
if err != nil {
45
return err
46
}
47
+ _, fullRT := nd.DHTClient.(*fullrt.FullRT)
48
42
- if err := res.Emit(stats); err != nil {
49
+ if err := res.Emit(reprovideStats{stats, fullRT}); err != nil {
50
return err
51
}
52
53
return nil
54
},
55
Encoders: cmds.EncoderMap{
49
- cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s *provider.ReproviderStats) error {
56
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s reprovideStats) error {
57
wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
58
defer wtr.Flush()
59
60
fmt.Fprintf(wtr, "TotalProvides:\t%s\n", humanNumber(s.TotalProvides))
61
fmt.Fprintf(wtr, "AvgProvideDuration:\t%s\n", humanDuration(s.AvgProvideDuration))
62
fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
56
- fmt.Fprintf(wtr, "LastReprovideBatchSize:\t%s\n", humanNumber(s.LastReprovideBatchSize))
63
+ if !s.LastRun.IsZero() {
64
+ fmt.Fprintf(wtr, "LastRun:\t%s\n", humanTime(s.LastRun))
65
+ if s.fullRT {
66
+ fmt.Fprintf(wtr, "NextRun:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
67
+ }
68
+ }
69
return nil
70
}),
71
},
60
- Type: provider.ReproviderStats{},
72
+ Type: reprovideStats{},
73
}
74
75
func humanDuration(val time.Duration) string {
76
return val.Truncate(time.Microsecond).String()
77
}
78
79
+func humanTime(val time.Time) string {
80
+ return val.Format("2006-01-02 15:04:05")
81
+}
82
+
83
func humanNumber[T constraints.Float | constraints.Integer](n T) string {
84
nf := float64(n)
85
str := humanSI(nf, 0)
docs/changelogs/v0.34.md
+10
@@ -6,6 +6,8 @@
6
7
- [Overview](#overview)
8
- [🔦 Highlights](#-highlights)
9
+ - [Reprovide command moved to routing](#reprovide-command-moved-to-routing)
10
+ - [Additional stats for Accelerated DHT Reprovides](#additional-stats-for-accelerated-dht-reprovides)
11
- [📝 Changelog](#-changelog)
12
- [👨👩👧👦 Contributors](#-contributors)
13
@@ -13,6 +15,14 @@
15
16
### 🔦 Highlights
17
18
+#### Reprovide command moved to routing
19
+
20
+Moved the `bitswap reprovide` command to `routing reprovide`. ([#10677](https://github.com/ipfs/kubo/pull/10677))
21
+
22
+#### Additional stats for Accelerated DHT Reprovides
23
+
24
+The `stats reprovide` command now shows additional stats for the DHT Accelerated Client, indicating the last and next `reprovide` times. ([#10677](https://github.com/ipfs/kubo/pull/10677))
25
+
26
### 📝 Changelog
27
28
### 👨👩👧👦 Contributors
docs/examples/kubo-as-a-library/go.mod
+1
-1
@@ -7,7 +7,7 @@ go 1.23
7
replace github.com/ipfs/kubo => ./../../..
8
9
require (
10
- github.com/ipfs/boxo v0.27.2
10
+ github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b
11
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12
github.com/libp2p/go-libp2p v0.38.2
13
github.com/multiformats/go-multiaddr v0.14.0
docs/examples/kubo-as-a-library/go.sum
+2
-2
@@ -304,8 +304,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
304
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
305
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
306
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
307
-github.com/ipfs/boxo v0.27.2 h1:sGo4KdwBaMjdBjH08lqPJyt27Z4CO6sugne3ryX513s=
308
-github.com/ipfs/boxo v0.27.2/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
307
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b h1:aHVcNBIAW/eKjnFpwABp+CgbhnYGBnEDdPLN1yYHQX0=
308
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
309
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
310
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
311
github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
go.mod
+1
-1
@@ -22,7 +22,7 @@ require (
22
github.com/hashicorp/go-version v1.7.0
23
github.com/ipfs-shipyard/nopfs v0.0.14
24
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
25
- github.com/ipfs/boxo v0.27.2
25
+ github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b
26
github.com/ipfs/go-block-format v0.2.0
27
github.com/ipfs/go-cid v0.4.1
28
github.com/ipfs/go-cidutil v0.1.0
go.sum
+2
-2
@@ -368,8 +368,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
368
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
369
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
370
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
371
-github.com/ipfs/boxo v0.27.2 h1:sGo4KdwBaMjdBjH08lqPJyt27Z4CO6sugne3ryX513s=
372
-github.com/ipfs/boxo v0.27.2/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
371
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b h1:aHVcNBIAW/eKjnFpwABp+CgbhnYGBnEDdPLN1yYHQX0=
372
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
373
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
374
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
375
github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
test/cli/delegated_routing_v1_http_proxy_test.go
+1
-1
@@ -72,7 +72,7 @@ func TestRoutingV1Proxy(t *testing.T) {
72
73
cidStr := nodes[0].IPFSAddStr(testutils.RandomStr(1000))
74
// Reprovide as initialProviderDelay still ongoing
75
- res := nodes[0].IPFS("bitswap", "reprovide")
75
+ res := nodes[0].IPFS("routing", "reprovide")
76
require.NoError(t, res.Err)
77
res = nodes[1].IPFS("routing", "findprovs", cidStr)
78
assert.Equal(t, nodes[0].PeerID().String(), res.Stdout.Trimmed())
test/cli/delegated_routing_v1_http_server_test.go
+1
-1
@@ -40,7 +40,7 @@ func TestRoutingV1Server(t *testing.T) {
40
cidStr := nodes[2].IPFSAddStr(text)
41
_ = nodes[3].IPFSAddStr(text)
42
// Reprovide as initialProviderDelay still ongoing
43
- res := nodes[3].IPFS("bitswap", "reprovide")
43
+ res := nodes[3].IPFS("routing", "reprovide")
44
require.NoError(t, res.Err)
45
46
cid, err := cid.Decode(cidStr)
test/cli/provider_test.go
+6
-6
@@ -43,7 +43,7 @@ func TestProvider(t *testing.T) {
43
44
cid := nodes[0].IPFSAddStr(time.Now().String())
45
// Reprovide as initialProviderDelay still ongoing
46
- res := nodes[0].IPFS("bitswap", "reprovide")
46
+ res := nodes[0].IPFS("routing", "reprovide")
47
require.NoError(t, res.Err)
48
expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...)
49
})
@@ -72,7 +72,7 @@ func TestProvider(t *testing.T) {
72
73
expectNoProviders(t, cid, nodes[1:]...)
74
75
- nodes[0].IPFS("bitswap", "reprovide")
75
+ nodes[0].IPFS("routing", "reprovide")
76
77
expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...)
78
})
@@ -89,7 +89,7 @@ func TestProvider(t *testing.T) {
89
90
expectNoProviders(t, cid, nodes[1:]...)
91
92
- nodes[0].IPFS("bitswap", "reprovide")
92
+ nodes[0].IPFS("routing", "reprovide")
93
94
expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...)
95
})
@@ -113,7 +113,7 @@ func TestProvider(t *testing.T) {
113
expectNoProviders(t, cidBar, nodes[1:]...)
114
expectNoProviders(t, cidBarDir, nodes[1:]...)
115
116
- nodes[0].IPFS("bitswap", "reprovide")
116
+ nodes[0].IPFS("routing", "reprovide")
117
118
expectNoProviders(t, cidFoo, nodes[1:]...)
119
expectProviders(t, cidBar, nodes[0].PeerID().String(), nodes[1:]...)
@@ -141,7 +141,7 @@ func TestProvider(t *testing.T) {
141
expectNoProviders(t, cidBar, nodes[1:]...)
142
expectNoProviders(t, cidBarDir, nodes[1:]...)
143
144
- nodes[0].IPFS("bitswap", "reprovide")
144
+ nodes[0].IPFS("routing", "reprovide")
145
146
expectNoProviders(t, cidFoo, nodes[1:]...)
147
expectNoProviders(t, cidBar, nodes[1:]...)
@@ -161,7 +161,7 @@ func TestProvider(t *testing.T) {
161
162
expectNoProviders(t, cid, nodes[1:]...)
163
164
- nodes[0].IPFS("bitswap", "reprovide")
164
+ nodes[0].IPFS("routing", "reprovide")
165
166
expectProviders(t, cid, nodes[0].PeerID().String(), nodes[1:]...)
167
})
test/cli/routing_dht_test.go
+1
-1
@@ -85,7 +85,7 @@ func testRoutingDHT(t *testing.T, enablePubsub bool) {
85
t.Parallel()
86
hash := nodes[3].IPFSAddStr("some stuff")
87
// Reprovide as initialProviderDelay still ongoing
88
- res := nodes[3].IPFS("bitswap", "reprovide")
88
+ res := nodes[3].IPFS("routing", "reprovide")
89
require.NoError(t, res.Err)
90
res = nodes[4].IPFS("routing", "findprovs", hash)
91
assert.Equal(t, nodes[3].PeerID().String(), res.Stdout.Trimmed())
test/dependencies/go.mod
+1
-1
@@ -120,7 +120,7 @@ require (
120
github.com/huin/goupnp v1.3.0 // indirect
121
github.com/inconshreveable/mousetrap v1.1.0 // indirect
122
github.com/ipfs/bbloom v0.0.4 // indirect
123
- github.com/ipfs/boxo v0.27.2 // indirect
123
+ github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b // indirect
124
github.com/ipfs/go-block-format v0.2.0 // indirect
125
github.com/ipfs/go-cid v0.4.1 // indirect
126
github.com/ipfs/go-datastore v0.6.0 // indirect
test/dependencies/go.sum
+2
-2
@@ -324,8 +324,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
324
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
325
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
326
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
327
-github.com/ipfs/boxo v0.27.2 h1:sGo4KdwBaMjdBjH08lqPJyt27Z4CO6sugne3ryX513s=
328
-github.com/ipfs/boxo v0.27.2/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
327
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b h1:aHVcNBIAW/eKjnFpwABp+CgbhnYGBnEDdPLN1yYHQX0=
328
+github.com/ipfs/boxo v0.27.3-0.20250131141414-5c158ecc3b0b/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM=
329
github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
330
github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
331
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=