@cryptotaxi247 / kubo / commits / 7df7d1119

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, &notif.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, &notif.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, &notif.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