Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Fuzz multi-part payments by joostjager · Pull Request #4367 · lightningdevkit/rust-lightning · GitHub
Skip to content

Fuzz multi-part payments - #4367

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels
Feb 9, 2026
Merged

Fuzz multi-part payments#4367
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
joostjager:fuzz-multi-channels

Conversation

@joostjager

@joostjagerjoostjager commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Increases fuzz coverage for multi-path payments in chanmon_consistency. Helpful for increasing confidence that #4345 (which makes use of async persistence) is stable to use.

Changes

  • Expand chanmon_consistency from 2 to 6 channels (3 per peer pair)
  • Add MPP payment fuzzing commands (0x70-0x74) that split payments across multiple channels, with variants for direct, single-hop, and multi-hop paths
  • Assert no stuck payments after settling all state

@ldk-reviews-bot

ldk-reviews-bot commented Feb 2, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@codecov

codecovBot commented Feb 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.03%. Comparing base (372ba65) to head (0a6b6d4).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #4367 +/- ##
==========================================
- Coverage 86.04% 86.03% -0.02% 
==========================================
Files 156 156 Lines 103002 103002 Branches 103002 103002 ==========================================
- Hits 88627 88614 -13 - Misses 11865 11879 +14 + Partials 2510 2509 -1 
FlagCoverage Δ
tests86.03% <ø> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager

joostjager commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@TheBlueMatt we keep expanding the fuzz space. If we want to stick to byte commands to not make it unnecessarily difficult for the fuzzer, it seems we have to accept less variation. In particular when there are multiple channels, fuzzing operations on each of them individually is quickly using up all byte values.

For the same reason, I selected only four variations of mpp.

Do you think the trade-off is still right, or should we consider something like 1 byte command + 1 byte parameter?

@joostjager
joostjagerforce-pushed the fuzz-multi-channels branch 2 times, most recently from 81c11a0 to e0ba40eCompareFebruary 3, 2026 15:18
@joostjager
joostjager marked this pull request as ready for review February 3, 2026 15:20
@joostjager
joostjager requested review from TheBlueMatt and valentinewallace and removed request for valentinewallaceFebruary 3, 2026 15:20
@joostjagerjoostjager changed the title Fuzz mpp paymentsFuzz multi-part paymentsFeb 3, 2026

@TheBlueMattTheBlueMatt left a comment

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.

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

@ldk-reviews-bot

Copy link
Copy Markdown

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

IMO one of the biggest coverage gaps that we can fix here is what happens to payments when a channel was closed. Its obviously not trivial (we have to handle clearing HTLCs via the monitor path) but I'm not actually sure the changes here would have found the bulk of the issues we've run into on 0.1, whereas closing some of the channels would.

Yes I can definitely see that. My idea was to first add multiple channels and mpp in this PR, and then continue with force closing in the next. Do you think doing it the other way around is better?

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oh, no, this is definitely fine, i just wanted to check if that was the next step/intended as a separate PR or if it wasn't planned. Happy to land this as-is first.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Intended next step. I had added it to the PR description to avoid the question :)

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Maybe that'll teach me to read (it won't).

0x6c => send_hop_noret(0, 1, chan_a, 2, chan_b, 1, &mut p_ctr),
0x6d => send_hop_noret(2, 1, chan_b, 0, chan_a, 1, &mut p_ctr),

// MPP payments

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.

We also need to fuzz the case where the recipient receives an MPP via multiple parts over a single channel. Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also probably the case where a forwarding node receives an MPP in multiple parts over a single channel.

This should have been covered already on commands 0x71 and 0x73.

Added a commit for the direct multi-part single-channel case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Squashed it as it was only the two lines for the command.

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tried hitting a panic in PaymentSent for all five mpp commands. Then I discovered #4385. With that applied, Claude came up with the following sequences for mpp:

CommandDescriptionFuzz String (hex)
0x70Direct MPP (multi A-B channels)00 70 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17
0x71Hop MPP (multi A-B, single B-C)00 71 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x72Hop MPP (multi A-B, multi B-C)00 72 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x73Hop MPP (single A-B, multi B-C)00 73 11 19 1f 11 19 1f 11 19 1f 11 19 1f 21 27 11 19 21 27 11 19 21 27 11 19 21 27 21 27 21 27 21 27 21 27 11 19 1f 11 19 1f 11 19 1f 11 19 1f 17 17 17 17 17 17 17 17
0x74Direct MPP (3 parts, single channel)00 74 11 19 1f 11 19 1f 11 19 1f 11 19 1f 11 19 17 11 19 17 11 19 17

joostjagerand others added 2 commits February 6, 2026 10:32
This expands the channel monitor consistency fuzz test from 2 channels
to 6 channels (3 between A-B and 3 between B-C), enabling future MPP
payment testing.
Changes:
- Extract `connect_peers!` macro from `make_channel!` to avoid duplicate
peer connections
- Create channel arrays `chan_ab_ids[3]` and `chan_bc_ids[3]`
- Store SCIDs in `chan_ab_scids[3]` and `chan_bc_scids[3]`
- Use funding transaction versions 1-6 to avoid txid collisions under
fuzz hashing (which XORs all bytes to a single byte, causing versions
0-5 to collide between A-B and B-C channel pairs)
- Update `test_return!` assertions to expect 3/6/3 channels
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add multi-path payment (MPP) fuzzing commands that split payments across
multiple channels:
- send_mpp_payment: direct MPP from source to dest using multiple channels
- send_mpp_hop_payment: MPP via intermediate node with multiple channels
on either or both hops
New fuzz commands:
- 0x70: direct MPP 0->1 (uses all 3 A-B channels)
- 0x71: MPP 0->1->2, multi channels on first hop (A-B)
- 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C)
- 0x73: MPP 0->1->2, multi channels on second hop (B-C)
- 0x74: single-channel MPP 0->1 (all parts over one channel)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After settling all state at 0xff, verify that pending_payments is empty
for all nodes. If payments remain stuck indefinitely, that indicates a
bug in payment resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@TheBlueMattTheBlueMatt left a comment

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.

Thanks!

@TheBlueMatt
TheBlueMatt merged commit 7044bc7 into lightningdevkit:mainFeb 9, 2026
20 of 21 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@ldk-reviews-bot@TheBlueMatt