Skip to content

Onion message forwarding#10089

Merged
Roasbeef merged 9 commits intolightningnetwork:masterfrom
gijswijs:onion-messaging-1
Mar 6, 2026
Merged

Onion message forwarding#10089
Roasbeef merged 9 commits intolightningnetwork:masterfrom
gijswijs:onion-messaging-1

Conversation

@gijswijs
Copy link
Copy Markdown
Collaborator

With this PR we add basic forwarding functionality for onion messages. It builds on PR #9868.

It adds OnionMessagePayload struct to the lnwire package.
It also depends on the not yet merged (PR 68)[https://github.com/lightningnetwork/lightning-onion/pull/68] in the lightning-onion package. For now it uses that package from a forked version.

The msgmux endpoint for onion messages is updated to parse the onion message packet, and forward the onion based on the acquired information.

The SubscribeOnionMessages endpoint is updated to pass along any decrypted information. This endpoint is currently solely meant for itests, although it could have practical use in the future.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @gijswijs, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the foundational functionality for forwarding onion messages within the Lightning Network. It integrates a new OnionMessage wire protocol message, enables its routing through the existing Sphinx onion processing infrastructure, and provides RPC endpoints for sending and subscribing to these messages. This work lays the groundwork for future application-layer protocols like BOLT12 offers, allowing for privacy-preserving communication beyond just payments.

Highlights

  • Onion Message Wire Protocol: Introduces a new lnwire.OnionMessage type to the wire protocol, enabling the transmission of onion-encrypted messages between Lightning Network nodes. This message type is distinct from HTLC-carrying onion packets and is designed for application-layer communication.
  • Sphinx Onion Processing Integration: Extends the existing Sphinx onion processing logic within htlcswitch/hop to correctly parse and handle OnionMessage payloads. This includes adapting the hop iterator to recognize onion messages, extracting forwarding information (such as the NextNodeID for node-based routing), and performing message-specific TLV validations.
  • New RPC Endpoints for Onion Messages: Adds SendOnionMessage and SubscribeOnionMessages to the LND RPC API. These new endpoints allow external applications and users to programmatically send onion messages to peers and subscribe to a stream of incoming onion messages, facilitating the development of new privacy-preserving communication features.
  • Dedicated Message Endpoint and Forwarding Logic: Implements a new onion_message.OnionEndpoint that integrates with the msgmux to process incoming lnwire.OnionMessages. This endpoint is responsible for decrypting the onion blob, determining if the message is for the local node or needs forwarding, and then either dispatching it to subscribers or relaying it to the next hop in the blinded path.
  • Enhanced Blinded Path Handling: Introduces specific logic for blinded paths within onion messages, including the addition of NextNodeID to ForwardingInfo. This ensures that onion messages, which do not carry payment-related information like CLTV deltas or amounts, are correctly processed and forwarded along their intended blinded routes.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces onion message forwarding, a significant feature that touches multiple parts of the codebase. The changes are generally well-structured, with new functionality encapsulated in the onion_message package and corresponding updates to lnwire, htlcswitch, and the RPC layer. The inclusion of integration tests for both direct and forwarded onion messages is a great addition. I've identified a few issues that need attention: a critical bug in handling dummy hops for onion messages, a high-severity issue with TLV decoding that could lead to panics, and a medium-severity issue regarding message routing logic that could cause confusion and potential bugs. Addressing these will improve the correctness and maintainability of the new functionality.

@saubyk saubyk added this to lnd v0.20 Jul 22, 2025
@saubyk saubyk moved this to In progress in lnd v0.20 Jul 22, 2025
@gijswijs gijswijs force-pushed the onion-messaging-1 branch 5 times, most recently from 9157266 to 83a36aa Compare September 1, 2025 13:53
@gijswijs gijswijs force-pushed the onion-messaging-1 branch 2 times, most recently from 953b2d8 to 3f475ce Compare September 16, 2025 09:48
@saubyk saubyk added this to the v0.21.0 milestone Sep 24, 2025
@saubyk saubyk added this to v0.21 Sep 24, 2025
@saubyk saubyk removed this from lnd v0.20 Sep 24, 2025
@saubyk saubyk moved this to In progress in v0.21 Sep 24, 2025
@Abdulkbk
Copy link
Copy Markdown
Contributor

Since #9868 has been merged, I think this needs to be updated, wanna take a look.

@ziggie1984 ziggie1984 changed the base branch from master to 0-21-0-staging October 18, 2025 14:48
@gijswijs gijswijs force-pushed the onion-messaging-1 branch 2 times, most recently from 5a7e61d to dbb64f4 Compare October 30, 2025 12:43
@yyforyongyu yyforyongyu force-pushed the 0-21-0-staging branch 2 times, most recently from 86fd4b7 to 57eb251 Compare November 4, 2025 11:50
@lightninglabs-deploy lightninglabs-deploy added severity-critical Requires expert review - security/consensus critical and removed severity-critical Requires expert review - security/consensus critical labels Feb 27, 2026
@lightninglabs-deploy lightninglabs-deploy added severity-critical Requires expert review - security/consensus critical and removed severity-critical Requires expert review - security/consensus critical labels Feb 27, 2026
@gijswijs
Copy link
Copy Markdown
Collaborator Author

gijswijs commented Mar 2, 2026

Running lnd with --protocol.no-onion-messages, I noticed we spawn OnionPeerActor if the remote peer supports onion messages regardless if we support it or not. I'm curious if there's any reason to spawn the actor if we don't support onion messages?.

@Abdulkbk Good catch! In the latest iteration, when --protocol.no-onion-messages is set, s.onionActorFactory is never initialized, it stays nil.

Then in brontide.go, the actor is only spawned when both conditions are met:

if p.remoteFeatures.HasFeature(lnwire.OnionMessagesOptional) &&
    p.cfg.SpawnOnionActor != nil {

So even if the remote peer supports onion messages, the nil check on SpawnOnionActor prevents the actor from being spawned when we've disabled onion messaging. No actors are created and no onion messages are processed or forwarded.

gijswijs added 9 commits March 2, 2026 15:46
The new wire message defines the OnionMessagePayload, FinalHopPayload,
ReplyPath, and related TLV encoding/decoding logic.
Update lightning-onion to commit that includes onion-messaging support.
Adds the NewNonFinalBlindedRouteDataOnionMessage function to create
blinded route data specifically for onion messages.
Initialize a sphinx router without persistent replay protection logging
for onion message processing. Onion messages don't require replay
protection since they don't involve payment routing.
Introduce a fat OnionPeerActor that handles the full onion message
processing pipeline for each peer connection. The actor decodes incoming
onion messages, determines the routing action (forward or deliver),
executes the action via PeerMessageSender, and dispatches updates to
subscribers via OnionMessageUpdateDispatcher.

Key components:
- OnionRouter interface abstracting sphinx router operations
- PeerMessageSender interface for forwarding to other peers
- OnionMessageUpdateDispatcher interface for subscriber notifications
- OnionActorFactory for spawning per-peer actors with shared deps
- Full test suite calling Receive() directly with NoOpReplayLog
Add onion message forwarding capability using the OnionPeerActor for
communication. Messages are routed through a receptionist pattern where
each peer has a dedicated OnionPeerActor for handling message sends.

The OnionEndpoint uses the sphinx router for decoding and decrypting the
onion message packet and the encrypted recipient data in the payload of
the onion messages.
This commit adds a configuration flag to disable onion messaging support.
When set, lnd will:
- Not advertise the onion messages feature bit (39) in init and node
announcements
- Skip creating the OnionEndpoint at server startup
- Not register an onion message handler with peers, so incoming onion
messages are not processed
Add an LRU cache to GraphNodeResolver to avoid repeated database lookups
when resolving SCIDs to node public keys. The cache stores up to 1000
compressed pubkey entries, which is sufficient for typical onion message
forwarding scenarios.

This change also introduces a NewGraphNodeResolver constructor to
properly initialize the cache, replacing direct struct literal usage.
@gijswijs gijswijs force-pushed the onion-messaging-1 branch from fe6d745 to 061b89a Compare March 2, 2026 14:46
@lightninglabs-deploy lightninglabs-deploy added severity-critical Requires expert review - security/consensus critical and removed severity-critical Requires expert review - security/consensus critical labels Mar 2, 2026
@gijswijs
Copy link
Copy Markdown
Collaborator Author

gijswijs commented Mar 2, 2026

This is ready for a final review round.

Status:

  • All CI checks pass (the only "failures" are Coveralls itest coverage decreases of -0.04% to -0.06%, which is cosmetic — unit coverage actually increased by +0.1%)
  • 95 out of 97 review threads have been resolved
  • The PR has been rebased and force-pushed with all feedback addressed

Unresolved threads (2) — both awaiting reviewer response only:

  1. lnwire/onion_msg_payload.go (@ziggie1984) — Suggestion to add ExtraOpaqueData to the struct: The entire payload is a TLV stream with no fixed fields, so there's no concept of "trailing bytes", consistent with other pure-TLV messages like AnnouncementSignatures2. Awaiting ziggie's acknowledgement.
  2. peer/brontide.go (@Roasbeef) — I've been swayed by your code-example and restructured the actor implementation. The actor is now a full end-to-end processing pipeline. So brontide sends the raw message to the actor (that is now tied to the pubkey of the originating node) and the actor takes it from there.

@gijswijs gijswijs requested review from Roasbeef and ziggie1984 March 2, 2026 21:11
Copy link
Copy Markdown
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM ⚡️

@Roasbeef Roasbeef merged commit 392d4c8 into lightningnetwork:master Mar 6, 2026
41 of 45 checks passed
@Abdulkbk
Copy link
Copy Markdown
Contributor

Abdulkbk commented Mar 6, 2026

I had some non-blocking in pending but I guess I'll discard since it's already merged :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

onion routing severity-critical Requires expert review - security/consensus critical

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants