Skip to content

Commit 0cb6720

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. They both fail as is, showing that we do not handle these cases correctly. Instead of claiming the HTLC with the preimage on the currently confirmed commitment, we'd always claim it from the latest counterparty commitment simply because we've seen it confirm onchain at some point.
1 parent 6016101 commit 0cb6720

File tree

1 file changed

+130
-1
lines changed

1 file changed

+130
-1
lines changed

lightning/src/ln/reorg_tests.rs

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

0 commit comments

Comments
 (0)