fix dht commands when pubsub routing is enabled
Instead of checking if Routing is a DHT (because it can now be a tiered router and still contain a DHT), stash the DHT in a separate field in the IPFS node (same as we do with the PSRouter). fixes #5197 License: MIT Signed-off-by: Steven Allen <steven@stebalien.com>
Steven Allen committed
Jul 6, 2018 at 23:33 UTC
7df7d1119939fb2f87a34464f45c94e7a181f1ef
3 files changed
+135
-114
core/commands/dht.go
+27
-30
@@ -13,7 +13,6 @@ import (
13
dag "github.com/ipfs/go-ipfs/merkledag"
14
path "github.com/ipfs/go-ipfs/path"
15
16
- ipdht "gx/ipfs/QmNg6M98bwS97SL9ArvrRxKujFps3eV6XvmKgduiYga8Bn/go-libp2p-kad-dht"
16
routing "gx/ipfs/QmPpdpS9fknTBM3qHDcpayU6nYPZQeVjia2fbNrD8YWDe6/go-libp2p-routing"
17
notif "gx/ipfs/QmPpdpS9fknTBM3qHDcpayU6nYPZQeVjia2fbNrD8YWDe6/go-libp2p-routing/notifications"
18
b58 "gx/ipfs/QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY/go-base58-fast/base58"
@@ -26,6 +25,9 @@ import (
25
26
var ErrNotDHT = errors.New("routing service is not a DHT")
27
28
+// TODO: Factor into `ipfs dht` and `ipfs routing`.
29
+// Everything *except `query` goes into `ipfs routing`.
30
+
31
var DhtCmd = &cmds.Command{
32
Helptext: cmdkit.HelpText{
33
Tagline: "Issue commands directly through the DHT.",
@@ -61,8 +63,7 @@ var queryDhtCmd = &cmds.Command{
63
return
64
}
65
64
- dht, ok := n.Routing.(*ipdht.IpfsDHT)
65
- if !ok {
66
+ if n.DHT == nil {
67
res.SetError(ErrNotDHT, cmdkit.ErrNormal)
68
return
69
}
@@ -76,7 +77,7 @@ var queryDhtCmd = &cmds.Command{
77
return
78
}
79
79
- closestPeers, err := dht.GetClosestPeers(ctx, string(id))
80
+ closestPeers, err := n.DHT.GetClosestPeers(ctx, string(id))
81
if err != nil {
82
res.SetError(err, cmdkit.ErrNormal)
83
return
@@ -140,7 +141,7 @@ var queryDhtCmd = &cmds.Command{
141
142
var findProvidersDhtCmd = &cmds.Command{
143
Helptext: cmdkit.HelpText{
143
- Tagline: "Find peers in the DHT that can provide a specific value, given a key.",
144
+ Tagline: "Find peers that can provide a specific value, given a key.",
145
ShortDescription: "Outputs a list of newline-delimited provider Peer IDs.",
146
},
147
@@ -158,9 +159,8 @@ var findProvidersDhtCmd = &cmds.Command{
159
return
160
}
161
161
- dht, ok := n.Routing.(*ipdht.IpfsDHT)
162
- if !ok {
163
- res.SetError(ErrNotDHT, cmdkit.ErrNormal)
162
+ if n.Routing == nil {
163
+ res.SetError(errNotOnline, cmdkit.ErrNormal)
164
return
165
}
166
@@ -186,7 +186,7 @@ var findProvidersDhtCmd = &cmds.Command{
186
outChan := make(chan interface{})
187
res.SetOutput((<-chan interface{})(outChan))
188
189
- pchan := dht.FindProvidersAsync(ctx, c, numProviders)
189
+ pchan := n.Routing.FindProvidersAsync(ctx, c, numProviders)
190
go func() {
191
defer close(outChan)
192
for e := range events {
@@ -406,7 +406,7 @@ func provideKeysRec(ctx context.Context, r routing.IpfsRouting, dserv ipld.DAGSe
406
407
var findPeerDhtCmd = &cmds.Command{
408
Helptext: cmdkit.HelpText{
409
- Tagline: "Query the DHT for all of the multiaddresses associated with a Peer ID.",
409
+ Tagline: "Find the multiaddresses associated with a Peer ID.",
410
ShortDescription: "Outputs a list of newline-delimited multiaddresses.",
411
},
412
@@ -423,9 +423,8 @@ var findPeerDhtCmd = &cmds.Command{
423
return
424
}
425
426
- dht, ok := n.Routing.(*ipdht.IpfsDHT)
427
- if !ok {
428
- res.SetError(ErrNotDHT, cmdkit.ErrNormal)
426
+ if n.Routing == nil {
427
+ res.SetError(errNotOnline, cmdkit.ErrNormal)
428
return
429
}
430
@@ -454,7 +453,7 @@ var findPeerDhtCmd = &cmds.Command{
453
454
go func() {
455
defer close(events)
457
- pi, err := dht.FindPeer(ctx, pid)
456
+ pi, err := n.Routing.FindPeer(ctx, pid)
457
if err != nil {
458
notif.PublishQueryEvent(ctx, ¬if.QueryEvent{
459
Type: notif.QueryError,
@@ -504,14 +503,14 @@ var findPeerDhtCmd = &cmds.Command{
503
504
var getValueDhtCmd = &cmds.Command{
505
Helptext: cmdkit.HelpText{
507
- Tagline: "Given a key, query the DHT for its best value.",
506
+ Tagline: "Given a key, query the routing system for its best value.",
507
ShortDescription: `
508
Outputs the best value for the given key.
509
511
-There may be several different values for a given key stored in the DHT; in
512
-this context 'best' means the record that is most desirable. There is no one
513
-metric for 'best': it depends entirely on the key type. For IPNS, 'best' is
514
-the record that is both valid and has the highest sequence number (freshest).
510
+There may be several different values for a given key stored in the routing
511
+system; in this context 'best' means the record that is most desirable. There is
512
+no one metric for 'best': it depends entirely on the key type. For IPNS, 'best'
513
+is the record that is both valid and has the highest sequence number (freshest).
514
Different key types can specify other 'best' rules.
515
`,
516
},
@@ -529,9 +528,8 @@ Different key types can specify other 'best' rules.
528
return
529
}
530
532
- dht, ok := n.Routing.(*ipdht.IpfsDHT)
533
- if !ok {
534
- res.SetError(ErrNotDHT, cmdkit.ErrNormal)
531
+ if n.Routing == nil {
532
+ res.SetError(errNotOnline, cmdkit.ErrNormal)
533
return
534
}
535
@@ -559,7 +557,7 @@ Different key types can specify other 'best' rules.
557
558
go func() {
559
defer close(events)
562
- val, err := dht.GetValue(ctx, dhtkey)
560
+ val, err := n.Routing.GetValue(ctx, dhtkey)
561
if err != nil {
562
notif.PublishQueryEvent(ctx, ¬if.QueryEvent{
563
Type: notif.QueryError,
@@ -610,10 +608,10 @@ Different key types can specify other 'best' rules.
608
609
var putValueDhtCmd = &cmds.Command{
610
Helptext: cmdkit.HelpText{
613
- Tagline: "Write a key/value pair to the DHT.",
611
+ Tagline: "Write a key/value pair to the routing system.",
612
ShortDescription: `
613
Given a key of the form /foo/bar and a value of any form, this will write that
616
-value to the DHT with that key.
614
+value to the routing system with that key.
615
616
Keys have two parts: a keytype (foo) and the key name (bar). IPNS uses the
617
/ipns keytype, and expects the key name to be a Peer ID. IPNS entries are
@@ -621,7 +619,7 @@ specifically formatted (protocol buffer).
619
620
You may only use keytypes that are supported in your ipfs binary: currently
621
this is only /ipns. Unless you have a relatively deep understanding of the
624
-go-ipfs DHT internals, you likely want to be using 'ipfs name publish' instead
622
+go-ipfs routing internals, you likely want to be using 'ipfs name publish' instead
623
of this.
624
625
Value is arbitrary text. Standard input can be used to provide value.
@@ -644,9 +642,8 @@ NOTE: A value may not exceed 2048 bytes.
642
return
643
}
644
647
- dht, ok := n.Routing.(*ipdht.IpfsDHT)
648
- if !ok {
649
- res.SetError(ErrNotDHT, cmdkit.ErrNormal)
645
+ if n.Routing == nil {
646
+ res.SetError(errNotOnline, cmdkit.ErrNormal)
647
return
648
}
649
@@ -677,7 +674,7 @@ NOTE: A value may not exceed 2048 bytes.
674
675
go func() {
676
defer close(events)
680
- err := dht.PutValue(ctx, key, []byte(data))
677
+ err := n.Routing.PutValue(ctx, key, []byte(data))
678
if err != nil {
679
notif.PublishQueryEvent(ctx, ¬if.QueryEvent{
680
Type: notif.QueryError,
core/core.go
+20
-2
@@ -137,6 +137,7 @@ type IpfsNode struct {
137
138
Floodsub *floodsub.PubSub
139
PSRouter *psrouter.PubsubValueStore
140
+ DHT *dht.IpfsDHT
141
P2P *p2p.P2P
142
143
proc goprocess.Process
@@ -465,6 +466,23 @@ func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost
466
}
467
n.Routing = r
468
469
+ // TODO: I'm not a fan of type assertions like this but the
470
+ // `RoutingOption` system doesn't currently provide access to the
471
+ // IpfsNode.
472
+ //
473
+ // Ideally, we'd do something like:
474
+ //
475
+ // 1. Add some fancy method to introspect into tiered routers to extract
476
+ // things like the pubsub router or the DHT (complicated, messy,
477
+ // probably not worth it).
478
+ // 2. Pass the IpfsNode into the RoutingOption (would also remove the
479
+ // PSRouter case below.
480
+ // 3. Introduce some kind of service manager? (my personal favorite but
481
+ // that requires a fair amount of work).
482
+ if dht, ok := r.(*dht.IpfsDHT); ok {
483
+ n.DHT = dht
484
+ }
485
+
486
if ipnsps {
487
n.PSRouter = psrouter.NewPubsubValueStore(
488
ctx,
@@ -601,8 +619,8 @@ func (n *IpfsNode) teardown() error {
619
closers = append(closers, mount.Closer(n.Mounts.Ipns))
620
}
621
604
- if dht, ok := n.Routing.(*dht.IpfsDHT); ok {
605
- closers = append(closers, dht.Process())
622
+ if n.DHT != nil {
623
+ closers = append(closers, n.DHT.Process())
624
}
625
626
if n.Blocks != nil {
test/sharness/t0170-dht.sh
+88
-82
@@ -7,87 +7,93 @@ test_description="Test dht command"
7
TEST_DHT_VALUE="foobar"
8
TEST_DHT_PATH="/pk/QmbWTwYGcmdyK9CYfNBcfs9nhZs17a6FQ4Y8oea278xx41"
9
10
-# start iptb + wait for peering
11
-NUM_NODES=5
12
-test_expect_success 'init iptb' '
13
- iptb init -n $NUM_NODES --bootstrap=none --port=0
14
-'
15
-
16
-startup_cluster $NUM_NODES
17
-
18
-test_expect_success 'peer ids' '
19
- PEERID_0=$(iptb get id 0) &&
20
- PEERID_2=$(iptb get id 2)
21
-'
22
-
23
-# ipfs dht findpeer <peerID>
24
-test_expect_success 'findpeer' '
25
- ipfsi 1 dht findpeer $PEERID_0 | sort >actual &&
26
- ipfsi 0 id -f "<addrs>" | cut -d / -f 1-5 | sort >expected &&
27
- test_cmp actual expected
28
-'
29
-
30
-# ipfs dht put <key> <value>
31
-test_expect_success 'put with good keys' '
32
- ipfsi 0 dht put "$TEST_DHT_PATH" "$TEST_DHT_VALUE" | sort >putted &&
33
- [ -s putted ] ||
34
- test_fsh cat putted
35
-'
36
-
37
-# ipfs dht get <key>
38
-test_expect_success 'get with good keys' '
39
- HASH="$(echo "hello world" | ipfsi 2 add -q)" &&
40
- ipfsi 2 name publish "/ipfs/$HASH" &&
41
- ipfsi 1 dht get "/ipns/$PEERID_2" | grep -aq "/ipfs/$HASH"
42
-'
43
-
44
-test_expect_success 'put with bad keys fails (issue #5113)' '
45
- ipfsi 0 dht put "foo" "bar" >putted
46
- ipfsi 0 dht put "/pk/foo" "bar" >>putted
47
- ipfsi 0 dht put "/ipns/foo" "bar" >>putted
48
- [ ! -s putted ] ||
49
- test_fsh cat putted
50
-'
51
-
52
-test_expect_failure 'put with bad keys returns error (issue #4611)' '
53
- ! ipfsi 0 dht put "foo" "bar" &&
54
- ! ipfsi 0 dht put "/pk/foo" "bar" &&
55
- ! ipfsi 0 dht put "/ipns/foo" "bar"
56
-'
57
-
58
-test_expect_failure 'get with bad keys (issue #4611)' '
59
- ! ipfsi 0 dht get "foo" &&
60
- ! ipfsi 0 dht get "/pk/foo"
61
-'
62
-
63
-test_expect_success "add a ref so we can find providers for it" '
64
- echo "some stuff" > afile &&
65
- HASH=$(ipfsi 3 add -q afile)
66
-'
67
-
68
-# ipfs dht findprovs <key>
69
-test_expect_success 'findprovs' '
70
- ipfsi 4 dht findprovs $HASH > provs &&
71
- iptb get id 3 > expected &&
72
- test_cmp provs expected
73
-'
74
-
75
-
76
-# ipfs dht query <peerID>
77
-## We query 3 different keys, to statisically lower the chance that the queryer
78
-## turns out to be the closest to what a key hashes to.
79
-# TODO: flaky. tracked by https://github.com/ipfs/go-ipfs/issues/2620
80
-test_expect_success 'query' '
81
- ipfsi 3 dht query "$(echo banana | ipfsi 3 add -q)" >actual &&
82
- ipfsi 3 dht query "$(echo apple | ipfsi 3 add -q)" >>actual &&
83
- ipfsi 3 dht query "$(echo pear | ipfsi 3 add -q)" >>actual &&
84
- PEERS=$(wc -l actual | cut -d '"'"' '"'"' -f 1) &&
85
- [ -s actual ] ||
86
- test_might_fail test_fsh cat actual
87
-'
88
-
89
-test_expect_success 'stop iptb' '
90
- iptb stop
91
-'
10
+test_dht() {
11
+ NUM_NODES=5
12
+
13
+ test_expect_success 'init iptb' '
14
+ rm -rf .iptb/ &&
15
+ iptb init -n $NUM_NODES --bootstrap=none --port=0
16
+ '
17
+
18
+ startup_cluster $NUM_NODES "$@"
19
+
20
+ test_expect_success 'peer ids' '
21
+ PEERID_0=$(iptb get id 0) &&
22
+ PEERID_2=$(iptb get id 2)
23
+ '
24
+
25
+ # ipfs dht findpeer <peerID>
26
+ test_expect_success 'findpeer' '
27
+ ipfsi 1 dht findpeer $PEERID_0 | sort >actual &&
28
+ ipfsi 0 id -f "<addrs>" | cut -d / -f 1-5 | sort >expected &&
29
+ test_cmp actual expected
30
+ '
31
+
32
+ # ipfs dht put <key> <value>
33
+ test_expect_success 'put with good keys' '
34
+ ipfsi 0 dht put "$TEST_DHT_PATH" "$TEST_DHT_VALUE" | sort >putted &&
35
+ [ -s putted ] ||
36
+ test_fsh cat putted
37
+ '
38
+
39
+ # ipfs dht get <key>
40
+ test_expect_success 'get with good keys' '
41
+ HASH="$(echo "hello world" | ipfsi 2 add -q)" &&
42
+ ipfsi 2 name publish "/ipfs/$HASH" &&
43
+ ipfsi 1 dht get "/ipns/$PEERID_2" | grep -aq "/ipfs/$HASH"
44
+ '
45
+
46
+ test_expect_success 'put with bad keys fails (issue #5113)' '
47
+ ipfsi 0 dht put "foo" "bar" >putted
48
+ ipfsi 0 dht put "/pk/foo" "bar" >>putted
49
+ ipfsi 0 dht put "/ipns/foo" "bar" >>putted
50
+ [ ! -s putted ] ||
51
+ test_fsh cat putted
52
+ '
53
+
54
+ test_expect_failure 'put with bad keys returns error (issue #4611)' '
55
+ ! ipfsi 0 dht put "foo" "bar" &&
56
+ ! ipfsi 0 dht put "/pk/foo" "bar" &&
57
+ ! ipfsi 0 dht put "/ipns/foo" "bar"
58
+ '
59
+
60
+ test_expect_failure 'get with bad keys (issue #4611)' '
61
+ ! ipfsi 0 dht get "foo" &&
62
+ ! ipfsi 0 dht get "/pk/foo"
63
+ '
64
+
65
+ test_expect_success "add a ref so we can find providers for it" '
66
+ echo "some stuff" > afile &&
67
+ HASH=$(ipfsi 3 add -q afile)
68
+ '
69
+
70
+ # ipfs dht findprovs <key>
71
+ test_expect_success 'findprovs' '
72
+ ipfsi 4 dht findprovs $HASH > provs &&
73
+ iptb get id 3 > expected &&
74
+ test_cmp provs expected
75
+ '
76
+
77
+
78
+ # ipfs dht query <peerID>
79
+ ## We query 3 different keys, to statisically lower the chance that the queryer
80
+ ## turns out to be the closest to what a key hashes to.
81
+ # TODO: flaky. tracked by https://github.com/ipfs/go-ipfs/issues/2620
82
+ test_expect_success 'query' '
83
+ ipfsi 3 dht query "$(echo banana | ipfsi 3 add -q)" >actual &&
84
+ ipfsi 3 dht query "$(echo apple | ipfsi 3 add -q)" >>actual &&
85
+ ipfsi 3 dht query "$(echo pear | ipfsi 3 add -q)" >>actual &&
86
+ PEERS=$(wc -l actual | cut -d '"'"' '"'"' -f 1) &&
87
+ [ -s actual ] ||
88
+ test_might_fail test_fsh cat actual
89
+ '
90
+
91
+ test_expect_success 'stop iptb' '
92
+ iptb stop
93
+ '
94
+}
95
+
96
+test_dht
97
+test_dht --enable-pubsub-experiment --enable-namesys-pubsub
98
99
test_done