') + ')', '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('^' + ".*" + ', '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" + ', '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('^' + ".*" + ', '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); } })(); })(); Bump BDK, address pending payment store follow ups by tnull · Pull Request #937 · lightningdevkit/ldk-node · GitHub
Skip to content

Bump BDK, address pending payment store follow ups - #937

Merged
tnull merged 6 commits into
lightningdevkit:mainfrom
tnull:2026-06-fix-770-payment-store-followups
Jun 26, 2026
Merged

Bump BDK, address pending payment store follow ups#937
tnull merged 6 commits into
lightningdevkit:mainfrom
tnull:2026-06-fix-770-payment-store-followups

Conversation

@tnull

@tnulltnull commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Fixes#770.
Fixes#776.
Fixes#901.

We bump our BDK dependency and address some follow-ups to #658.

(cc @Camillarhi)

@tnull
tnull requested a review from jkczyzJune 12, 2026 11:27
@ldk-reviews-bot

ldk-reviews-bot commented Jun 12, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @jkczyz 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.

@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@tnull
tnullforce-pushed the 2026-06-fix-770-payment-store-followups branch from 70654b2 to da75376CompareJune 15, 2026 08:40
@tnull

Copy link
Copy Markdown
CollaboratorAuthor

Now that bdk_wallet 3.1 shipped over the weekend, I now directly bump to that and include a commit addressing #901. I also added a commit that has us respect anchor reserves when fee bumping.

@ldk-reviews-bot

Copy link
Copy Markdown

🔔 2nd Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@tnulltnull mentioned this pull request Jun 19, 2026
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 3rd Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot

Copy link
Copy Markdown

🔔 4th Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment threadsrc/wallet/mod.rs Outdated
Comment threadsrc/payment/store.rs Outdated
Comment threadsrc/wallet/mod.rs Outdated
Comment on lines +392 to +421
let pending_payment_details =
self.create_pending_payment_from_tx(payment, conflict_txids.clone());
let payment_txid = match &payment.kind {
PaymentKind::Onchain { txid, .. } => *txid,
_ => {
log_error!(
self.logger,
"Payment {:?} is not on-chain during WalletEvent::TxReplaced",
payment_id,
);
continue;
},
};
let pending_payment_details = self.create_pending_payment_from_tx(
payment_id,
payment_txid,
conflict_txids,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regarding the approach from #888, it's probably better to take this approach rather than using ChannelReady as you suggest in that PR. IIUC, it will remove the race condition that needs to be protected yet. Gonna give that a try by rebasing on this PR and will report back there.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Alright, sounds good, let me know.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The one concern about this approach is the amount of data in TransactionType::InteractiveFunding. Following #791's approach, we can store minimal information like Vec<Channel>. But we do need to keep other information until confirmation in order to set the correct amount and fee in case an RBF candidate other than the latest confirms.

We can use the pending payment store for this, storing either everything or a minimal fields like this:

pub(crate)structFundingTxCandidate{pubtxid:Txid,pubamount_msat:Option<u64>,pubfee_paid_msat:Option<u64>,}

Since we don't support mixed-mode splicing, we don't need to store the direction. But supporting that or batched splices / v2 opens would require including that here. Or including some other data instead of a direction if we think that it is no longer meaningful in the presence of those features.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Another confusing point about direction, if we splice-out we may say this is outbound, but should it be if it goes to our own address?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

The one concern about this approach is the amount of data in TransactionType::InteractiveFunding. Following #791's approach, we can store minimal information like Vec<Channel>. But we do need to keep other information until confirmation in order to set the correct amount and fee in case an RBF candidate other than the latest confirms.

We can use the pending payment store for this, storing either everything or a minimal fields like this:

pub(crate)structFundingTxCandidate{pubtxid:Txid,pubamount_msat:Option<u64>,pubfee_paid_msat:Option<u64>,}

Since we don't support mixed-mode splicing, we don't need to store the direction. But supporting that or batched splices / v2 opens would require including that here. Or including some other data instead of a direction if we think that it is no longer meaningful in the presence of those features.

Okay, but that seems reasonable? It's fine to add additional fields to the pending payment store, as long as we're fine with them getting pruned eventually once the transactions confirm?

Another confusing point about direction, if we splice-out we may say this is outbound, but should it be if it goes to our own address?

That seems also fine? Potentially we could consider a third variant that indicates 'internal balance transfer' or similar, but not sure it's worth?

@tnulltnull added this to the 0.8 milestone Jun 24, 2026
@tnull
tnull requested a review from jkczyzJune 24, 2026 09:13

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like the fixups aren't interleaved

Comment threadtests/integration_tests_rust.rs
Comment threadsrc/payment/store.rs Outdated
Comment threadsrc/payment/store.rs Outdated
let old_txid = self.txid;
self.txid = update.txid;
if old_txid != self.txid && !self.conflicting_txids.contains(&old_txid) {
self.conflicting_txids.push(old_txid);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIUC, this means an update can add but never remove.

@tnulltnullJun 25, 2026

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Outdated by now, might revisit in the future. Now opened #950 to track that.

tnull added 2 commits June 25, 2026 09:27
Update the direct BDK wallet stack to the latest crate releases.
This lets follow-up wallet event code use the upstream BDK API. It
also preserves temporary transaction cleanup after BDK removed its
cancel_tx helper.
Co-Authored-By: HAL 9000
Use BDK's wallet event helper for mempool updates.
This removes the local event diffing copy now that BDK exposes the
needed event API.
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-06-fix-770-payment-store-followups branch from a6a0dee to 486c2b3CompareJune 25, 2026 07:32
@tnull

Copy link
Copy Markdown
CollaboratorAuthor

Now decided to drop two commits (consolidating in one file, compacting pending payment store) to defer the decision how to simplify/refactor pending payment store post #948, as there we'll likely start to track user-registered payments (manual claim flow) in the pending payment store, i.e., it could be simpler to just keep the PaymentDetails around for that, though I'm not quite sure yet.

@tnull
tnullforce-pushed the 2026-06-fix-770-payment-store-followups branch from 486c2b3 to ad0bbc2CompareJune 25, 2026 08:31
@tnull
tnull requested a review from jkczyzJune 25, 2026 08:41
@Camillarhi

Copy link
Copy Markdown
Contributor

Thanks for this @tnull. Just a few commit nits, there's an f before two commit messages f Build RBF test with UniFFI and f Keep pending tx conflicts canonical

@tnull

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for this @tnull. Just a few commit nits, there's an f before two commit messages f Build RBF test with UniFFI and f Keep pending tx conflicts canonical

Yes, this is intentional as they are fixups to-be-squashed after review.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Please squash.

tnull added 4 commits June 26, 2026 07:21
Move affected on-chain payments back to pending when BDK reports that
their transaction is unconfirmed again.
This keeps payment history aligned with wallet events after a reorg. It
does not update payment records directly from disconnected-block
notifications.
Co-Authored-By: HAL 9000
Keep pending payment namespace constants next to the primary payment
store constants.
This keeps related persistence keys discoverable together.
Co-Authored-By: HAL 9000
Stop exporting the pending payment index record from the public
payment module.
The pending index is an internal persistence detail and should not
become public API before this ships.
Co-Authored-By: HAL 9000
RBF can spend fee increases from the original transaction's change
output.
Check the replacement fee increase against the current anchor-channel
reserve before signing. This prevents high manual fee rates from
consuming funds reserved for anchor spends.
This finding was discovered by Project Loupe.
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-06-fix-770-payment-store-followups branch from ad0bbc2 to c82c2e5CompareJune 26, 2026 05:21
@tnull

Copy link
Copy Markdown
CollaboratorAuthor

LGTM. Please squash.

Squashed without further changes.

@tnull
tnull merged commit ad4a3a8 into lightningdevkit:mainJun 26, 2026
23 checks passed
Sign up for freeto 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.

Drop rounding correction once we update to BDK 3.1.0 Drop copied-over wallet_events when possible Follow-ups to PR #658

4 participants

@tnull@ldk-reviews-bot@Camillarhi@jkczyz