Skip to content

Commit c8c5dc0

Browse files
committed
Release tx_signatures after async monitor update completes
In 83b2d3e, we reworked `ChannelManager::funding_transaction_signed` such that it would also for a user to cancel a splice up until they send `commitment_signed`. Previously, we would would only emit `Event::FundingTransactionReadyForSigning` when both nodes exchanged `commitment_signed` and the corresponding monitor update completed. With the event now being generated immediately after the nodes exchange `tx_complete`, we now need to handle the monitor update not having completed by the time we are ready to send `tx_signatures`. Unfortunately, we also did not have test coverage, allowing this to go unnoticed until being caught by the fuzzer due to a debug assertion. Doing so avoids a potential funds-loss scenario if the funding transaction confirms without the counterparty's signature for our commitment being durably persisted.
1 parent 36d04c3 commit c8c5dc0

File tree

5 files changed

+365
-96
lines changed

5 files changed

+365
-96
lines changed

lightning/src/ln/async_signer_tests.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,3 +1648,95 @@ fn test_async_splice_initial_commit_sig() {
16481648
let _ = get_event!(initiator, Event::SplicePending);
16491649
let _ = get_event!(acceptor, Event::SplicePending);
16501650
}
1651+
1652+
#[test]
1653+
fn test_async_splice_initial_commit_sig_waits_for_monitor_before_tx_signatures() {
1654+
let chanmon_cfgs = create_chanmon_cfgs(2);
1655+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1656+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1657+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1658+
1659+
let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1).2;
1660+
1661+
let (initiator, acceptor) = (&nodes[0], &nodes[1]);
1662+
let initiator_node_id = initiator.node.get_our_node_id();
1663+
let acceptor_node_id = acceptor.node.get_our_node_id();
1664+
1665+
acceptor.disable_channel_signer_op(
1666+
&initiator_node_id,
1667+
&channel_id,
1668+
SignerOp::SignCounterpartyCommitment,
1669+
);
1670+
1671+
// Negotiate a splice up until the signature exchange.
1672+
let outputs = vec![TxOut {
1673+
value: Amount::from_sat(1_000),
1674+
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
1675+
}];
1676+
let contribution = initiate_splice_out(initiator, acceptor, channel_id, outputs).unwrap();
1677+
negotiate_splice_tx(initiator, acceptor, channel_id, contribution);
1678+
1679+
let event = get_event!(initiator, Event::FundingTransactionReadyForSigning);
1680+
if let Event::FundingTransactionReadyForSigning { unsigned_transaction, .. } = event {
1681+
let partially_signed_tx = initiator.wallet_source.sign_tx(unsigned_transaction).unwrap();
1682+
initiator
1683+
.node
1684+
.funding_transaction_signed(&channel_id, &acceptor_node_id, partially_signed_tx)
1685+
.unwrap();
1686+
}
1687+
1688+
let initiator_commit_sig = get_htlc_update_msgs(initiator, &acceptor_node_id);
1689+
1690+
// Keep the monitor update from processing the initiator's initial commitment signed pending on
1691+
// the acceptor.
1692+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
1693+
acceptor
1694+
.node
1695+
.handle_commitment_signed(initiator_node_id, &initiator_commit_sig.commitment_signed[0]);
1696+
check_added_monitors(acceptor, 1);
1697+
assert!(acceptor.node.get_and_clear_pending_msg_events().is_empty());
1698+
1699+
// Once the async signer is unblocked, we should send the initial commitment_signed, but still
1700+
// hold back tx_signatures until the monitor update is completed.
1701+
acceptor.enable_channel_signer_op(
1702+
&initiator_node_id,
1703+
&channel_id,
1704+
SignerOp::SignCounterpartyCommitment,
1705+
);
1706+
acceptor.node.signer_unblocked(None);
1707+
1708+
let msg_events = acceptor.node.get_and_clear_pending_msg_events();
1709+
assert_eq!(msg_events.len(), 1, "{msg_events:?}");
1710+
if let MessageSendEvent::UpdateHTLCs { updates, .. } = &msg_events[0] {
1711+
initiator.node.handle_commitment_signed(acceptor_node_id, &updates.commitment_signed[0]);
1712+
check_added_monitors(initiator, 1);
1713+
} else {
1714+
panic!("Unexpected event");
1715+
}
1716+
1717+
assert!(initiator.node.get_and_clear_pending_msg_events().is_empty());
1718+
assert!(acceptor.node.get_and_clear_pending_msg_events().is_empty());
1719+
1720+
// Reestablishing before the monitor update completes should still not release `tx_signatures`.
1721+
initiator.node.peer_disconnected(acceptor_node_id);
1722+
acceptor.node.peer_disconnected(initiator_node_id);
1723+
let mut reconnect_args = ReconnectArgs::new(initiator, acceptor);
1724+
reconnect_args.send_announcement_sigs = (true, true);
1725+
reconnect_nodes(reconnect_args);
1726+
assert!(initiator.node.get_and_clear_pending_msg_events().is_empty());
1727+
assert!(acceptor.node.get_and_clear_pending_msg_events().is_empty());
1728+
1729+
acceptor.chain_monitor.complete_sole_pending_chan_update(&channel_id);
1730+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
1731+
1732+
let tx_signatures =
1733+
get_event_msg!(acceptor, MessageSendEvent::SendTxSignatures, initiator_node_id);
1734+
initiator.node.handle_tx_signatures(acceptor_node_id, &tx_signatures);
1735+
1736+
let tx_signatures =
1737+
get_event_msg!(initiator, MessageSendEvent::SendTxSignatures, acceptor_node_id);
1738+
acceptor.node.handle_tx_signatures(initiator_node_id, &tx_signatures);
1739+
1740+
let _ = get_event!(initiator, Event::SplicePending);
1741+
let _ = get_event!(acceptor, Event::SplicePending);
1742+
}

0 commit comments

Comments
 (0)