Skip to content

batteries: Allow wrapping the MessageRouter in ChannelManagerConstructor - #183

Draft
Synesso wants to merge 1 commit into
lightningdevkit:mainfrom
Synesso:message-router-wrapper
Draft

batteries: Allow wrapping the MessageRouter in ChannelManagerConstructor#183
Synesso wants to merge 1 commit into
lightningdevkit:mainfrom
Synesso:message-router-wrapper

Conversation

@Synesso

@Synesso Synesso commented Aug 1, 2026

Copy link
Copy Markdown

ChannelManagerConstructor hardcodes DefaultMessageRouter for onion message path finding, with no way to customize it. This mirrors the existing RouterWrapper hook (which covers the payment Router) with a MessageRouterWrapper for the onion MessageRouter.

Motivation

DefaultMessageRouter::find_path only returns paths whose first hop is a directly connected peer. Nodes that restrict outbound connections (e.g. for egress-policy reasons) cannot act on Event::ConnectionNeeded, so onion messages to unconnected destinations — BOLT 12 invoice requests in particular — buffer forever. Such deployments instead route onion messages through a trusted forwarding peer by prefixing the path with a connected node, which requires substituting the MessageRouter handed to the OnionMessenger (and ChannelManager).

Today the only options are vendoring a modified copy of ChannelManagerConstructor or reconstructing ChannelManager/OnionMessenger/PeerManager/BackgroundProcessor by hand: the msg_router field is private, concretely typed DefaultMessageRouter, and the OnionMessenger built in chain_sync_completed is not exposed. (We are currently carrying such a vendored copy.)

Design

Follows RouterWrapper as closely as possible:

  • New MessageRouterWrapper interface with find_path and create_blinded_paths, each receiving the DefaultMessageRouter the constructor would otherwise have used, so implementations can delegate for any case they don't want to customize.
  • Both constructors take a @Nullable MessageRouterWrapper parameter, immediately after router_wrapper. null preserves existing behavior exactly.
  • The msg_router field becomes MessageRouter (it was only ever consumed via as_MessageRouter()).

Like the original RouterWrapper addition, this changes the public constructor signatures. Happy to add overloads preserving the old signatures instead if that's preferred.

ChannelManagerConstructor hardcodes DefaultMessageRouter for onion
message path finding, with no way to customize it. Nodes that restrict
outbound connections cannot act on Event::ConnectionNeeded, so onion
messages (e.g. BOLT 12 invoice requests) to unconnected destinations
buffer forever. Such deployments route onion messages through a trusted
forwarding peer by prefixing the path with a connected node, which
requires substituting the MessageRouter handed to the OnionMessenger
and ChannelManager.

Add a MessageRouterWrapper hook mirroring the existing RouterWrapper
pattern: a nullable constructor parameter whose find_path and
create_blinded_paths receive the DefaultMessageRouter the constructor
would otherwise have used, so implementations can delegate any case
they don't want to customize. Passing null preserves existing behavior
exactly.

Amp-Thread-ID: https://ampcode.com/threads/T-019fac05-3d6f-75ca-9581-2c17d12954db
Co-authored-by: Amp <amp@ampcode.com>
@Synesso

Synesso commented Aug 3, 2026

Copy link
Copy Markdown
Author

The CI failures here are pre-existing (upstream main is red for the same reasons). Opened #184 to repair the fixable ones — MSRV pins for unicode-ident/proc-macro2, retired macos-13 runners, and regenerated checked-in C# sources. The remaining bins-repo 404s (git.bitcoin.ninja) need maintainer-published binaries.

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.

1 participant