Skip to content

Randomize chain source selection in tests#769

Open
tnull wants to merge 5 commits intolightningdevkit:mainfrom
tnull:2026-01-test-setup
Open

Randomize chain source selection in tests#769
tnull wants to merge 5 commits intolightningdevkit:mainfrom
tnull:2026-01-test-setup

Conversation

@tnull
Copy link
Collaborator

@tnull tnull commented Jan 23, 2026

.. all of our tests should be robust against switching chain sources. We
here opt to pick a random one each time to considerably extend our test
coverage, instead of just running some cases against non-Esplora chain
sources.

@tnull tnull requested a review from TheBlueMatt January 23, 2026 14:00
@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Jan 23, 2026

👋 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.

@tnull
Copy link
Collaborator Author

tnull commented Jan 23, 2026

This will be flaky, at the very least until lightningdevkit/rust-lightning#4341 gets release, which would have been caught if we'd ever had run the 0conf test case with an Electrum chain source.

TheBlueMatt
TheBlueMatt previously approved these changes Jan 23, 2026
Copy link
Contributor

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

makes sense to me. Hopefully CI fails until lightningdevkit/rust-lightning#4341

@tnull
Copy link
Collaborator Author

tnull commented Jan 23, 2026

makes sense to me. Hopefully CI fails until lightningdevkit/rust-lightning#4341

I think I'll whack-a-mole a few more flakes/bugs before landing this.

@tnull
Copy link
Collaborator Author

tnull commented Jan 23, 2026

Previously

    simple_bolt12_send_receive (bitcoind RPC)
    test_node_announcement_propagation (bitcoind RPC)

had failed, I want to double-check them once more before moving forward here.

@tnull
Copy link
Collaborator Author

tnull commented Jan 29, 2026

Pushed an update, but currently onchain_send_receive is still (or newly?) broken when syncing with bitcoind. Will look into that.

@tnull tnull marked this pull request as draft January 29, 2026 19:12
@tnull tnull force-pushed the 2026-01-test-setup branch from b8179ca to 282605b Compare January 29, 2026 19:12
It's weird to have a special intermediary `setup_node` method if we have
`TestConfig` for exactly that reason by now. So we move
`async_payment_role` over.
@tnull tnull force-pushed the 2026-01-test-setup branch from 7796735 to d0946d1 Compare February 12, 2026 10:10
@tnull
Copy link
Collaborator Author

tnull commented Feb 12, 2026

Pushed an update, but currently onchain_send_receive is still (or newly?) broken when syncing with bitcoind. Will look into that.

Alright, fixed that one, too and rebased. Should be ready for review now.

@tnull tnull marked this pull request as ready for review February 12, 2026 10:10
@tnull tnull requested a review from TheBlueMatt February 12, 2026 10:11
.. all of our tests should be robust against switching chain sources. We
here opt to pick a random one each time to considerably extend our test
coverage, instead of just running some cases against non-Esplora chain
sources.

Signed-off-by: Elias Rohrer <dev@tnull.de>
When we intially implemented `bitcoind` syncing polling the mempool was
very frequent and rather inefficient so we made a choice not to
unnecessarily update the payment store for mempool changes, especially
since we only consider transactions `Succeeded` after
`ANTI_REORG_DELAY` anyways.

However, since then we made quite a few peformance improvements to the
mempool syncing, and by now we should just update they payment store as
not doing so will lead to rather unexpected behavior, making some tests
fail for `TestChainSource::Bitcoind`, e.g., `channel_full_cycle_0conf`,
which we fix here.

As we recently switched to updating the payment store based on BDK's
`WalletEvent`, but they currently don't offer an API returning such
events when applying mempool transactions, we copy over the respective
method for generating events from `bdk_wallet`, with the intention of
dropping it again once they do.

Signed-off-by: Elias Rohrer <dev@tnull.de>
Previously, we fixed than a fresh node syncing via `bitcoind` RPC would
resync all chain data back to genesis. However, while introducing a
wallet birthday is great, it disallowed discovery of historical funds if
a wallet would be imported from seed. Here, we add a recovery mode flag
to the builder that explictly allows to re-enable resyncing from genesis
in such a scenario. Going forward, we intend to reuse that API for an
upcoming Lightning recoery flow, too.
@tnull tnull force-pushed the 2026-01-test-setup branch from d0946d1 to 7c08a0b Compare February 12, 2026 10:22
Copy link
Contributor

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

I don't really know BDK well enough to feel like I can meaningfully review this, but a few questions.


// FIXME/TODO: This is copied-over from bdk_wallet and only used to generate `WalletEvent`s after
// applying mempool transactions. We should drop this when BDK offers to generate events for
// mempool transactions natively.
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, if BDK doesn't support this natively, do they have logic to correctly handle conflicts and build balance knowledge appropriately? ie if there's an RBF that conflicts do we remove the 0conf tx from our balance?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, they support all of the canonical transaction handling, it's just when they recently introduced the WalletEvent, they didn't update all APIs we require to return them. Arguably, they should just expose the helper we here copied over which would avoid them having to provide _event variants for all API endpoints individually. See also the discussion on bitcoindevkit/bdk_wallet#374

///
/// This should only be set on first startup when importing an older wallet from a previously
/// used [`NodeEntropy`].
pub fn set_wallet_recovery_mode(&mut self) -> &mut Self {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than a coarse "recovery mode" can we just enable setting the "wallet birthday"? In some setups that might be available and would avoid a lot of effort.

Copy link
Collaborator Author

@tnull tnull Feb 12, 2026

Choose a reason for hiding this comment

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

Hmm, wallet birthday support is still inflight on the BDK side (see bitcoindevkit/bdk_wallet#368) and I'd like to punt on it until we can actually make use of that and remove our hacky birthday logic.

That said, if you prefer we could of course rename the current "recovery_mode" API to "disable_wallet_birthday" for now which ~does the same thing?

@tnull tnull removed this from LDK Priorities Feb 12, 2026
@tnull tnull moved this to Goal: Merge in Weekly Goals Feb 12, 2026
@tnull tnull self-assigned this Feb 12, 2026
Previously, we'd selectively insert the funding outputs into the onchain
wallet to later allow calculating `fees_paid` when creating payment
store entries (only for splicing mostly). However, this didn't always work, and we might for
example end up with a missing funding output (and hence would fall back
to `fees_paid: Some(0)`) if it was a counterparty-initiated channel and
we synced via `bitcoind` RPC.

Here, we fix this by tracking all LDK-registered `txids` in
`ChainSource` and then in the `Wallet`'s `Listen` implementation insert
all outputs of all registered transactions into the `Wallet`, ensuring
we'd always have sufficient data for `calculate_fee` available.

Thereby we also fix the `onchain_send_receive` test which previously
failed when using `TestChainSource::Bitcoind`.

Signed-off-by: Elias Rohrer <dev@tnull.de>
@tnull tnull force-pushed the 2026-01-test-setup branch from 7c08a0b to c4ca6d3 Compare February 13, 2026 09:54
@tnull
Copy link
Collaborator Author

tnull commented Feb 13, 2026

Amended the last commit to include a comment explaining what we do/why we do it:

diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs
index 835e1b31..2decf981 100644
--- a/src/wallet/mod.rs
+++ b/src/wallet/mod.rs
@@ -1031,4 +1031,12 @@ impl Listen for Wallet {
                }

+               // In order to be able to reliably calculate fees the `Wallet` needs access to the previous
+               // ouput data. To this end, we here insert any ouputs of transactions that LDK is intersted
+               // in (e.g., funding transaction ouputs) into the wallet's transaction graph when we see
+               // them, so it is reliably able to calculate fees for subsequent spends.
+               //
+               // FIXME: technically, we should also do this for mempool transactions. However, at the
+               // current time fixing the edge case doesn't seem worth the additional conplexity /
+               // additional overhead..
                let registered_txids = self.chain_source.registered_txids();
                for tx in &block.txdata {

@tnull tnull requested a review from TheBlueMatt February 13, 2026 09:56
Error::PersistenceFailed
})?;

self.update_payment_store(&mut *locked_wallet, events).map_err(|e| {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this happen before locked_wallet.persist()? What happens if we crash between the wallet persist and the payment store update (presumably the second is idempotent so we should do it first to reply on restart if needed?)?

&self, unconfirmed_txs: Vec<(Transaction, u64)>, evicted_txids: Vec<(Txid, u64)>,
) -> Result<(), Error> {
if unconfirmed_txs.is_empty() {
return Ok(());
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't appear to be tested. Also not clear to me why we'd want to skip this if we don't have any unconfirmed txs in the mempool but do have some txs that got evicted (iiuc).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Goal: Merge

Development

Successfully merging this pull request may close these issues.

3 participants