Skip to content

Commit b8a76c1

Browse files
committed
Lower strictness of pending monitor update while awaiting tx_signatures
We previously assumed that no monitor update should ever be pending when receiving `tx_signatures` while quiescent, with the exception of the `RenegotiatedFunding` variant. This was a bit too strict, as we did not consider that if an HTLC was sent via the same channel, its preimage could be received from upstream leading to a monitor update to durably persist it. This commit ensures that if the recipient of a `tx_signatures` has not yet echoed theirs back, and it is awaiting a monitor update completion, then the pending monitor update must be of the `RenegotiatedFunding` variant. If the pending monitor update is of another variant, then we must remain quiescent with no pending updates available to send until after the `tx_signatures` exchange.
1 parent fab9595 commit b8a76c1

2 files changed

Lines changed: 174 additions & 4 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9530,8 +9530,10 @@ where
95309530
&mut self, funding_tx_signed: &mut FundingTxSigned, funding_tx: Transaction,
95319531
best_block_height: u32, logger: &WithChannelContext<'a, L>,
95329532
) {
9533-
debug_assert!(!self.context.channel_state.is_monitor_update_in_progress());
9534-
debug_assert!(!self.context.channel_state.is_awaiting_remote_revoke());
9533+
debug_assert!(
9534+
!self.is_awaiting_monitor_update() || !self.context.monitor_pending_tx_signatures
9535+
);
9536+
debug_assert!(!self.context.is_waiting_on_peer_pending_channel_update());
95359537

95369538
if let Some(pending_splice) = self.pending_splice.as_mut() {
95379539
if let Some(FundingNegotiation::AwaitingSignatures {
@@ -9684,11 +9686,11 @@ where
96849686
splice_negotiated: None,
96859687
splice_locked: None,
96869688
};
9687-
if self.is_awaiting_monitor_update() {
9689+
if self.is_awaiting_monitor_update() && self.context.monitor_pending_tx_signatures {
96889690
// Although the user may have already provided our `tx_signatures`, we must not send
96899691
// them if we're waiting for the monitor to durably persist the counterparty's signature
96909692
// for our initial commitment post-splice.
9691-
debug_assert!(self.context.monitor_pending_tx_signatures);
9693+
debug_assert!(holder_tx_signatures.is_some());
96929694
log_debug!(
96939695
logger,
96949696
"Waiting for async monitor update to complete prior to releasing our tx_signatures"

lightning/src/ln/splicing_tests.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::types::string::UntrustedString;
3434
use crate::util::config::UserConfig;
3535
use crate::util::errors::APIError;
3636
use crate::util::ser::Writeable;
37+
use crate::util::test_channel_signer::SignerOp;
3738
use crate::util::wallet_utils::{
3839
CoinSelection, CoinSelectionSourceSync, ConfirmedUtxo, Input, WalletSourceSync, WalletSync,
3940
};
@@ -10248,3 +10249,170 @@ fn test_splice_out_maximum_includes_pending_claimed_inbound_htlc() {
1024810249

1024910250
assert!(nodes[1].node.splice_channel(&channel_id, &node_id_0).is_ok());
1025010251
}
10252+
10253+
#[test]
10254+
fn test_async_splice_receives_tx_signatures_while_unrelated_monitor_update_pending() {
10255+
let chanmon_cfgs = create_chanmon_cfgs(3);
10256+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
10257+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
10258+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
10259+
10260+
let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1).2;
10261+
create_announced_chan_between_nodes(&nodes, 1, 2);
10262+
10263+
let (initiator, acceptor) = (&nodes[0], &nodes[1]);
10264+
let initiator_node_id = initiator.node.get_our_node_id();
10265+
let acceptor_node_id = acceptor.node.get_our_node_id();
10266+
let final_node_id = nodes[2].node.get_our_node_id();
10267+
10268+
// Leave a forwarded HTLC across A-B and B-C. Later, C will reveal the
10269+
// preimage so B has to persist an unrelated preimage update on A-B while the
10270+
// delayed splice `tx_signatures` are still in flight.
10271+
let (payment_preimage, payment_hash, ..) =
10272+
route_payment(initiator, &[acceptor, &nodes[2]], 1_000_000);
10273+
10274+
// Keep the A-B splice from completing immediately at B. The disabled
10275+
// counterparty-commitment signer forces B to wait for both the signer and
10276+
// the splice monitor update before it can send `tx_signatures`.
10277+
acceptor.disable_channel_signer_op(
10278+
&initiator_node_id,
10279+
&channel_id,
10280+
SignerOp::SignCounterpartyCommitment,
10281+
);
10282+
10283+
let outputs = vec![TxOut {
10284+
value: Amount::from_sat(1_000),
10285+
script_pubkey: initiator.wallet_source.get_change_script().unwrap(),
10286+
}];
10287+
let contribution = initiate_splice_out(initiator, acceptor, channel_id, outputs).unwrap();
10288+
negotiate_splice_tx(initiator, acceptor, channel_id, contribution);
10289+
10290+
let event = get_event!(initiator, Event::FundingTransactionReadyForSigning);
10291+
if let Event::FundingTransactionReadyForSigning { unsigned_transaction, .. } = event {
10292+
let partially_signed_tx = initiator.wallet_source.sign_tx(unsigned_transaction).unwrap();
10293+
initiator
10294+
.node
10295+
.funding_transaction_signed(&channel_id, &acceptor_node_id, partially_signed_tx)
10296+
.unwrap();
10297+
}
10298+
10299+
let initiator_commit_sig = get_htlc_update_msgs(initiator, &acceptor_node_id);
10300+
10301+
// B accepts A's splice commitment, but the monitor update remains pending.
10302+
// This is the async-signing window that normally guards emission of B's
10303+
// `tx_signatures`.
10304+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
10305+
acceptor
10306+
.node
10307+
.handle_commitment_signed(initiator_node_id, &initiator_commit_sig.commitment_signed[0]);
10308+
check_added_monitors(acceptor, 1);
10309+
assert!(acceptor.node.get_and_clear_pending_msg_events().is_empty());
10310+
10311+
// Unblock only the signer side first. B can now produce its splice
10312+
// `commitment_signed`, but still must not send `tx_signatures` until the
10313+
// monitor update above completes.
10314+
acceptor.enable_channel_signer_op(
10315+
&initiator_node_id,
10316+
&channel_id,
10317+
SignerOp::SignCounterpartyCommitment,
10318+
);
10319+
acceptor.node.signer_unblocked(None);
10320+
10321+
let msg_events = acceptor.node.get_and_clear_pending_msg_events();
10322+
assert_eq!(msg_events.len(), 1, "{msg_events:?}");
10323+
if let MessageSendEvent::UpdateHTLCs { updates, .. } = &msg_events[0] {
10324+
initiator.node.handle_commitment_signed(acceptor_node_id, &updates.commitment_signed[0]);
10325+
check_added_monitors(initiator, 1);
10326+
} else {
10327+
panic!("Unexpected event");
10328+
}
10329+
10330+
// Completing B's splice monitor update releases B's `tx_signatures`. This
10331+
// is the update for which `monitor_pending_tx_signatures` is expected to be
10332+
// set.
10333+
acceptor.chain_monitor.complete_sole_pending_chan_update(&channel_id);
10334+
10335+
let acceptor_tx_signatures =
10336+
get_event_msg!(acceptor, MessageSendEvent::SendTxSignatures, initiator_node_id);
10337+
initiator.node.handle_tx_signatures(acceptor_node_id, &acceptor_tx_signatures);
10338+
10339+
// A can now fully sign and broadcast the splice transaction. Save A's
10340+
// reciprocal `tx_signatures` instead of delivering them to B, so B later
10341+
// sees an old splice message after another monitor update has started.
10342+
let delayed_initiator_tx_signatures =
10343+
get_event_msg!(initiator, MessageSendEvent::SendTxSignatures, acceptor_node_id);
10344+
let mut broadcasted = initiator.tx_broadcaster.txn_broadcast();
10345+
assert_eq!(broadcasted.len(), 1, "{broadcasted:?}");
10346+
let splice_tx = broadcasted.pop().unwrap();
10347+
10348+
// Confirm the splice on both A and B before B receives A's delayed
10349+
// `tx_signatures`. This mirrors the fuzz timeline where one side's
10350+
// broadcast can reach chain before the reciprocal message reaches its peer.
10351+
mine_transaction(initiator, &splice_tx);
10352+
mine_transaction(acceptor, &splice_tx);
10353+
let _ = get_event!(initiator, Event::SpliceNegotiated);
10354+
10355+
// Claiming the forwarded payment at C creates an HTLC fulfill that B must
10356+
// propagate backward over the same A-B channel that is being spliced.
10357+
nodes[2].node.claim_funds(payment_preimage);
10358+
check_added_monitors(&nodes[2], 1);
10359+
expect_payment_claimed!(nodes[2], payment_hash, 1_000_000);
10360+
10361+
let mut commitment_update = get_htlc_update_msgs(&nodes[2], &acceptor_node_id);
10362+
assert_eq!(commitment_update.update_fulfill_htlcs.len(), 1);
10363+
// Deliver only the fulfill to B and make B's A-B monitor update stay
10364+
// in-flight. This monitor update is unrelated to splice tx signatures: it
10365+
// durably records the payment preimage so B can safely settle the incoming
10366+
// HTLC from A.
10367+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
10368+
acceptor.node.handle_update_fulfill_htlc(
10369+
final_node_id,
10370+
commitment_update.update_fulfill_htlcs.remove(0),
10371+
);
10372+
check_added_monitors(acceptor, 1);
10373+
assert!(acceptor.node.get_and_clear_pending_msg_events().is_empty());
10374+
10375+
// Deliver A's delayed splice `tx_signatures` while B is waiting on the unrelated HTLC-preimage
10376+
// monitor update. B's `tx_signatures` was already released, so there's no message to send and
10377+
// we should expect the splice negotiation to complete.
10378+
acceptor.node.handle_tx_signatures(initiator_node_id, &delayed_initiator_tx_signatures);
10379+
expect_splice_pending_event(acceptor, &initiator_node_id);
10380+
10381+
// Finally, drive the state machines to completion.
10382+
acceptor.chain_monitor.complete_sole_pending_chan_update(&channel_id);
10383+
let mut update_fulfill = get_htlc_update_msgs(acceptor, &initiator_node_id);
10384+
check_added_monitors(acceptor, 1);
10385+
let payment_forwarded = get_event!(acceptor, Event::PaymentForwarded);
10386+
expect_payment_forwarded(
10387+
payment_forwarded,
10388+
acceptor,
10389+
initiator,
10390+
&nodes[2],
10391+
Some(1000),
10392+
None,
10393+
false,
10394+
false,
10395+
false,
10396+
);
10397+
10398+
do_commitment_signed_dance(
10399+
acceptor,
10400+
&nodes[2],
10401+
&commitment_update.commitment_signed,
10402+
false,
10403+
false,
10404+
);
10405+
10406+
initiator.node.handle_update_fulfill_htlc(
10407+
acceptor_node_id,
10408+
update_fulfill.update_fulfill_htlcs.remove(0),
10409+
);
10410+
do_commitment_signed_dance(
10411+
initiator,
10412+
acceptor,
10413+
&update_fulfill.commitment_signed,
10414+
false,
10415+
false,
10416+
);
10417+
expect_payment_sent(initiator, payment_preimage, None, true, true);
10418+
}

0 commit comments

Comments
 (0)