Skip to content

Commit 80a170f

Browse files
tnullamackillop
authored andcommitted
Add test for payment persistence after node restart
Add integration test that verifies 200 payments are correctly persisted and retrievable via `list_payments` after restarting a node. Co-Authored-By: Claude AI
1 parent 4a0acc2 commit 80a170f

1 file changed

Lines changed: 120 additions & 1 deletion

File tree

tests/integration_tests_rust.rs

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ use bitcoin::address::NetworkUnchecked;
3838
use bitcoin::hashes::sha256::Hash as Sha256Hash;
3939
use bitcoin::hashes::Hash;
4040
use bitcoin::{Address, Amount, ScriptBuf};
41-
4241
use log::LevelFilter;
4342

4443
use std::collections::HashSet;
4544
use std::str::FromStr;
4645
use std::sync::Arc;
4746

47+
use crate::common::TestStoreType;
48+
4849
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
4950
async fn channel_full_cycle() {
5051
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
@@ -2602,3 +2603,121 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() {
26022603
Some(6)
26032604
);
26042605
}
2606+
2607+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
2608+
async fn payment_persistence_after_restart() {
2609+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
2610+
let chain_source = TestChainSource::Esplora(&electrsd);
2611+
2612+
// Setup nodes manually so we can restart node_a with the same config
2613+
println!("== Node A ==");
2614+
let mut config_a = random_config(true);
2615+
config_a.store_type = TestStoreType::Sqlite;
2616+
2617+
let num_payments = 200;
2618+
let payment_amount_msat = 1_000_000; // 1000 sats per payment
2619+
2620+
{
2621+
let node_a = setup_node(&chain_source, config_a.clone(), None);
2622+
2623+
println!("\n== Node B ==");
2624+
let config_b = random_config(true);
2625+
let node_b = setup_node(&chain_source, config_b, None);
2626+
2627+
let addr_a = node_a.onchain_payment().new_address().unwrap();
2628+
let addr_b = node_b.onchain_payment().new_address().unwrap();
2629+
2630+
// Premine sufficient funds for a large channel and many payments
2631+
let premine_amount_sat = 10_000_000;
2632+
premine_and_distribute_funds(
2633+
&bitcoind.client,
2634+
&electrsd.client,
2635+
vec![addr_a, addr_b],
2636+
Amount::from_sat(premine_amount_sat),
2637+
)
2638+
.await;
2639+
node_a.sync_wallets().unwrap();
2640+
node_b.sync_wallets().unwrap();
2641+
assert_eq!(node_a.list_balances().spendable_onchain_balance_sats, premine_amount_sat);
2642+
assert_eq!(node_b.list_balances().spendable_onchain_balance_sats, premine_amount_sat);
2643+
2644+
// Open a large channel from node_a to node_b
2645+
let channel_amount_sat = 5_000_000;
2646+
open_channel(&node_a, &node_b, channel_amount_sat, true, &electrsd).await;
2647+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
2648+
node_a.sync_wallets().unwrap();
2649+
node_b.sync_wallets().unwrap();
2650+
expect_channel_ready_event!(node_a, node_b.node_id());
2651+
expect_channel_ready_event!(node_b, node_a.node_id());
2652+
2653+
// Send 200 payments from node_a to node_b
2654+
println!("\nSending {} payments from A to B...", num_payments);
2655+
let invoice_description =
2656+
Bolt11InvoiceDescription::Direct(Description::new(String::from("test")).unwrap());
2657+
2658+
for i in 0..num_payments {
2659+
let invoice = node_b
2660+
.bolt11_payment()
2661+
.receive(payment_amount_msat, &invoice_description.clone().into(), 3600)
2662+
.unwrap();
2663+
let payment_id = node_a.bolt11_payment().send(&invoice, None).unwrap();
2664+
expect_event!(node_a, PaymentSuccessful);
2665+
expect_event!(node_b, PaymentReceived);
2666+
2667+
if (i + 1) % 50 == 0 {
2668+
println!("Completed {} payments", i + 1);
2669+
}
2670+
2671+
// Verify payment succeeded
2672+
assert_eq!(node_a.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded);
2673+
}
2674+
println!("All {} payments completed successfully", num_payments);
2675+
2676+
// Verify node_a has 200 outbound Bolt11 payments before shutdown
2677+
let outbound_payments_before = node_a.list_payments_with_filter(|p| {
2678+
p.direction == PaymentDirection::Outbound
2679+
&& matches!(p.kind, PaymentKind::Bolt11 { .. })
2680+
});
2681+
assert_eq!(outbound_payments_before.len(), num_payments);
2682+
2683+
// Shut down both nodes
2684+
println!("\nShutting down nodes...");
2685+
node_a.stop().unwrap();
2686+
node_b.stop().unwrap();
2687+
}
2688+
2689+
// Restart node_a with the same config
2690+
println!("\nRestarting node A...");
2691+
let restarted_node_a = setup_node(&chain_source, config_a, None);
2692+
2693+
// Assert all 200 payments are still in the store
2694+
let outbound_payments_after = restarted_node_a.list_payments_with_filter(|p| {
2695+
p.direction == PaymentDirection::Outbound && matches!(p.kind, PaymentKind::Bolt11 { .. })
2696+
});
2697+
assert_eq!(
2698+
outbound_payments_after.len(),
2699+
num_payments,
2700+
"Expected {} payments after restart, found {}",
2701+
num_payments,
2702+
outbound_payments_after.len()
2703+
);
2704+
2705+
// Verify all payments have the correct status
2706+
for payment in &outbound_payments_after {
2707+
assert_eq!(
2708+
payment.status,
2709+
PaymentStatus::Succeeded,
2710+
"Payment {:?} has unexpected status {:?}",
2711+
payment.id,
2712+
payment.status
2713+
);
2714+
assert_eq!(payment.amount_msat, Some(payment_amount_msat));
2715+
}
2716+
2717+
println!(
2718+
"Successfully verified {} payments persisted after restart",
2719+
outbound_payments_after.len()
2720+
);
2721+
2722+
restarted_node_a.stop().unwrap();
2723+
}

0 commit comments

Comments
 (0)