Description
routerrpc.HtlcInterceptor currently receives forwarded HTLCs after onion/payload parsing, but before the normal outgoing forwarding checks in Switch.handlePacketForward / CheckHtlcForward.
This means an interceptor client can see HTLCs that lnd would later reject if the client replies with RESUME. One simple example is a normal forwarded HTLC where incoming_amount_msat < outgoing_amount_msat. Today this is rejected later by the forwarding policy checks, but it is still visible to the interceptor first.
The current behavior is understandable if the intended contract of RESUME is "stop holding this HTLC and continue lnd's default forwarding path." But it can be surprising for interceptor clients and operators that treat RESUME as an explicit approval decision. If downstream forwarding policy behavior changes in the future, a client that blindly resumes could appear to opt into behavior it never explicitly validated.
Questions
- Should basic non-policy invariants, such as
incoming_amount_msat >= outgoing_amount_msat for normal forwarded HTLCs, be enforced before the HTLC is offered to the interceptor?
- Should this be opt-in to preserve compatibility with
RESUME_MODIFIED or custom/aux traffic use cases?
- Should the API docs make clearer that
RESUME is not an approval, but a handoff back to lnd's default forwarding path?
- Should there be a stricter mode where the interceptor only sees forwards that pass basic lnd forwarding sanity checks?
Relevant Code Paths
channelLink.processRemoteAdds decodes the onion/payload and builds the forwarded packet.
InterceptableSwitch.ForwardPackets exposes forwarded packets to the interceptor.
interceptedForward.Resume sends the packet to Switch.ForwardPackets.
Switch.handlePacketForward / CheckHtlcForward later reject insufficient fees and cases such as incoming_amount_msat < outgoing_amount_msat.
Motivation
The goal is to clarify the API contract and discuss whether some basic sanity checks should happen before interception, especially for cases that are not really policy preferences but fundamental forwarding invariants for normal HTLC traffic.
Description
routerrpc.HtlcInterceptorcurrently receives forwarded HTLCs after onion/payload parsing, but before the normal outgoing forwarding checks inSwitch.handlePacketForward/CheckHtlcForward.This means an interceptor client can see HTLCs that lnd would later reject if the client replies with
RESUME. One simple example is a normal forwarded HTLC whereincoming_amount_msat < outgoing_amount_msat. Today this is rejected later by the forwarding policy checks, but it is still visible to the interceptor first.The current behavior is understandable if the intended contract of
RESUMEis "stop holding this HTLC and continue lnd's default forwarding path." But it can be surprising for interceptor clients and operators that treatRESUMEas an explicit approval decision. If downstream forwarding policy behavior changes in the future, a client that blindly resumes could appear to opt into behavior it never explicitly validated.Questions
incoming_amount_msat >= outgoing_amount_msatfor normal forwarded HTLCs, be enforced before the HTLC is offered to the interceptor?RESUME_MODIFIEDor custom/aux traffic use cases?RESUMEis not an approval, but a handoff back to lnd's default forwarding path?Relevant Code Paths
channelLink.processRemoteAddsdecodes the onion/payload and builds the forwarded packet.InterceptableSwitch.ForwardPacketsexposes forwarded packets to the interceptor.interceptedForward.Resumesends the packet toSwitch.ForwardPackets.Switch.handlePacketForward/CheckHtlcForwardlater reject insufficient fees and cases such asincoming_amount_msat < outgoing_amount_msat.Motivation
The goal is to clarify the API contract and discuss whether some basic sanity checks should happen before interception, especially for cases that are not really policy preferences but fundamental forwarding invariants for normal HTLC traffic.