Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In-browser Peer routing with DHT client not working #1621

Closed
2color opened this issue Mar 9, 2023 · 19 comments
Closed

In-browser Peer routing with DHT client not working #1621

2color opened this issue Mar 9, 2023 · 19 comments
Labels
kind/support A question or request for support need/triage Needs initial labeling and prioritization

Comments

@2color
Copy link
Contributor

2color commented Mar 9, 2023

Background

As a user, I want to be able to write browser-based applications that use PeerIDs, e.g. 12D3KooWRBy97UB99e3J6hiPesre1MZeuNQvfan4gBziswrRJsNK to connect to server peers (kubo) over WebTransport.

For js-libp2p to connect to a peer, it needs to resolve a string PeerID to a list of multi-addresses and establish a connection over a protocol supported by the browser, e.g. WebTransport /ip4/77.191.236.66/udp/27432/quic-v1/webtransport/certhash/uEiCHJ1wdNQ6PuWY_q1fZ1xYBk02c8P8vzYKLUB37swCD3g/certhash/uEiCdUXNMurDDZbHMsIBD-wEwuXN1xqT3LuAaS1XyLtEjVQ/p2p/12D3KooWRBy97UB99e3J6hiPesre1MZeuNQvfan4gBziswrRJsNK

This issue is blocking libp2p/universal-connectivity#1

Problem encountered

The problem is that when a js-libp2p node is instantiated with DHT client mode in the browser, and a call is made tolibp2p.dht.findPeer('12D3KooWBdmLJjhpgJ9KZgLM3f894ff9xyBfPvPjFNn7MKJpyrC2'), the response is missing the WebTransport multi addresses.

Specifically, I get:

/ip4/127.0.0.1/tcp/4001
/ip4/127.0.0.1/udp/4001/quic
/ip4/192.168.50.102/tcp/4001
/ip4/192.168.50.102/udp/4001/quic
/ip4/46.21.210.45/tcp/41752
/ip4/46.21.210.45/udp/41752/quic
/ip6/::1/tcp/4001

But why? 🙃

  • I suspect it might have to do with how peer records from the DHT are parsed.
  • Another suspicion is that not all multiaddrs aren't even stored on the DHT. Instead, they come from the identify protocol.
    • Is there a discrepancy between the DHT and the protocols coming from identify?
    • I can get the correct multiaddr with the kubo:
ipfs routing findpeer 12D3KooWBdmLJjhpgJ9KZgLM3f894ff9xyBfPvPjFNn7MKJpyrC2
/ip4/127.0.0.1/udp/4001/quic-v1
/ip4/46.21.210.45/udp/41752/quic-v1
/ip4/46.21.210.45/udp/41752/quic
/ip4/192.168.50.102/udp/4001/quic
/ip4/127.0.0.1/udp/4001/quic
/ip4/192.168.50.102/tcp/4001
/ip4/127.0.0.1/tcp/4001
/ip4/192.168.50.102/udp/4001/quic-v1
/ip4/127.0.0.1/udp/4001/quic-v1/webtransport/certhash/uEiC2VicD86O_HCbSJBdBTowH40qsRNOLoZsHRKUHMtVJVg/certhash/uEiCP5EPex6pTJYAvokykyQ2CKdcABpYsKmvEtMrt4_gLkw
/ip4/46.21.210.45/udp/41752/quic-v1/webtransport/certhash/uEiC2VicD86O_HCbSJBdBTowH40qsRNOLoZsHRKUHMtVJVg/certhash/uEiCP5EPex6pTJYAvokykyQ2CKdcABpYsKmvEtMrt4_gLkw
/ip6/::1/tcp/4001
/ip4/46.21.210.45/tcp/41752
/ip4/192.168.50.102/udp/4001/quic-v1/webtransport/certhash/uEiC2VicD86O_HCbSJBdBTowH40qsRNOLoZsHRKUHMtVJVg/certhash/uEiCP5EPex6pTJYAvokykyQ2CKdcABpYsKmvEtMrt4_gLkw

Reproduction: https://js-libp2p-transports-example-nextjs.vercel.app/

Source: https://github.com/2color/js-libp2p-transports-example/

Package Versions

  ├── @chainsafe/libp2p-noise@11.0.1
  ├── @chainsafe/libp2p-yamux@3.0.7
  ├── @headlessui/react@1.7.13
  ├── @heroicons/react@2.0.16
  ├── @libp2p/bootstrap@6.0.0
  ├── @libp2p/kad-dht@7.0.0
  ├── @libp2p/peer-id@2.0.2
  ├── @libp2p/websockets@5.0.4
  ├── @libp2p/webtransport@1.0.7
  ├── @types/node@18.14.6
  ├── @types/react-dom@18.0.11
  ├── @types/react@18.0.28
  ├── autoprefixer@10.4.13
  ├── blockstore-core@3.0.0
  ├── datastore-core@8.0.4
  ├── datastore-level@9.0.4
  ├── eslint-config-next@13.2.3
  ├── eslint@8.35.0
  ├── libp2p@0.42.2
  ├── next@13.2.3
  ├── postcss@8.4.21
  ├── private-ip@3.0.0
  ├── react-dom@18.2.0
  ├── react@18.2.0
  ├── tailwindcss@3.2.7
  └── typescript@4.9.5

Platform

  • Chrome Version 110.0.5481.177 (Official Build) (arm64)

  • Subsystem: DHT

Severity:

High - The main functionality of the application does not work, API breakage, repo format breakage, etc.

Steps to reproduce the error:

See full reproduction: https://github.com/2color/js-libp2p-transports-example/tree/main/packages/nextjs

@2color 2color added the need/triage Needs initial labeling and prioritization label Mar 9, 2023
@maschad maschad self-assigned this Mar 9, 2023
@2color
Copy link
Contributor Author

2color commented Mar 10, 2023

Based on further investigation, the root cause of this problem is how multiaddrs are published to the DHT.

It seems that non of the quic-v1 multiaddrs are published to the DHT

@maschad
Copy link
Member

maschad commented Mar 10, 2023

Based on further investigation

Thanks for digging into this @2color , but I don't have access to that slack archive, would you be able to post a screenshot of those findings here for reference? Thanks.

@BigLep
Copy link
Contributor

BigLep commented Mar 11, 2023

@maschad : the discussion is in a public channel #ipfs-chatter on Filecoin slack (which is bridged to IPFS Discord/Matrix).

@maschad
Copy link
Member

maschad commented Mar 11, 2023

Thanks for pointing that out @BigLep I will post a link here to the discord chat since that's a bit more accessible

@2color have you also explored whether identify and the peerstore are storing multiaddrs ? Apparently quic-v1 multiaddrs could be filtered out based on the discussion here

@2color
Copy link
Contributor Author

2color commented Mar 11, 2023

have you also explored whether identify and the peerstore are storing multiaddrs ?

I haven't yet. Would love any tips on how to best debug/explore this with js-libp2p

Apparently quic-v1 multiaddrs could be filtered out based on the discussion here

Yeah that seems to be the case. There's a number of things happening here probably causing this:

  • js-libp2p can only connect to nodes with a valid TLS certificate this limits the number of nodes to test with to the libp2p bootstrap nodes and preload nodes.
  • 3 of the bootstrap nodes are running Kubo0.17 and one 0.18.1 (by running ipfs id QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa)
dig +short TXT _dnsaddr.bootstrap.libp2p.io
"dnsaddr=/dnsaddr/sg1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
"dnsaddr=/dnsaddr/sv15.bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"
"dnsaddr=/dnsaddr/am6.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb"
"dnsaddr=/dnsaddr/ny5.bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa
  • 0.17 Kubo nodes don't support quic-v1 multiaddrs.
  • Kubo v0.18 introduced the quic-v1 multiaddrs.

  • When connecting to the 0.18.1 bootstrap node over WSS (which wasn't working yesterday but now fixed), I am able to get the WebTransport addresses! 🎉

@p-shahi
Copy link
Member

p-shahi commented Mar 13, 2023

Issue for upgrading bootstrap nodes to newer Kubo versions: https://github.com/protocol/bifrost-infra/issues/2409

@achingbrain achingbrain added kind/support A question or request for support need/triage Needs initial labeling and prioritization and removed need/triage Needs initial labeling and prioritization labels Mar 14, 2023
@achingbrain
Copy link
Member

@2color I think this can be closed, right? There's no change to js-libp2p necessary here, the remote peer needs to be running kubo 0.18.x to tell you its quic-v1 addresses.

have you also explored whether identify and the peerstore are storing multiaddrs ?

I haven't yet. Would love any tips on how to best debug/explore this with js-libp2p

js-libp2p has a .peerStore property that lets you see what your node knows about a remote peer.

See the example in the jsdoc linked to for how to get that information.

@2color
Copy link
Contributor Author

2color commented Mar 14, 2023

I want to verify this again today.

I also realised that this is very different to delegated routing because this lookup isn't recursive and there are likely not many other nodes the browser can connect to (only WSS and Webtransport), to find the peer record.

@achingbrain
Copy link
Member

there are likely not many other nodes the browser can connect to (only WSS and Webtransport), to find the peer record.

That's correct, and why delegated routing exists - to ask a node that can make more connections (via tcp, quic, etc) to do the lookup operation on your behalf.

This will be less necessary over time, as more network non-browser nodes support listening on webtransport and webrtc addresses.

this lookup isn't recursive

What do you mean by "recursive" in this context?

@maschad maschad removed their assignment Mar 14, 2023
@2color
Copy link
Contributor Author

2color commented Mar 14, 2023

This will be less necessary over time, as more network non-browser nodes support listening on webtransport and webrtc addresses.

Although the initial peer routing will rely on WSS nodes because both WebTransport and WebRTC multiaddrs are ephemeral, and you need to get those from somewhere.

What do you mean by "recursive" in this context?

A proper Kademlia search with multiple hops

@p-shahi
Copy link
Member

p-shahi commented Mar 15, 2023

I saw a PR from achingbrain which disabled autodailing and delegated peer routing here. Did that solve this issue?

@2color
Copy link
Contributor Author

2color commented Mar 15, 2023

Yeah, this is generally working and was likely a problem with the bootstrap nodes running an older version of Kubo.

It's still hard to sometimes tell which connections are actually open in the browser, but that isn't directly related to this issue.

@2color 2color closed this as completed Mar 15, 2023
@AustinFoss
Copy link

AustinFoss commented Jul 3, 2023

Just popping in out of curiosity if you ever managed to get peer routing working in a browser by way of setting the dht to client mode instead of needing to rely on delegated peer routing?

The screen cast video linked in the readme shows two form fields, one for find multiaddrs, and another to connect to a peer using a multiaddr. Currently the master branch's (https://github.com/libp2p/universal-connectivity) front end builds only with the later field so I get the impression peer routing from the browser was removed for the time being?

It seems like this feature is either just recently doable, or still not quite possible, for browser based libp2p nodes.

@BigLep
Copy link
Contributor

BigLep commented Jul 3, 2023

Currently the master branch's front end builds only with the later field so I get the impression peer routing from the browser was removed for the time being?

@AustinFoss : are you referring to https://github.com/libp2p/universal-connectivity ?

@AustinFoss
Copy link

@BigLep Yes, my bad should have been more explicit. Forgot, amidst all my tabs, this issue wasn't over in that repo.

@p-shahi
Copy link
Member

p-shahi commented Jul 5, 2023

Just popping in out of curiosity if you ever managed to get peer routing working in a browser by way of setting the dht to client mode instead of needing to rely on delegated peer routing?

@AustinFoss the universal-connectivity app sets the browser node's DHT to client mode:
https://github.com/libp2p/universal-connectivity/blob/main/packages/frontend/src/lib/libp2p.ts#L78

So all browser nodes in the app function as clients. They rely on the rust-peer, which acts as the DHT server, to discover other peers. Does that help?

@AustinFoss
Copy link

@p-shahi This helps a bit I think. From what I understand from your response there's some feature of the rust implementation of the libp2p node that allows it to act as a kademlia server, and able to provide routing for the browser nodes with kadDHT set to client mode?

Whereas in my test case, because I've only bootstrapped my browser node to the provided bootstrap peers found in all the libp2p examples, even with client mode set I can't utilize this method of peer routing because those default bootstrap nodes don't provide a DHT server?

Is that correct? If so, do kubo/go-ipfs nodes have the ability to act as a DHT server but most just haven't toggled that flag yet?

I'm not super fluent in rust but that line in the rust node's code you linked to I'm not sure where it's enabling the DHT server functionality.

@p-shahi
Copy link
Member

p-shahi commented Jul 11, 2023

This helps a bit I think. From what I understand from your response there's some feature of the rust implementation of the libp2p node that allows it to act as a kademlia server, and able to provide routing for the browser nodes with kadDHT set to client mode?

Yes that's right

I'm not super fluent in rust but that line in the rust node's code you linked to I'm not sure where it's enabling the DHT server functionality.

No worries, the relevant point is the rust-libp2p peer has Kademlia enabled by default in the app. The line I shared shows the rust peer adding addresses to it's routing table.

Whereas in my test case, because I've only bootstrapped my browser node to the provided bootstrap peers found in all the libp2p examples, even with client mode set I can't utilize this method of peer routing because those default bootstrap nodes don't provide a DHT server?
Is that correct? If so, do kubo/go-ipfs nodes have the ability to act as a DHT server but most just haven't toggled that flag yet?

I will direct this question to one of the kubo stewards, perhaps @aschmahmann or @Jorropo ?

@AustinFoss
Copy link

No worries, the relevant point is the rust-libp2p peer has Kademlia enabled by default in the app. The line I shared shows the rust peer adding addresses to it's routing table.

This is another step forward in my understanding, but for further clarity; is this a side effect of the rust implementation of Kademlia over the go implementation, or just a side effect of how the rust/go(kubo) implementations of libp2p use Kademlia? That question might need to wait for the two other contributors you tagged to make a comment.

Something else that might need to wait for them is, if go-libp2p can offer peer routing to connected browser nodes operating with their DHTs set to client mode when will the default bootstrap nodes have this feature enabled? Specficially these ones:

peerDiscovery: [
    bootstrap({
      list: [
        '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
        '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
        '/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
        '/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
        '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
      ]
    })
]

Side note, I'm a aware this might not be the best place to be continuing this discussion; but it is the most relevant issue (open or closed) to what I'm trying to achieve, and with the aim of not fragmenting the discussion I'm just continuing to post replies here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/support A question or request for support need/triage Needs initial labeling and prioritization
Projects
None yet
Development

No branches or pull requests

6 participants