-
Notifications
You must be signed in to change notification settings - Fork 28
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
WebRTC exploration #396
WebRTC exploration #396
Conversation
@@ -43,8 +44,14 @@ export default function Layout() { | |||
|
|||
const layoutVariant = useBreakpointValue({ | |||
base: ( | |||
<Tabs height="100%" width={'100%'} index={state.tabIndex} onChange={handleTabsChange}> | |||
<TabList height="5%" width="100%" justifyContent={'space-around'}> | |||
<Tabs width={'100%'} index={state.tabIndex} onChange={handleTabsChange}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick note that the simple chat tab is only visible in a mobile equivalent view.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted all of the browser layout changes -- they were just a part of the process for me figuring things out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest thing I'm wondering about is do we need to have the webrtc stuff embedded in the client and protocol? We're kind of breaking the modular transport concept by introducing all these special checks for webRTC in client
and protocol
and ideally all of that would be handled within the hybridTransport
class. I've offered some ideas in my comments so let me know if there's a way I can further help.
packages/portalnetwork/package.json
Outdated
@@ -54,10 +52,17 @@ | |||
"@ethereumjs/common": "^3.0.0", | |||
"@ethereumjs/tx": "^4.0.0", | |||
"@ethereumjs/util": "^8.0.0", | |||
"@libp2p/bootstrap": "6.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are all these now devDependencies? Don't we need them installed in order to use the waku/libp2p stuff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved them all up to dependencies. I'll admit that my grasp of the difference between dependencies and devDependencies is a bit fuzzy...
@@ -25,7 +25,7 @@ jobs: | |||
with: | |||
node-version: 16 | |||
cache: 'npm' | |||
|
|||
- run: npm i -g @mapbox/node-pre-gyp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this build step? Is there some browser dependency that needs node-gyp or is this leftover from when you were using the older webtorrent tracker library?
toHexString(enr.get('rtc')!) === '0x01' | ||
) { | ||
this.logger.extend('RTC')('Adding RTC conneection') | ||
await this.client.discv5.sessionService.transport.connectWebRTC(enr.nodeId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to move this whole thing down to the transport layer somehow? Ideally, the protocol layer stuff shouldn't need to worry about which transport layer we're using. Could you move the webRTC
maps up from webRTC.ts
to hybridTransport.ts
and then use the multiaddr or nodeId passed into client.discv5.session.transport.send
to figure out whether to go with webRTC or websocket->UDP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in fact this was not necessary here at all, as it is happening in the transport itself now. Deleting these lines should not have an affect
this.webRTC.closeAll() | ||
} | ||
|
||
async send(to: Multiaddr, toId: string, packet: IPacket, rtc?: boolean) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted in my other comment, instead of adding a new parameter to the transport interface for send
here, can we just keep a Map<nodeId, webRTCcontactinfo>
inside this class and determine whether to use webrtc or websockets here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, agreed. I tried several solutions to the "PING from unknown node" problem, and that rtc parameter was one of the clunkier ones. the webrtc transport does already keep a map of nodeId > RTCConnection.
- run: npm i -g @mapbox/node-pre-gyp | ||
- run: npm i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be removed. I mentioned this at some point, but a lot of older webrtc npm packages (simple-peer, etc.) use a package called wrtc
, which will not build without this node-pre-gyp
thing installed in the system. I'm pretty sure I've removed anything that referenced that package, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed. deleted those changes and the build works fine.
The My own testing hasn't exposed any issues with the webrtc transports, so I'd be confident merging this with your approval. |
Fine by me. I added |
does that work?? i found that i needed It may just look like me building it from scratch in typescript. maybe i'll get famous on npm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I should have explained --
the cli npm run test:integration
triggers the previous integration test adapted for the nodejs client.
While this test does pass locally, it never worked (wouldn't actually run) in the CI checks.
The other model that was already in place, the "devnet-cli-test", has always worked, and I think as it is now, it does cover the same ground as the old integration tests
@acolytec3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! We still need to work on the race conditions in the contentWriter
but this can be addressed later.
WebRTC
PR to explore WebRTC use in Transport Layer
Hybrid Transport Service
Browser clients can now use a hybrid transport layer. This adds the capacity to connect directly to other browser-clients.
LibP2P / Waku
NodeId
@waku/interfaces
Encoder/DecoderPING
packet to the peer'sNodeId
on the WAKULightPush
protocolLightPush
protocol. Discv5 packets received this way are handled usingtransport.emit('packet', ...)
just like those received any other way.The WAKU LightPush part was built using core
@waku
and@libp2p
packages.The WebRTC part was built from scratch using mozilla web api (https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
#### ENRTo advertise that a node is available for RTC connections, we add 1 byte to the ENR likeENR.set('rtc', 0x01)
. When sending a packet, we look for this bit in a peer's ENR, and then route the outgoing packet either to an rtc datachannel, or to the websocket proxy.This part was removed as unnecessary
Embedding a webrtc tag in the ENR does not fully provide a way to route outgoing packets in all scenarios, so this part was dropped. The transport layer does not have access to the discv5 routing table, nor does it directly interact with ENR. This also failed to address scenarios where we have received a packet from a peer who's ENR is not yet known (1st PING).
Instead, the first time the hybrid transport handles an incoming packet from a new
Multiaddr
, it will Map that multiaddr to the type of transport (websocket vs. rtc) from which it was received. The hybrid "Send" function will check that map to determine how to send packets to that peer.Without any RTC tag in the ENR...
When we PING an unknown node we will not yet know which transport it supports. In this case we will send the PING packet out along both transports. When a response is received, we then know which transport (websocket or webrtc) this peer supports.
The PING is sent first over WAKU to prioritize webrtc connections among hybrid Ultralight nodes.
Proxy / Multiaddr
The websocket proxy has been edited to listen for an event emitted from the connecting websocket to set the port number. This way, the udp port number can be selected during PortalNetwork.create(), instead of randomly by the Proxy.
CLI
Small edits made to fix some build issues. A CLI client can now connect to a browser-client running in normal mode.
Browser
Small layout changes. Header now displays address, nodeId, and ENR.
Routing table display will distinguish between RTC peers and websocket peers. RTC connected peers will be highlighted a different color, and have the
RTC
tag in the last column.Issue: routing table view does not reliably display all peers
Two browsers may connect, but both may not appear in the display
They are connected. The issue is in the react components
To test
npm run start-proxy
npm run start-browser-client
localhost:8080
- clients should start and connect to external bootnodes, quickly building a routing table
COPY ENR
from one browser, and paste intoconnect to peer
input on other page.clients should connect over waku, perform discv5 handshake, perform webrtc handshake, and add eachother to their routing tables
You can now test using the Peer-Tools or Get-Block-By functions in the browser