Skip to content

feat: Add wasm support#1

Merged
nasdf merged 7 commits intosourcenetwork:masterfrom
nasdf:wasm
May 7, 2026
Merged

feat: Add wasm support#1
nasdf merged 7 commits intosourcenetwork:masterfrom
nasdf:wasm

Conversation

@nasdf
Copy link
Copy Markdown
Member

@nasdf nasdf commented Apr 29, 2026

This PR adds wasm build support. It also adds a wasm compatible version of the webtransport implementation.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 53e086bd-644c-4614-a267-009832066fa0

📥 Commits

Reviewing files that changed from the base of the PR and between 8a1214f and f224241.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (1)
  • go.mod

📝 Walkthrough

Walkthrough

Removes monolithic defaults and replaces them with platform-specific default implementations; introduces JS/WASM WebTransport implementations and stubs for WebRTC, and applies build tags to gate WebRTC/WebTransport files between js and non-js builds.

Changes

Defaults split

Layer / File(s) Summary
Data Shape / API
defaults.go
Removed previously centralized exported defaults: DefaultTransports, DefaultPrivateTransports, DefaultListenAddrs.
Platform Implementations
defaults_js.go, defaults_other.go
Added js-specific defaults (defaults_js.go) enabling WebTransport dialing and no-op private transports; added non-js defaults (defaults_other.go) composing TCP/QUIC/WS/WebTransport/WebRTC and default listen addresses.
Module deps
go.mod
Added github.com/sourcenetwork/goji v0.0.10 dependency.

WebRTC: non-js gating

Layer / File(s) Summary
Build gating
p2p/transport/webrtc/...
connection.go, fingerprint.go, hex.go, hex_test.go, listener.go, logger.go, sdp.go, sdp_test.go, stream.go, stream_read.go, stream_test.go, stream_write.go, transport.go, transport_test.go
Added //go:build !js build constraints so these files are excluded from js builds.

WebRTC: js stub

Layer / File(s) Summary
Stub API
p2p/transport/webrtc/stub_js.go
Added a //go:build js WebRTC stub exposing WebRTCTransport and associated Option/ListenUDPFn types and methods; constructor and operations return errNotSupported / no-op behavior for js builds.

WebTransport: non-js gating

Layer / File(s) Summary
Build gating
p2p/transport/webtransport/...
cert_manager.go, cert_manager_test.go, crypto.go, crypto_test.go, listener.go, mock_connection_gater_test.go, multiaddr.go, multiaddr_test.go, noise_early_data.go, stream.go, transport.go, transport_test.go
Added //go:build !js constraints so these implementations/tests are excluded from js builds.

WebTransport: js implementations

Layer / File(s) Summary
Connection/session/stream primitives
p2p/transport/webtransport/conn_js.go, session_js.go, stream_js.go
Added js-only connection/session/stream types implementing libp2p transport interfaces backed by WebTransport runtime values and stream reader/writer halves.
Listener
p2p/transport/webtransport/listener_js.go
Added js-only noop listener that rewrites unspecified IPs to loopback and exposes Multiaddr/Accept/Close semantics.
Multiaddr helpers & validator
p2p/transport/webtransport/multiaddr_js.go
Added conversion helpers, certhash extraction and IsWebtransportMultiaddr validator (js-only).
Noise early-data handler
p2p/transport/webtransport/noise_early_data_js.go
Added js-only early-data handler implementing noise.EarlyDataHandler to surface protobuf noise extensions.
Transport implementation
p2p/transport/webtransport/transport_js.go
Added js-only WebTransport transport: New constructor, Dial flow that builds HTTPS URL/SNI, opens WebTransport session, opens stream, runs Noise SecureOutbound with early-data verification of certificate hashes, and returns a libp2p capable connection.
Non-js counterparts gated
p2p/transport/webtransport/conn.go, .../crypto.go, .../transport.go
Non-js implementations are now build-gated (!js) and thus separated from js code above.

Tests gating

Layer / File(s) Summary
Test build constraints
p2p/test/webtransport/webtransport_test.go, p2p/transport/webtransport/*_test.go, p2p/transport/webrtc/*_test.go, p2p/transport/webrtc/*
Added //go:build !js to various test files so they are excluded from js builds where appropriate.

Sequence Diagram(s)

sequenceDiagram
    participant Client as JS Client
    participant T as WebTransport Transport
    participant S as WebTransport Session
    participant N as Noise
    participant C as libp2p Connection

    Client->>T: Dial(multiaddr with certhashes)
    T->>T: parse SNI, build HTTPS URL
    T->>S: Open WebTransport session (URL, expected certs)
    S-->>T: session ready
    T->>S: openStream()
    S-->>T: bidirectional stream
    T->>N: SecureOutbound(stream) with early-data handler
    N->>T: request early data
    T-->>N: provide cert hashes (from multiaddr / protobuf)
    N->>N: complete handshake & verify certs
    N-->>T: secure stream
    T->>C: wrap secure stream into CapableConn
    T-->>Client: return CapableConn
Loading
sequenceDiagram
    participant App as Application
    participant Config as libp2p Config
    participant Defaults as Platform Defaults
    participant Stack as Transport Stack

    App->>Config: create Config
    Config->>Defaults: Apply defaults (build-tagged)
    alt js build
        Defaults->>Stack: WebTransport only
    else non-js build
        Defaults->>Stack: TCP, QUIC, WS, WebTransport, WebRTC
    end
    Defaults-->>Config: set ListenAddrs / Transports
    Config-->>App: configured node
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

Suggested tag: v0.48.0

This is the first release of this module.

Cutting a Release (and modifying code files)

This PR is modifying both version.json and code files (not markdown, YAML, TOML or lock files).
The Release Checker is not able to analyse files that are not checked in to master. This might cause the above analysis to be inaccurate.
Please consider performing all the code changes in a separate PR before cutting the release.

Automatically created GitHub Release

Pre-creating GitHub Releases on release PRs initiated from forks is not supported.
If you wish to prepare release notes yourself, you should create a draft GitHub Release for tag v0.48.0 manually.
The draft GitHub Release is going to be published when this PR is merged.
If you choose not to create a draft GitHub Release, a published GitHub Released is going to be created when this PR is merged.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
go.mod (1)

3-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

CI is blocked by Go toolchain mismatch against the module directive.

go.mod declares go 1.25.7, but your pipeline reports a max supported version of 1.16, so go mod tidy cannot pass in current CI. Please align CI Go version (preferred) or lower the module directive if that compatibility is intentional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 3, The module directive in go.mod currently reads "go 1.25.7"
which is incompatible with CI's Go toolchain; either update your CI toolchain to
a Go version that supports 1.25.7 or change the go directive in go.mod to the
maximum supported CI version (e.g., "go 1.16") so commands like go mod tidy
succeed; locate the go directive line in go.mod and edit it to the chosen
supported version, then re-run the CI steps.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@p2p/transport/webtransport/listener_js.go`:
- Around line 15-16: The Accept method currently returns the package-local
sentinel errListenerClosed instead of the shared sentinel tpt.ErrListenerClosed;
update Accept (and any other returns using errListenerClosed on lines around the
Accept implementation) to return tpt.ErrListenerClosed so callers receive the
standard listener-closed sentinel; remove or stop using the local var
errListenerClosed in favor of the shared tpt.ErrListenerClosed in
listener_js.go.

In `@p2p/transport/webtransport/stream_js.go`:
- Around line 47-63: In Read, after calling s.read(b) (the call to s.read), mark
s.readAny = true if n > 0 immediately before handling err so that any delivered
bytes are recorded even when s.read returns both bytes and errInputStream; then
continue the existing error handling (if err != nil and err.Error() ==
errInputStream set s.done = true and return io.EOF, else return n, err). Keep
the rest of the logic (the s.done precheck and final return) unchanged and only
move the readAny assignment to occur right after observing n > 0.

In `@p2p/transport/webtransport/transport_js.go`:
- Around line 154-159: The current code defers s.Close() immediately after
calling sess.openStream, which closes the underlying stream before upgrade
returns and thus returns a ConnSecurity backed by a closed stream; remove the
unconditional defer s.Close() in the upgrade path and instead ensure the stream
is closed only on error (e.g., close s if sess.openStream or subsequent upgrade
steps fail) so that when upgrade returns successfully the returned ConnSecurity
still owns an open stream; look for usages of sess.openStream, s.Close(), and
the upgrade function/ConnSecurity return to implement this change.
- Around line 161-163: The callback passed to t.noise.WithSessionOptions via
noise.EarlyData and newEarlyDataReceiver dereferences the protobuf extensions
(pb.NoiseExtensions) without checking for nil, which can panic when Received
supplies a nil payload; update the early-data handler inside
newEarlyDataReceiver (the function receiving *pb.NoiseExtensions) to first guard
`if b == nil` (or similarly check b.WebtransportCerthashes) and return a
controlled error or nil to cleanly abort the handshake, otherwise proceed to
call decodeCertHashesFromProtobuf on b.WebtransportCerthashes.
- Around line 137-143: The dial function builds the URL using sni but currently
drops any port from host; update the url construction in transport.dial to
preserve the advertised port when sni is used by extracting the port from host
(e.g. via net.SplitHostPort or equivalent) and appending it to the sni
(sni:port) before formatting the URL with webtransportHTTPEndpoint, falling back
to sni alone if no port present; leave the host branch unchanged and ensure the
resulting URL still includes "?type=noise".

---

Outside diff comments:
In `@go.mod`:
- Line 3: The module directive in go.mod currently reads "go 1.25.7" which is
incompatible with CI's Go toolchain; either update your CI toolchain to a Go
version that supports 1.25.7 or change the go directive in go.mod to the maximum
supported CI version (e.g., "go 1.16") so commands like go mod tidy succeed;
locate the go directive line in go.mod and edit it to the chosen supported
version, then re-run the CI steps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b0e677b5-ddc8-402b-ae19-b8ab8a26beb7

📥 Commits

Reviewing files that changed from the base of the PR and between 1556c91 and a45096d.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (40)
  • defaults.go
  • defaults_js.go
  • defaults_other.go
  • go.mod
  • p2p/test/webtransport/webtransport_test.go
  • p2p/transport/webrtc/connection.go
  • p2p/transport/webrtc/fingerprint.go
  • p2p/transport/webrtc/hex.go
  • p2p/transport/webrtc/hex_test.go
  • p2p/transport/webrtc/listener.go
  • p2p/transport/webrtc/logger.go
  • p2p/transport/webrtc/sdp.go
  • p2p/transport/webrtc/sdp_test.go
  • p2p/transport/webrtc/stream.go
  • p2p/transport/webrtc/stream_read.go
  • p2p/transport/webrtc/stream_test.go
  • p2p/transport/webrtc/stream_write.go
  • p2p/transport/webrtc/stub_js.go
  • p2p/transport/webrtc/transport.go
  • p2p/transport/webrtc/transport_test.go
  • p2p/transport/webtransport/cert_manager.go
  • p2p/transport/webtransport/cert_manager_test.go
  • p2p/transport/webtransport/conn.go
  • p2p/transport/webtransport/conn_js.go
  • p2p/transport/webtransport/crypto.go
  • p2p/transport/webtransport/crypto_test.go
  • p2p/transport/webtransport/listener.go
  • p2p/transport/webtransport/listener_js.go
  • p2p/transport/webtransport/mock_connection_gater_test.go
  • p2p/transport/webtransport/multiaddr.go
  • p2p/transport/webtransport/multiaddr_js.go
  • p2p/transport/webtransport/multiaddr_test.go
  • p2p/transport/webtransport/noise_early_data.go
  • p2p/transport/webtransport/noise_early_data_js.go
  • p2p/transport/webtransport/session_js.go
  • p2p/transport/webtransport/stream.go
  • p2p/transport/webtransport/stream_js.go
  • p2p/transport/webtransport/transport.go
  • p2p/transport/webtransport/transport_js.go
  • p2p/transport/webtransport/transport_test.go
💤 Files with no reviewable changes (1)
  • defaults.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: go-check / All
  • GitHub Check: go-test / ubuntu (go 1.26.x)
  • GitHub Check: go-test / ubuntu (go 1.25.x)
  • GitHub Check: go-test / macos (go 1.25.x)
  • GitHub Check: go-test / macos (go 1.26.x)
  • GitHub Check: go-test / windows (go 1.25.x)
  • GitHub Check: go-test / windows (go 1.26.x)
  • GitHub Check: Run transport interoperability tests
🧰 Additional context used
🪛 GitHub Actions: Upstream Test
go.mod

[error] 1-1: go mod tidy failed: go.mod file indicates go 1.25, but maximum supported version is 1.16.

🔇 Additional comments (34)
p2p/transport/webrtc/logger.go (1)

1-2: Build constraint is correctly scoped for wasm/js compatibility.

//go:build !js cleanly prevents native WebRTC logger code from being compiled into js/wasm targets, which aligns with the PR’s transport split strategy.

go.mod (1)

57-57: goji direct dependency looks correctly scoped for wasm/js transport paths.

This addition is consistent with the js-gated imports in p2p/transport/webtransport/session_js.go, p2p/transport/webtransport/transport_js.go, and p2p/transport/webtransport/stream_js.go.

p2p/transport/webtransport/mock_connection_gater_test.go (1)

1-1: Build constraint is correctly scoped.

Good call adding the !js guard for this generated test mock so js/wasm builds don’t pull in non-applicable test code.

p2p/transport/webrtc/sdp.go (1)

1-1: !js tag placement looks correct.

This keeps the native SDP path out of js/wasm builds and matches the introduced platform separation.

p2p/transport/webtransport/cert_manager.go (1)

1-1: Build gating here is appropriate.

Restricting cert-manager implementation to non-js targets is consistent with wasm/browser constraints.

p2p/transport/webtransport/multiaddr_js.go (2)

18-53: Helper conversion/parsing path looks solid.

UDP enforcement plus explicit multibase/multihash decode errors is a good, defensive shape for JS WebTransport address handling.


55-89: State-machine validation is clear and maintainable.

The ordered protocol progression (udp -> quic-v1 -> webtransport) with certhash counting is straightforward and easy to reason about.

p2p/transport/webtransport/multiaddr.go (1)

1-1: Non-js guard is correct.

This cleanly avoids symbol collision with the new js-specific multiaddr implementation.

p2p/transport/webrtc/stub_js.go (1)

3-52: Stub design is well structured for js/wasm compatibility.

Matching the non-js constructor/type signatures while returning a consistent unsupported error is the right tradeoff for platform-limited builds.

p2p/transport/webrtc/fingerprint.go (1)

1-1: Build tag update is correct here.

Excluding this fingerprint implementation from js aligns with the new js stub strategy.

p2p/transport/webrtc/listener.go (1)

1-1: !js constraint is appropriate for this listener implementation.

This cleanly routes js/wasm builds to the stub transport and avoids native runtime assumptions.

p2p/transport/webrtc/transport_test.go (1)

1-2: LGTM! Build constraint correctly excludes WebRTC tests from JS builds.

The //go:build !js constraint properly gates this test file from JS/WASM compilation, aligning with the PR's strategy of providing separate JS-specific implementations.

p2p/transport/webrtc/sdp_test.go (1)

1-2: LGTM! Consistent build constraint pattern.

The build tag correctly excludes SDP tests from JS builds, maintaining consistency with the broader PR pattern.

p2p/transport/webrtc/stream.go (1)

1-2: LGTM! Build constraint correctly applied to implementation.

The !js tag properly excludes the non-JS WebRTC stream implementation, allowing for the JS-specific alternative mentioned in the PR summary.

p2p/transport/webtransport/crypto_test.go (1)

1-2: LGTM! WebTransport crypto tests appropriately gated.

The build constraint correctly excludes crypto tests from JS builds, consistent with the PR's platform-specific implementation strategy.

p2p/transport/webtransport/transport_test.go (1)

1-2: LGTM! Consistent gating of WebTransport tests.

The build tag properly excludes transport tests from JS compilation, maintaining the PR's clean separation between platform implementations.

p2p/transport/webtransport/stream.go (1)

1-2: LGTM! WebTransport stream implementation correctly gated.

The !js constraint appropriately excludes the non-JS stream implementation, aligning with the PR's platform-specific architecture.

p2p/transport/webtransport/multiaddr_test.go (1)

1-2: LGTM! Multiaddr tests appropriately excluded from JS builds.

The build constraint correctly gates these tests from JS compilation, consistent with the overall PR pattern.

p2p/transport/webtransport/listener.go (1)

1-2: LGTM! WebTransport listener correctly gated from JS builds.

The !js build constraint properly excludes the non-JS listener implementation. This completes a consistent pattern across all 8 files in this review, cleanly separating platform-specific implementations for WASM support.

p2p/transport/webrtc/connection.go (1)

1-2: LGTM! Build constraint correctly gates WebRTC for non-JS platforms.

The //go:build !js constraint appropriately excludes this Pion-based WebRTC connection implementation from JavaScript/WASM builds, where the browser's native WebRTC APIs would be used instead.

p2p/transport/webrtc/transport.go (1)

1-2: LGTM! Build constraint properly isolates platform-specific WebRTC transport.

The build tag ensures this implementation is excluded from JS builds, complementing the stub implementation in stub_js.go.

p2p/transport/webrtc/stream_test.go (1)

1-2: LGTM! Test gating aligns with implementation platform constraints.

The build tag correctly prevents these Pion WebRTC-dependent tests from running on JS/WASM targets.

p2p/transport/webtransport/conn.go (1)

1-2: LGTM! Build constraint enables platform-specific WebTransport connection implementations.

The constraint appropriately separates the quic-go-based connection (non-JS) from the browser API-based implementation (JS).

p2p/transport/webtransport/cert_manager_test.go (1)

1-2: LGTM! Certificate manager tests appropriately excluded from browser builds.

Browser-based WebTransport handles certificates differently, making these tests inapplicable to JS environments.

p2p/transport/webtransport/transport.go (1)

1-2: LGTM! Transport build constraint enables platform-appropriate WebTransport implementations.

The constraint correctly separates the full-featured transport (with Listen support) from the browser-based client-only implementation.

p2p/transport/webtransport/noise_early_data.go (1)

1-2: LGTM! Build constraint appropriately splits server and client-only early data handling.

The constraint correctly separates the full implementation (with newEarlyDataSender for servers) from the JS client-only version that omits server-side functionality.

p2p/test/webtransport/webtransport_test.go (1)

1-2: LGTM! Integration test correctly excluded from browser environments.

The test exercises Listen and certificate management features unavailable in browsers, making the build constraint appropriate.

p2p/transport/webrtc/hex_test.go (1)

1-1: !js test gating looks correct.

This build constraint cleanly keeps these tests aligned with the non-JS WebRTC hex implementation.

p2p/transport/webrtc/stream_write.go (1)

1-1: Build tag split is appropriate here.

Keeping this write path out of JS builds matches the platform-specific transport split.

p2p/transport/webrtc/stream_read.go (1)

1-1: !js guard is a good fit.

This prevents non-applicable WebRTC stream-read code from entering JS/WASM builds.

p2p/transport/webrtc/hex.go (1)

1-1: Non-JS build constraint is consistent.

No concerns with scoping this implementation to non-JS targets.

p2p/transport/webtransport/crypto.go (1)

1-1: !js gating is correct for this crypto path.

This cleanly separates non-JS certificate logic from JS/WASM transport code.

p2p/transport/webtransport/conn_js.go (1)

39-95: CapableConn implementation shape looks solid.

The delegation pattern to session plus explicit interface assertion is clean and consistent for the JS transport path.

p2p/transport/webtransport/session_js.go (1)

16-69: Session lifecycle and stream wiring are clear and well-scoped.

The split between ready, openStream, acceptStream, and close is easy to follow and fits the JS transport abstraction.

Comment thread p2p/transport/webtransport/listener_js.go Outdated
Comment thread p2p/transport/webtransport/stream_js.go
Comment thread p2p/transport/webtransport/transport_js.go
Comment thread p2p/transport/webtransport/transport_js.go
Comment thread p2p/transport/webtransport/transport_js.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@p2p/transport/webtransport/stream_js.go`:
- Around line 68-85: The current read and Write methods snapshot deadlines and
call reader.ReadContext / writer.WriteContext on a context that won't be
canceled if SetReadDeadline/SetWriteDeadline/SetDeadline is called while an I/O
is in flight; change to per-direction cancellable context management: add
per-direction cancellation state (e.g., readCancel and writeCancel fields,
protected by a mutex or atomic) and have
SetReadDeadline/SetWriteDeadline/SetDeadline call the existing cancel to abort
any in-progress ReadContext/WriteContext before installing the new deadline;
update stream.read and stream.Write to create a context whose cancel func is
stored in the per-direction field so deadline updates can cancel the in-flight
operation via the stored cancel and then cleared appropriately.

In `@p2p/transport/webtransport/transport_js.go`:
- Around line 87-89: CanDial currently returns true for WebTransport multiaddrs
even when Dial will fail due to unsupported certhashes; update CanDial (in
transport.CanDial) to perform the same certhash support check that Dial uses
(i.e., call IsWebtransportMultiaddr and then verify the multiaddr contains at
least one JS-supported certhash) and return false if no supported certhashes are
present so that undialable addresses are rejected up front.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d36e151a-f48a-424d-8788-1ad09fe6f4cb

📥 Commits

Reviewing files that changed from the base of the PR and between a45096d and 8a1214f.

📒 Files selected for processing (3)
  • p2p/transport/webtransport/listener_js.go
  • p2p/transport/webtransport/stream_js.go
  • p2p/transport/webtransport/transport_js.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • p2p/transport/webtransport/listener_js.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: go-check / All
  • GitHub Check: go-test / ubuntu (go 1.25.x)
  • GitHub Check: go-test / macos (go 1.26.x)
  • GitHub Check: go-test / macos (go 1.25.x)
  • GitHub Check: go-test / windows (go 1.25.x)
  • GitHub Check: go-test / windows (go 1.26.x)
  • GitHub Check: go-test / ubuntu (go 1.26.x)
  • GitHub Check: Run transport interoperability tests

Comment on lines +68 to +85
func (s *stream) read(b []byte) (int, error) {
deadline := s.readDeadline.Load()
if deadline == nil {
return s.reader.Read(b)
}
ctx, cancel := context.WithDeadline(context.Background(), *deadline)
defer cancel()
return s.reader.ReadContext(ctx, b)
}

func (s *stream) Write(b []byte) (int, error) {
deadline := s.writeDeadline.Load()
if deadline == nil {
return s.writer.Write(b)
}
ctx, cancel := context.WithDeadline(context.Background(), *deadline)
defer cancel()
return s.writer.WriteContext(ctx, b)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Deadline changes only affect future I/O, not blocked calls.

read and Write snapshot the current deadline once and then block on that context. If another goroutine calls SetReadDeadline, SetWriteDeadline, or SetDeadline while a Read/Write is already in progress, the in-flight operation keeps waiting on the old context and may never unblock when the caller expects it to.

This needs per-direction cancellation state so deadline updates can cancel the currently running ReadContext / WriteContext, not just the next call.

Also applies to: 91-117

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@p2p/transport/webtransport/stream_js.go` around lines 68 - 85, The current
read and Write methods snapshot deadlines and call reader.ReadContext /
writer.WriteContext on a context that won't be canceled if
SetReadDeadline/SetWriteDeadline/SetDeadline is called while an I/O is in
flight; change to per-direction cancellable context management: add
per-direction cancellation state (e.g., readCancel and writeCancel fields,
protected by a mutex or atomic) and have
SetReadDeadline/SetWriteDeadline/SetDeadline call the existing cancel to abort
any in-progress ReadContext/WriteContext before installing the new deadline;
update stream.read and stream.Write to create a context whose cancel func is
stored in the per-direction field so deadline updates can cancel the in-flight
operation via the stored cancel and then cleared appropriately.

Comment on lines +87 to +89
func (t *transport) CanDial(addr ma.Multiaddr) bool {
ok, _ := IsWebtransportMultiaddr(addr)
return ok
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make CanDial reject undialable JS WebTransport addresses.

Dial hard-fails when the multiaddr has no supported certhashes, but CanDial still returns true for the same address. That violates the transport contract here and lets address selection pick this transport for dials that can never succeed on wasm.

Suggested fix
 func (t *transport) CanDial(addr ma.Multiaddr) bool {
 	ok, _ := IsWebtransportMultiaddr(addr)
-	return ok
+	if !ok {
+		return false
+	}
+	certHashes, err := extractCertHashes(addr)
+	return err == nil && len(certHashes) > 0
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@p2p/transport/webtransport/transport_js.go` around lines 87 - 89, CanDial
currently returns true for WebTransport multiaddrs even when Dial will fail due
to unsupported certhashes; update CanDial (in transport.CanDial) to perform the
same certhash support check that Dial uses (i.e., call IsWebtransportMultiaddr
and then verify the multiaddr contains at least one JS-supported certhash) and
return false if no supported certhashes are present so that undialable addresses
are rejected up front.

@nasdf nasdf requested a review from fredcarle May 6, 2026 15:49
Copy link
Copy Markdown

@fredcarle fredcarle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nasdf nasdf merged commit 936d69f into sourcenetwork:master May 7, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants