Skip to content

Commit e45db2b

Browse files
Merge pull request #1691 from TheBlueMatt/2022-08-dust-retry
Correct payment resolution after on chain failure of dust HTLCs
2 parents 8c6cb99 + a795e45 commit e45db2b

File tree

4 files changed

+335
-81
lines changed

4 files changed

+335
-81
lines changed

lightning/src/chain/channelmonitor.rs

+41-15
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ pub enum Balance {
619619
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
620620
#[derive(PartialEq)]
621621
struct IrrevocablyResolvedHTLC {
622-
commitment_tx_output_idx: u32,
622+
commitment_tx_output_idx: Option<u32>,
623623
/// The txid of the transaction which resolved the HTLC, this may be a commitment (if the HTLC
624624
/// was not present in the confirmed commitment transaction), HTLC-Success, or HTLC-Timeout
625625
/// transaction.
@@ -628,11 +628,39 @@ struct IrrevocablyResolvedHTLC {
628628
payment_preimage: Option<PaymentPreimage>,
629629
}
630630

631-
impl_writeable_tlv_based!(IrrevocablyResolvedHTLC, {
632-
(0, commitment_tx_output_idx, required),
633-
(1, resolving_txid, option),
634-
(2, payment_preimage, option),
635-
});
631+
// In LDK versions prior to 0.0.111 commitment_tx_output_idx was not Option-al and
632+
// IrrevocablyResolvedHTLC objects only existed for non-dust HTLCs. This was a bug, but to maintain
633+
// backwards compatibility we must ensure we always write out a commitment_tx_output_idx field,
634+
// using `u32::max_value()` as a sentinal to indicate the HTLC was dust.
635+
impl Writeable for IrrevocablyResolvedHTLC {
636+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
637+
let mapped_commitment_tx_output_idx = self.commitment_tx_output_idx.unwrap_or(u32::max_value());
638+
write_tlv_fields!(writer, {
639+
(0, mapped_commitment_tx_output_idx, required),
640+
(1, self.resolving_txid, option),
641+
(2, self.payment_preimage, option),
642+
});
643+
Ok(())
644+
}
645+
}
646+
647+
impl Readable for IrrevocablyResolvedHTLC {
648+
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
649+
let mut mapped_commitment_tx_output_idx = 0;
650+
let mut resolving_txid = None;
651+
let mut payment_preimage = None;
652+
read_tlv_fields!(reader, {
653+
(0, mapped_commitment_tx_output_idx, required),
654+
(1, resolving_txid, option),
655+
(2, payment_preimage, option),
656+
});
657+
Ok(Self {
658+
commitment_tx_output_idx: if mapped_commitment_tx_output_idx == u32::max_value() { None } else { Some(mapped_commitment_tx_output_idx) },
659+
resolving_txid,
660+
payment_preimage,
661+
})
662+
}
663+
}
636664

637665
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
638666
/// on-chain transactions to ensure no loss of funds occurs.
@@ -1485,7 +1513,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
14851513
}
14861514
}
14871515
let htlc_resolved = self.htlcs_resolved_on_chain.iter()
1488-
.find(|v| if v.commitment_tx_output_idx == htlc_commitment_tx_output_idx {
1516+
.find(|v| if v.commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) {
14891517
debug_assert!(htlc_spend_txid_opt.is_none());
14901518
htlc_spend_txid_opt = v.resolving_txid;
14911519
true
@@ -1775,7 +1803,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
17751803
macro_rules! walk_htlcs {
17761804
($holder_commitment: expr, $htlc_iter: expr) => {
17771805
for (htlc, source) in $htlc_iter {
1778-
if us.htlcs_resolved_on_chain.iter().any(|v| Some(v.commitment_tx_output_idx) == htlc.transaction_output_index) {
1806+
if us.htlcs_resolved_on_chain.iter().any(|v| v.commitment_tx_output_idx == htlc.transaction_output_index) {
17791807
// We should assert that funding_spend_confirmed is_some() here, but we
17801808
// have some unit tests which violate HTLC transaction CSVs entirely and
17811809
// would fail.
@@ -2902,12 +2930,10 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
29022930
source: source.clone(),
29032931
htlc_value_satoshis,
29042932
}));
2905-
if let Some(idx) = commitment_tx_output_idx {
2906-
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
2907-
commitment_tx_output_idx: idx, resolving_txid: Some(entry.txid),
2908-
payment_preimage: None,
2909-
});
2910-
}
2933+
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
2934+
commitment_tx_output_idx, resolving_txid: Some(entry.txid),
2935+
payment_preimage: None,
2936+
});
29112937
},
29122938
OnchainEvent::MaturingOutput { descriptor } => {
29132939
log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
@@ -2917,7 +2943,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
29172943
},
29182944
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } => {
29192945
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
2920-
commitment_tx_output_idx, resolving_txid: Some(entry.txid),
2946+
commitment_tx_output_idx: Some(commitment_tx_output_idx), resolving_txid: Some(entry.txid),
29212947
payment_preimage: preimage,
29222948
});
29232949
},

lightning/src/ln/functional_test_utils.rs

+66
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,72 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &
669669
tx
670670
}
671671

672+
// Receiver must have been initialized with manually_accept_inbound_channels set to true.
673+
pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, receiver: &'a Node<'b, 'c, 'd>, initiator_config: Option<UserConfig>) -> (bitcoin::Transaction, [u8; 32]) {
674+
let initiator_channels = initiator.node.list_usable_channels().len();
675+
let receiver_channels = receiver.node.list_usable_channels().len();
676+
677+
initiator.node.create_channel(receiver.node.get_our_node_id(), 100_000, 10_001, 42, initiator_config).unwrap();
678+
let open_channel = get_event_msg!(initiator, MessageSendEvent::SendOpenChannel, receiver.node.get_our_node_id());
679+
680+
receiver.node.handle_open_channel(&initiator.node.get_our_node_id(), InitFeatures::known(), &open_channel);
681+
let events = receiver.node.get_and_clear_pending_events();
682+
assert_eq!(events.len(), 1);
683+
match events[0] {
684+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
685+
receiver.node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &initiator.node.get_our_node_id(), 0).unwrap();
686+
},
687+
_ => panic!("Unexpected event"),
688+
};
689+
690+
let accept_channel = get_event_msg!(receiver, MessageSendEvent::SendAcceptChannel, initiator.node.get_our_node_id());
691+
assert_eq!(accept_channel.minimum_depth, 0);
692+
initiator.node.handle_accept_channel(&receiver.node.get_our_node_id(), InitFeatures::known(), &accept_channel);
693+
694+
let (temporary_channel_id, tx, _) = create_funding_transaction(&initiator, &receiver.node.get_our_node_id(), 100_000, 42);
695+
initiator.node.funding_transaction_generated(&temporary_channel_id, &receiver.node.get_our_node_id(), tx.clone()).unwrap();
696+
let funding_created = get_event_msg!(initiator, MessageSendEvent::SendFundingCreated, receiver.node.get_our_node_id());
697+
698+
receiver.node.handle_funding_created(&initiator.node.get_our_node_id(), &funding_created);
699+
check_added_monitors!(receiver, 1);
700+
let bs_signed_locked = receiver.node.get_and_clear_pending_msg_events();
701+
assert_eq!(bs_signed_locked.len(), 2);
702+
let as_channel_ready;
703+
match &bs_signed_locked[0] {
704+
MessageSendEvent::SendFundingSigned { node_id, msg } => {
705+
assert_eq!(*node_id, initiator.node.get_our_node_id());
706+
initiator.node.handle_funding_signed(&receiver.node.get_our_node_id(), &msg);
707+
check_added_monitors!(initiator, 1);
708+
709+
assert_eq!(initiator.tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
710+
assert_eq!(initiator.tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0)[0], tx);
711+
712+
as_channel_ready = get_event_msg!(initiator, MessageSendEvent::SendChannelReady, receiver.node.get_our_node_id());
713+
}
714+
_ => panic!("Unexpected event"),
715+
}
716+
match &bs_signed_locked[1] {
717+
MessageSendEvent::SendChannelReady { node_id, msg } => {
718+
assert_eq!(*node_id, initiator.node.get_our_node_id());
719+
initiator.node.handle_channel_ready(&receiver.node.get_our_node_id(), &msg);
720+
}
721+
_ => panic!("Unexpected event"),
722+
}
723+
724+
receiver.node.handle_channel_ready(&initiator.node.get_our_node_id(), &as_channel_ready);
725+
726+
let as_channel_update = get_event_msg!(initiator, MessageSendEvent::SendChannelUpdate, receiver.node.get_our_node_id());
727+
let bs_channel_update = get_event_msg!(receiver, MessageSendEvent::SendChannelUpdate, initiator.node.get_our_node_id());
728+
729+
initiator.node.handle_channel_update(&receiver.node.get_our_node_id(), &bs_channel_update);
730+
receiver.node.handle_channel_update(&initiator.node.get_our_node_id(), &as_channel_update);
731+
732+
assert_eq!(initiator.node.list_usable_channels().len(), initiator_channels + 1);
733+
assert_eq!(receiver.node.list_usable_channels().len(), receiver_channels + 1);
734+
735+
(tx, as_channel_ready.channel_id)
736+
}
737+
672738
pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> Transaction {
673739
let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap();
674740
let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id());

0 commit comments

Comments
 (0)