Skip to content

Commit ebf9e60

Browse files
joostjagerAtishyy27
authored andcommitted
Add test for monitor update after funding spend
Add a regression test that reproduces the panic when a commitment_signed is processed after the counterparty commitment transaction has confirmed. The ChannelMonitor's no_further_updates_allowed() returns true, causing update_monitor to fail, which ChainMonitor overrides to InProgress. A subsequent preimage claim returning Completed then triggers the per-channel assertion that Completed must not follow InProgress. AI tools were used in preparing this commit.
1 parent f0daee0 commit ebf9e60

1 file changed

Lines changed: 70 additions & 1 deletion

File tree

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::chain::chaininterface::LowerBoundedFeeEstimator;
1616
use crate::chain::chainmonitor::ChainMonitor;
1717
use crate::chain::channelmonitor::{ChannelMonitor, MonitorEvent, ANTI_REORG_DELAY};
1818
use crate::chain::transaction::OutPoint;
19-
use crate::chain::{ChannelMonitorUpdateStatus, Listen, Watch};
19+
use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
2020
use crate::events::{ClosureReason, Event, HTLCHandlingFailureType, PaymentPurpose};
2121
use crate::ln::channel::AnnouncementSigsState;
2222
use crate::ln::channelmanager::{PaymentId, RAACommitmentOrder};
@@ -5421,3 +5421,72 @@ fn test_late_counterparty_commitment_update_after_holder_commitment_spend() {
54215421
fn test_late_counterparty_commitment_update_after_holder_commitment_spend_dust() {
54225422
do_test_late_counterparty_commitment_update_after_holder_commitment_spend(true);
54235423
}
5424+
5425+
#[test]
5426+
#[should_panic(
5427+
expected = "Watch::update_channel returned Completed while prior updates are still InProgress"
5428+
)]
5429+
fn test_monitor_update_fail_after_funding_spend() {
5430+
// When a counterparty commitment transaction confirms (funding spend), the
5431+
// ChannelMonitor sets funding_spend_seen. If a commitment_signed from the
5432+
// counterparty is then processed (a race between chain events and message
5433+
// processing), update_monitor returns Err because no_further_updates_allowed()
5434+
// is true. ChainMonitor overrides the result to InProgress, permanently
5435+
// freezing the channel. A subsequent preimage claim returning Completed then
5436+
// triggers the per-channel assertion.
5437+
let chanmon_cfgs = create_chanmon_cfgs(2);
5438+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
5439+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
5440+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
5441+
5442+
let node_a_id = nodes[0].node.get_our_node_id();
5443+
5444+
let (_, _, chan_id, _) = create_announced_chan_between_nodes(&nodes, 0, 1);
5445+
5446+
// Route payment 1 fully so B can claim it later.
5447+
let (payment_preimage_1, _payment_hash_1, ..) =
5448+
route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
5449+
5450+
// Get A's commitment tx (this is the "counterparty" commitment from B's perspective).
5451+
let as_commitment_tx = get_local_commitment_txn!(nodes[0], chan_id);
5452+
assert_eq!(as_commitment_tx.len(), 1);
5453+
5454+
// Confirm A's commitment tx on B's chain_monitor ONLY (not on B's ChannelManager).
5455+
// This sets funding_spend_seen in the monitor, making no_further_updates_allowed() true.
5456+
let (block_hash, height) = nodes[1].best_block_info();
5457+
let block = create_dummy_block(block_hash, height + 1, vec![as_commitment_tx[0].clone()]);
5458+
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
5459+
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height + 1);
5460+
5461+
// Send payment 2 from A to B.
5462+
let (route, payment_hash_2, _, payment_secret_2) =
5463+
get_route_and_payment_hash!(&nodes[0], nodes[1], 1_000_000);
5464+
nodes[0]
5465+
.node
5466+
.send_payment_with_route(
5467+
route,
5468+
payment_hash_2,
5469+
RecipientOnionFields::secret_only(payment_secret_2, 1_000_000),
5470+
PaymentId(payment_hash_2.0),
5471+
)
5472+
.unwrap();
5473+
check_added_monitors(&nodes[0], 1);
5474+
5475+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
5476+
assert_eq!(events.len(), 1);
5477+
let payment_event = SendEvent::from_event(events.remove(0));
5478+
5479+
nodes[1].node.handle_update_add_htlc(node_a_id, &payment_event.msgs[0]);
5480+
5481+
// B processes commitment_signed. The monitor's update_monitor succeeds on the
5482+
// update steps, but returns Err at the end because no_further_updates_allowed()
5483+
// is true (funding_spend_seen). ChainMonitor overrides the result to InProgress.
5484+
nodes[1].node.handle_commitment_signed(node_a_id, &payment_event.commitment_msg[0]);
5485+
check_added_monitors(&nodes[1], 1);
5486+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
5487+
5488+
// B claims payment 1. The PaymentPreimage monitor update returns Completed
5489+
// (update_monitor succeeds for preimage, and persister returns Completed),
5490+
// but the prior InProgress from the commitment_signed is still pending.
5491+
nodes[1].node.claim_funds(payment_preimage_1);
5492+
}

0 commit comments

Comments
 (0)