Skip to content

Commit 5d21bd7

Browse files
jkczyzclaude
andcommitted
Wait for funding classification before syncing in splice tests
In a splice, both channel parties broadcast the funding transaction, and the tests drive a single shared bitcoind, so the counterparty's broadcast can surface it to this node's wallet sync before this node's own funding classification has run. Under parallel test execution that classification can lag far enough behind for the sync to record the transaction as a plain on-chain payment, failing the funding-payment assertions. Wait for the funding broadcast to be classified before each affected splice test syncs its wallets. This is test-only: on a real node the classification runs locally, well ahead of a counterparty's broadcast arriving over the network, so the race does not occur. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f9a64a0 commit 5d21bd7

1 file changed

Lines changed: 46 additions & 1 deletion

File tree

tests/integration_tests_rust.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use ldk_node::payment::{
3636
ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus,
3737
TransactionType, UnifiedPaymentResult,
3838
};
39-
use ldk_node::{Builder, Event, NodeError};
39+
use ldk_node::{Builder, Event, Node, NodeError};
4040
use lightning::ln::channelmanager::PaymentId;
4141
use lightning::routing::gossip::{NodeAlias, NodeId};
4242
use lightning::routing::router::RouteParametersConfig;
@@ -45,6 +45,34 @@ use lightning_types::payment::{PaymentHash, PaymentPreimage};
4545
use log::LevelFilter;
4646
use serde_json::json;
4747

48+
/// Waits until `node` has classified the funding broadcast `funding_txid` (a channel open or splice
49+
/// candidate) into a payment record carrying a `tx_type`. Classification runs off the broadcaster's
50+
/// queue, which can lag a `sync_wallets` call under load — and for a splice the counterparty also
51+
/// broadcasts the same tx, so a racing sync can see it before this node classifies. Waiting here
52+
/// keeps the next sync on the funding short-circuit instead of recording a generic on-chain payment
53+
/// that clobbers the classification.
54+
async fn wait_for_classified_funding_payment(node: &Node, funding_txid: Txid) {
55+
let poll = async {
56+
loop {
57+
let classified = node.list_payments().into_iter().any(|p| {
58+
matches!(
59+
p.kind,
60+
PaymentKind::Onchain { txid, tx_type: Some(_), .. } if txid == funding_txid
61+
)
62+
});
63+
if classified {
64+
return;
65+
}
66+
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
67+
}
68+
};
69+
tokio::time::timeout(std::time::Duration::from_secs(common::INTEROP_TIMEOUT_SECS), poll)
70+
.await
71+
.unwrap_or_else(|_| {
72+
panic!("timed out waiting for funding broadcast {} to be classified", funding_txid)
73+
});
74+
}
75+
4876
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
4977
async fn channel_full_cycle() {
5078
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
@@ -1236,6 +1264,10 @@ async fn splice_channel() {
12361264
let txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
12371265
expect_splice_negotiated_event!(node_b, node_a.node_id());
12381266

1267+
// Node B contributed to this splice, so wait for its funding broadcast to be classified before
1268+
// syncing — otherwise a sync racing the broadcaster's queue records a generic on-chain payment.
1269+
wait_for_classified_funding_payment(&node_b, txo.txid).await;
1270+
12391271
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
12401272

12411273
node_a.sync_wallets().unwrap();
@@ -1292,6 +1324,10 @@ async fn splice_channel() {
12921324
let txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
12931325
expect_splice_negotiated_event!(node_b, node_a.node_id());
12941326

1327+
// Node A contributed to this splice, so wait for its funding broadcast to be classified before
1328+
// syncing — otherwise a sync racing the broadcaster's queue records a generic on-chain payment.
1329+
wait_for_classified_funding_payment(&node_a, txo.txid).await;
1330+
12951331
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
12961332

12971333
node_a.sync_wallets().unwrap();
@@ -1407,6 +1443,9 @@ async fn run_rbf_splice_channel_test(confirm_original: bool) {
14071443
// replaced (a `WalletEvent::TxReplaced`), which must not drop the payment's durable funding
14081444
// classification — the `tx_type` assertion below catches a regression deterministically.
14091445
wait_for_tx(&electrsd.client, original_txo.txid).await;
1446+
// Node B contributed to this splice; wait for its classification before syncing so the sync
1447+
// takes the funding short-circuit rather than racing the broadcaster's queue.
1448+
wait_for_classified_funding_payment(&node_b, original_txo.txid).await;
14101449
node_a.sync_wallets().unwrap();
14111450
node_b.sync_wallets().unwrap();
14121451

@@ -1441,6 +1480,9 @@ async fn run_rbf_splice_channel_test(confirm_original: bool) {
14411480

14421481
// Wait for the RBF transaction to replace the original in the mempool.
14431482
wait_for_tx(&electrsd.client, rbf_txo.txid).await;
1483+
// Wait for node_b's re-classification of the RBF candidate before syncing, so the recorded
1484+
// candidate figures reflect the replacement rather than racing the broadcaster's queue.
1485+
wait_for_classified_funding_payment(&node_b, rbf_txo.txid).await;
14441486
node_a.sync_wallets().unwrap();
14451487
node_b.sync_wallets().unwrap();
14461488

@@ -1640,6 +1682,9 @@ async fn splice_payment_reorged_to_unconfirmed() {
16401682
let splice_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
16411683
expect_splice_negotiated_event!(node_b, node_a.node_id());
16421684
wait_for_tx(&electrsd.client, splice_txo.txid).await;
1685+
// Ensure node_b classified the splice before syncing so the test exercises a funding payment's
1686+
// reorg rather than a generic on-chain payment's.
1687+
wait_for_classified_funding_payment(&node_b, splice_txo.txid).await;
16431688

16441689
// Confirm the splice with a single block — confirmed, but short of `ANTI_REORG_DELAY`, so the
16451690
// payment is `Confirmed`/`Pending` rather than graduated.

0 commit comments

Comments
 (0)