Skip to content

htlcswitch: re-add single decode hop iterator#10665

Merged
ziggie1984 merged 3 commits intolightningnetwork:elle-base-branch-payment-servicefrom
calvinrzachman:decode-hop-iterator-blinding
Apr 15, 2026
Merged

htlcswitch: re-add single decode hop iterator#10665
ziggie1984 merged 3 commits intolightningnetwork:elle-base-branch-payment-servicefrom
calvinrzachman:decode-hop-iterator-blinding

Conversation

@calvinrzachman
Copy link
Copy Markdown
Collaborator

Change Description

This commit revives the singular DecodeHopIterator method on OnionProcessor, which was removed in 42069ef after having been replaced by the batch processed DecodeHopIterators within lnd itself. The singular version of the method is more natural for use by the external invoice registry ("payment service"), which uses the HTLC interception API to receive onions one at a time and decrypts them locally using its own sphinx router. It doesn't have need for the batch version's transaction-based replay log, the id/re-forward parameters, etc. that the channel link uses when processing multiple HTLCs per commitment update.

The old function signature is updated to include updates made since its removal. It accepts the same per-packet fields as DecodeHopIterators (incoming amount, CLTV, and blinding point) so that route blinding is supported.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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 restores a previously removed method for decoding individual onion packets, which is essential for external payment services that process HTLCs one at a time. The re-introduced method has been updated to support modern features like route blinding, ensuring compatibility and enhanced privacy. This change streamlines the integration of external services with the HTLC interception API by providing a more natural and efficient decoding interface.

Highlights

  • Re-introduction of DecodeHopIterator: The DecodeHopIterator method has been re-added to the OnionProcessor to facilitate individual onion packet decoding, primarily for external invoice registries using the HTLC interception API.
  • Updated Method Signature: The re-added DecodeHopIterator method now includes incomingAmount and blindingPoint parameters, enabling support for route blinding.
  • Comprehensive Testing: New tests have been added for DecodeHopIterator to ensure its correct functionality and robust error handling, covering valid onions, truncated packets, corrupted HMACs, and invalid versions.
  • Logging Initialization: The htlcswitch/hop package now has its logging subsystem initialized, providing better observability for hop-related operations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request 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 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. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

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 a new DecodeHopIterator function within the htlcswitch/hop package to decode and process Sphinx onion packets, including support for blinded paths. Comprehensive unit tests for this new functionality have been added, covering various valid and error scenarios. Additionally, the logging setup for the htlcswitch/hop package has been updated to initialize a logger by default, and the mockIteratorDecoder has been adjusted to reflect the new DecodeHopIterator signature. The review feedback suggests improvements related to adhering to line length guidelines for function signatures and calls, simplifying redundant error handling logic, making the blindingPoint.WhenSome call more concise, and updating comments for clarity and detailed documentation of the new exported function.

Comment thread htlcswitch/hop/iterator.go
Comment thread htlcswitch/hop/iterator.go
Comment thread htlcswitch/hop/iterator.go
Comment thread htlcswitch/hop/iterator.go
Comment thread htlcswitch/hop/iterator.go
Comment on lines +244 to +245
noBlinding,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The processor.DecodeHopIterator function call exceeds the recommended line length. Please wrap the arguments according to the style guide (Repository Style Guide, lines 170-186).

				reader, tc.rHash, incomingCltv,
				incomingAmt, noBlinding,

Comment thread htlcswitch/hop/log.go
Comment on lines 11 to 14
// log is a logger that is initialized with no output filters. This
// means the package will not perform any logging by default until the caller
// requests it.
var log btclog.Logger
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The comment for the log variable states that it 'will not perform any logging by default until the caller requests it.' However, the newly added init() function now initializes the logger by default. Please update the comment to reflect this change for clarity.

Suggested change
// log is a logger that is initialized with no output filters. This
// means the package will not perform any logging by default until the caller
// requests it.
var log btclog.Logger
// log is a logger that is initialized with no output filters. This
// means the package will perform logging by default, but the caller can
// customize it using UseLogger.
var log btclog.Logger

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The approach is copied from other lnd subpackage log.go files (like htlcswitch/log.go and funding/log.go) so I think it's probably okay to keep.

@saubyk saubyk added this to v0.21 Mar 25, 2026
@saubyk saubyk moved this to In progress in v0.21 Mar 25, 2026
@bitromortac bitromortac self-requested a review March 25, 2026 20:31
@saubyk saubyk added this to lnd v0.22 Mar 30, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 Mar 30, 2026
@saubyk saubyk moved this from Backlog to In review in lnd v0.22 Mar 30, 2026
@saubyk saubyk removed this from v0.21 Mar 30, 2026
Copy link
Copy Markdown
Collaborator

@bitromortac bitromortac left a comment

Choose a reason for hiding this comment

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

LGTM ⚡

@lightninglabs-deploy
Copy link
Copy Markdown
Collaborator

@calvinrzachman, remember to re-request review from reviewers when ready

@saubyk saubyk requested a review from ziggie1984 April 14, 2026 15:25
Copy link
Copy Markdown
Collaborator

@ziggie1984 ziggie1984 left a comment

Choose a reason for hiding this comment

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

LGTM - had some minor nits

Comment on lines +132 to +136
var (
fwdAmt uint64 = 500_000
outgoingCltv uint32 = 144
)
var payloadBuf bytes.Buffer
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

put this in one var block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

merged both var blocks into one ✅

Comment thread htlcswitch/hop/iterator.go

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
reader := bytes.NewReader(tc.onionBytes)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: the subtests don't call t.Parallel(). The outer test does, and the sphinx router is read-only across all subtests, so parallel execution is safe. lnd style generally includes t.Parallel() as the first line inside each t.Run closure.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

thanks for pointing this out. updated so the subtests now run in parallel.

This commit re-adds the singular DecodeHopIterator method on
OnionProcessor, which was removed in 42069ef as unused within lnd
itself. The method is needed by the external payment service, which
uses the HTLC interception API to receive onions one at a time and
decrypts them locally using its own sphinx router.

The signature accepts the same per-packet fields as DecodeHopIterators
(incoming amount, CLTV, and blinding point) so that route blinding
works out of the box.
Without this, running hop tests in isolation panics because the
package's log variable is nil until the parent htlcswitch package
calls UseLogger during init.
@calvinrzachman calvinrzachman force-pushed the decode-hop-iterator-blinding branch from 203e52f to 24f2b24 Compare April 15, 2026 05:22
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Apr 15, 2026
@github-actions
Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

htlcswitch/* | 3 files | 84 lines changed (excl. tests)

🔴 Critical (3 files)
  • htlcswitch/hop/iterator.go - HTLC forwarding iterator; core payment routing state machine (htlcswitch/*)
  • htlcswitch/hop/log.go - logging for hop iterator package (htlcswitch/*)
  • htlcswitch/mock.go - mock helpers within htlcswitch package (htlcswitch/*)
Excluded from counting (1 file)
  • htlcswitch/hop/iterator_test.go - test file (*_test.go)

Analysis

All non-test files reside under htlcswitch/hop/ and htlcswitch/, mapping to the CRITICAL tier (htlcswitch/* - HTLC forwarding, payment routing state machine). The primary change is iterator.go, which handles per-hop payload parsing at the heart of every forwarded HTLC. Bugs here can directly affect payment reliability, fund safety, and correct routing behaviour.

No severity bumps triggered: 3 non-test files, 84 non-test lines changed (thresholds: >20 files or >500 lines). All files are within a single critical package.


To override, add a severity-override-{critical,high,medium,low} label.
<!-- pr-severity-bot -->

@ziggie1984 ziggie1984 merged commit 519807c into lightningnetwork:elle-base-branch-payment-service Apr 15, 2026
40 of 42 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in lnd v0.22 Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

payments-v2 severity-critical Requires expert review - security/consensus critical

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants