Skip to content

Commit d82e6ba

Browse files
committed
Test preimage claim after reorg of counterparty commitment
This test adds coverage for receiving a preimage after seeing a counterparty commitment confirm, followed by a reorg and the confirmation of a different commitment instead. The first test covers the case where a holder commitment confirms after the counterparty commitment reorg. The second test covers the case where a previous counterparty commitment confirms after the latest counterparty commitment reorg.
1 parent 89fbbb3 commit d82e6ba

File tree

1 file changed

+138
-1
lines changed

1 file changed

+138
-1
lines changed

lightning/src/ln/reorg_tests.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99

1010
//! Further functional tests which test blockchain reorganizations.
1111
12+
use crate::chain::chaininterface::LowerBoundedFeeEstimator;
1213
use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS};
1314
use crate::chain::transaction::OutPoint;
1415
use crate::chain::Confirm;
15-
use crate::events::{Event, MessageSendEventsProvider, ClosureReason, HTLCDestination};
16+
use crate::events::{Event, MessageSendEventsProvider, ClosureReason, HTLCDestination, MessageSendEvent};
1617
use crate::ln::msgs::{ChannelMessageHandler, Init};
1718
use crate::util::test_utils;
1819
use crate::util::ser::Writeable;
@@ -617,3 +618,139 @@ fn test_to_remote_after_local_detection() {
617618
do_test_to_remote_after_local_detection(ConnectStyle::TransactionsFirstReorgsOnlyTip);
618619
do_test_to_remote_after_local_detection(ConnectStyle::FullBlockViaListen);
619620
}
621+
622+
#[test]
623+
fn test_htlc_preimage_claim_holder_commitment_after_counterparty_commitment_reorg() {
624+
// We detect a counterparty commitment confirm onchain, followed by a reorg and a confirmation
625+
// of a holder commitment. Then, if we learn of the preimage for an HTLC in both commitments,
626+
// test that we only claim the currently confirmed commitment.
627+
let chanmon_cfgs = create_chanmon_cfgs(2);
628+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
629+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
630+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
631+
632+
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
633+
634+
// Route an HTLC which we will claim onchain with the preimage.
635+
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
636+
637+
// Force close with the latest counterparty commitment, confirm it, and reorg it with the latest
638+
// holder commitment.
639+
nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
640+
check_closed_broadcast(&nodes[0], 1, true);
641+
check_added_monitors(&nodes[0], 1);
642+
check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed, false, &[nodes[1].node.get_our_node_id()], 100000);
643+
644+
nodes[1].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[0].node.get_our_node_id()).unwrap();
645+
check_closed_broadcast(&nodes[1], 1, true);
646+
check_added_monitors(&nodes[1], 1);
647+
check_closed_event(&nodes[1], 1, ClosureReason::HolderForceClosed, false, &[nodes[0].node.get_our_node_id()], 100000);
648+
649+
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
650+
assert_eq!(txn.len(), 1);
651+
let commitment_tx_a = txn.pop().unwrap();
652+
check_spends!(commitment_tx_a, funding_tx);
653+
654+
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
655+
assert_eq!(txn.len(), 1);
656+
let commitment_tx_b = txn.pop().unwrap();
657+
check_spends!(commitment_tx_b, funding_tx);
658+
659+
mine_transaction(&nodes[0], &commitment_tx_a);
660+
mine_transaction(&nodes[1], &commitment_tx_a);
661+
662+
disconnect_blocks(&nodes[0], 1);
663+
disconnect_blocks(&nodes[1], 1);
664+
665+
mine_transaction(&nodes[0], &commitment_tx_b);
666+
mine_transaction(&nodes[1], &commitment_tx_b);
667+
668+
// Provide the preimage now, such that we only claim from the holder commitment (since it's
669+
// currently confirmed) and not the counterparty's.
670+
get_monitor!(nodes[1], chan_id).provide_payment_preimage(
671+
&payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
672+
&LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
673+
);
674+
675+
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
676+
assert_eq!(txn.len(), 1);
677+
let htlc_success_tx = txn.pop().unwrap();
678+
check_spends!(htlc_success_tx, commitment_tx_b);
679+
}
680+
681+
#[test]
682+
fn test_htlc_preimage_claim_prev_counterparty_commitment_after_current_counterparty_commitment_reorg() {
683+
// We detect a counterparty commitment confirm onchain, followed by a reorg and a
684+
// confirmation of the previous (still unrevoked) counterparty commitment. Then, if we learn
685+
// of the preimage for an HTLC in both commitments, test that we only claim the currently
686+
// confirmed commitment.
687+
let chanmon_cfgs = create_chanmon_cfgs(2);
688+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
689+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
690+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
691+
692+
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
693+
694+
// Route an HTLC which we will claim onchain with the preimage.
695+
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
696+
697+
// Obtain the current commitment, which will become the previous after a fee update.
698+
let prev_commitment_a = &get_local_commitment_txn!(nodes[0], chan_id)[0];
699+
700+
*nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 4;
701+
nodes[0].node.timer_tick_occurred();
702+
check_added_monitors(&nodes[0], 1);
703+
let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
704+
assert_eq!(msg_events.len(), 1);
705+
let (update_fee, commit_sig) = if let MessageSendEvent::UpdateHTLCs { node_id, mut updates } = msg_events.pop().unwrap() {
706+
assert_eq!(node_id, nodes[1].node.get_our_node_id());
707+
(updates.update_fee.take().unwrap(), updates.commitment_signed)
708+
} else {
709+
panic!("Unexpected message send event");
710+
};
711+
712+
// Handle the fee update on the other side, but don't send the last RAA such that the previous
713+
// commitment is still valid (unrevoked).
714+
nodes[1].node().handle_update_fee(&nodes[0].node.get_our_node_id(), &update_fee);
715+
let _last_revoke_and_ack = commitment_signed_dance!(nodes[1], nodes[0], commit_sig, false, true, false, true);
716+
717+
// Force close with the latest commitment, confirm it, and reorg it with the previous commitment.
718+
nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
719+
check_closed_broadcast(&nodes[0], 1, true);
720+
check_added_monitors(&nodes[0], 1);
721+
check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed, false, &[nodes[1].node.get_our_node_id()], 100000);
722+
723+
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
724+
assert_eq!(txn.len(), 1);
725+
let current_commitment_a = txn.pop().unwrap();
726+
assert_ne!(current_commitment_a.txid(), prev_commitment_a.txid());
727+
check_spends!(current_commitment_a, funding_tx);
728+
729+
mine_transaction(&nodes[0], &current_commitment_a);
730+
mine_transaction(&nodes[1], &current_commitment_a);
731+
732+
check_closed_broadcast(&nodes[1], 1, true);
733+
check_added_monitors(&nodes[1], 1);
734+
check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false, &[nodes[0].node.get_our_node_id()], 100000);
735+
736+
disconnect_blocks(&nodes[0], 1);
737+
disconnect_blocks(&nodes[1], 1);
738+
739+
mine_transaction(&nodes[0], &prev_commitment_a);
740+
mine_transaction(&nodes[1], &prev_commitment_a);
741+
742+
// Provide the preimage now, such that we only claim from the previous commitment (since it's
743+
// currently confirmed) and not the latest.
744+
get_monitor!(nodes[1], chan_id).provide_payment_preimage(
745+
&payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
746+
&LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
747+
);
748+
749+
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
750+
assert_eq!(txn.len(), 1);
751+
let htlc_preimage_tx = txn.pop().unwrap();
752+
check_spends!(htlc_preimage_tx, prev_commitment_a);
753+
// Make sure it was indeed a preimage claim and not a revocation claim since the previous
754+
// commitment (still unrevoked) is the currently confirmed closing transaction.
755+
assert_eq!(htlc_preimage_tx.input[0].witness.second_to_last().unwrap(), &payment_preimage.0[..]);
756+
}

0 commit comments

Comments
 (0)