From 9941aba84ba1a385733ce6dbb04ac7578561a449 Mon Sep 17 00:00:00 2001 From: shaavan Date: Thu, 2 Jan 2025 18:45:46 +0530 Subject: [PATCH 1/4] 1: Close the channel from bob's end --- lightning/src/ln/offers_tests.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 6455a60b139..70d5b0ca5c9 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -2341,5 +2341,15 @@ fn no_double_pay_with_stale_channelmanager() { // Alice and Bob is closed. Since no 2nd attempt should be made, check that no events are // generated in response to the duplicate invoice. assert!(nodes[0].node.get_and_clear_pending_events().is_empty()); -} + // Claim payment on chain + + // First close the channel between bob and alice, from bob's side + let error_message = "Channel force-closed"; + nodes[1].node.force_close_broadcasting_latest_txn(&chan_id_0, &alice_id, error_message.to_string()).unwrap(); + check_closed_broadcast!(nodes[1], true); + nodes[1].node.force_close_broadcasting_latest_txn(&chan_id_1, &alice_id, error_message.to_string()).unwrap(); + check_closed_broadcast!(nodes[1], true); + check_added_monitors!(nodes[1], 2); + check_closed_event!(nodes[1], 2, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) }, [alice_id, alice_id], 10_000_000); +} From b8623c2587d2f2e0120c7138f1fc9e30610880cf Mon Sep 17 00:00:00 2001 From: shaavan Date: Thu, 2 Jan 2025 19:24:41 +0530 Subject: [PATCH 2/4] 2: get the payment preimage --- lightning/src/ln/offers_tests.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 70d5b0ca5c9..2b9c3ed89fe 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -2319,11 +2319,10 @@ fn no_double_pay_with_stale_channelmanager() { .without_clearing_recipient_events(); do_pass_along_path(args); - expect_recent_payment!(nodes[0], RecentPaymentDetails::Pending, payment_id); - match get_event!(nodes[1], Event::PaymentClaimable) { - Event::PaymentClaimable { .. } => {}, + let payment_preimage = match get_event!(nodes[1], Event::PaymentClaimable) { + Event::PaymentClaimable { purpose, .. } => purpose.preimage(), _ => panic!("No Event::PaymentClaimable"), - } + }; // Reload with the stale manager and check that receiving the invoice again won't result in a // duplicate payment attempt. From cfe94efbfe2be9849f95da8ee83d8b1b3e030e26 Mon Sep 17 00:00:00 2001 From: shaavan Date: Thu, 2 Jan 2025 19:34:55 +0530 Subject: [PATCH 3/4] 3: Claimed HTLC from Bob's side --- lightning/src/ln/offers_tests.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 2b9c3ed89fe..bee0fa161d7 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -2281,7 +2281,8 @@ fn no_double_pay_with_stale_channelmanager() { let alice_id = nodes[0].node.get_our_node_id(); let bob_id = nodes[1].node.get_our_node_id(); - let amt_msat = nodes[0].node.list_usable_channels()[0].next_outbound_htlc_limit_msat + 1; // Force MPP + // ??: The amount need to be modified to match the total amount received to bob, why? + let amt_msat = nodes[0].node.list_usable_channels()[0].next_outbound_htlc_limit_msat + 1000; // Force MPP let offer = nodes[1].node .create_offer_builder(None).unwrap() .clear_paths() @@ -2320,7 +2321,7 @@ fn no_double_pay_with_stale_channelmanager() { do_pass_along_path(args); let payment_preimage = match get_event!(nodes[1], Event::PaymentClaimable) { - Event::PaymentClaimable { purpose, .. } => purpose.preimage(), + Event::PaymentClaimable { purpose, .. } => purpose.preimage().unwrap(), _ => panic!("No Event::PaymentClaimable"), }; @@ -2351,4 +2352,8 @@ fn no_double_pay_with_stale_channelmanager() { check_closed_broadcast!(nodes[1], true); check_added_monitors!(nodes[1], 2); check_closed_event!(nodes[1], 2, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) }, [alice_id, alice_id], 10_000_000); + + nodes[1].node.claim_funds(payment_preimage); + expect_payment_claimed!(nodes[1], payment_hash, amt_msat); + check_added_monitors!(nodes[1], 2); } From 451464b732f50e6ba09ac0682b311d2efa1913ae Mon Sep 17 00:00:00 2001 From: shaavan Date: Thu, 2 Jan 2025 20:51:23 +0530 Subject: [PATCH 4/4] Complete but PaymentPathFailed event instead of PaymentSent --- lightning/src/ln/offers_tests.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index bee0fa161d7..d8b42039add 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -48,7 +48,7 @@ use crate::blinded_path::message::BlindedMessagePath; use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentContext}; use crate::blinded_path::message::{MessageContext, OffersContext}; use crate::events::{ClosureReason, Event, MessageSendEventsProvider, PaymentFailureReason, PaymentPurpose}; -use crate::ln::channelmanager::{Bolt12PaymentError, MAX_SHORT_LIVED_RELATIVE_EXPIRY, PaymentId, RecentPaymentDetails, Retry, self}; +use crate::ln::channelmanager::{self, Bolt12PaymentError, PaymentId, RecentPaymentDetails, Retry, MAX_SHORT_LIVED_RELATIVE_EXPIRY}; use crate::types::features::Bolt12InvoiceFeatures; use crate::ln::functional_test_utils::*; use crate::ln::msgs::{ChannelMessageHandler, Init, NodeAnnouncement, OnionMessage, OnionMessageHandler, RoutingMessageHandler, SocketAddress, UnsignedGossipMessage, UnsignedNodeAnnouncement}; @@ -2344,6 +2344,9 @@ fn no_double_pay_with_stale_channelmanager() { // Claim payment on chain + let commitment_tx_0 = get_local_commitment_txn!(nodes[1], chan_id_0); + let commitment_tx_1 = get_local_commitment_txn!(nodes[1], chan_id_1); + // First close the channel between bob and alice, from bob's side let error_message = "Channel force-closed"; nodes[1].node.force_close_broadcasting_latest_txn(&chan_id_0, &alice_id, error_message.to_string()).unwrap(); @@ -2356,4 +2359,19 @@ fn no_double_pay_with_stale_channelmanager() { nodes[1].node.claim_funds(payment_preimage); expect_payment_claimed!(nodes[1], payment_hash, amt_msat); check_added_monitors!(nodes[1], 2); + + let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0); + assert_eq!(node_txn.len(), 2); + + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![commitment_tx_0[0].clone(), node_txn[0].clone()])); + connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![commitment_tx_1[0].clone(), node_txn[1].clone()])); + connect_blocks(&nodes[0], TEST_FINAL_CLTV as u32); + + let events = nodes[0].node.get_and_clear_pending_events(); + + match events[0] { + Event::PaymentSent { .. } => {}, + Event::PaymentPathFailed { .. } => panic!("Received PaymentPathFailed"), + _ => panic!("Unexpected event") + } }