Skip to content

Commit af02d10

Browse files
committed
Track HTLC resolving transaction to determine input index
1 parent 36e6023 commit af02d10

File tree

2 files changed

+39
-13
lines changed

2 files changed

+39
-13
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ struct IrrevocablyResolvedHTLC {
647647
/// was not present in the confirmed commitment transaction), HTLC-Success, or HTLC-Timeout
648648
/// transaction.
649649
resolving_txid: Option<Txid>, // Added as optional, but always filled in, in 0.0.110
650+
resolving_tx: Option<Transaction>,
650651
/// Only set if the HTLC claim was ours using a payment preimage
651652
payment_preimage: Option<PaymentPreimage>,
652653
}
@@ -662,6 +663,7 @@ impl Writeable for IrrevocablyResolvedHTLC {
662663
(0, mapped_commitment_tx_output_idx, required),
663664
(1, self.resolving_txid, option),
664665
(2, self.payment_preimage, option),
666+
(3, self.resolving_tx, option),
665667
});
666668
Ok(())
667669
}
@@ -672,15 +674,18 @@ impl Readable for IrrevocablyResolvedHTLC {
672674
let mut mapped_commitment_tx_output_idx = 0;
673675
let mut resolving_txid = None;
674676
let mut payment_preimage = None;
677+
let mut resolving_tx = None;
675678
read_tlv_fields!(reader, {
676679
(0, mapped_commitment_tx_output_idx, required),
677680
(1, resolving_txid, option),
678681
(2, payment_preimage, option),
682+
(3, resolving_tx, option),
679683
});
680684
Ok(Self {
681685
commitment_tx_output_idx: if mapped_commitment_tx_output_idx == u32::max_value() { None } else { Some(mapped_commitment_tx_output_idx) },
682686
resolving_txid,
683687
payment_preimage,
688+
resolving_tx,
684689
})
685690
}
686691
}
@@ -1526,6 +1531,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15261531
if let Some(v) = htlc.transaction_output_index { v } else { return None; };
15271532

15281533
let mut htlc_spend_txid_opt = None;
1534+
let mut htlc_spend_tx_opt = None;
15291535
let mut holder_timeout_spend_pending = None;
15301536
let mut htlc_spend_pending = None;
15311537
let mut holder_delayed_output_pending = None;
@@ -1534,15 +1540,19 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15341540
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
15351541
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
15361542
debug_assert!(htlc_spend_txid_opt.is_none());
1537-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1543+
htlc_spend_txid_opt = Some(&event.txid);
1544+
debug_assert!(htlc_spend_tx_opt.is_none());
1545+
htlc_spend_tx_opt = event.transaction.as_ref();
15381546
debug_assert!(holder_timeout_spend_pending.is_none());
15391547
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
15401548
holder_timeout_spend_pending = Some(event.confirmation_threshold());
15411549
},
15421550
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
15431551
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
15441552
debug_assert!(htlc_spend_txid_opt.is_none());
1545-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1553+
htlc_spend_txid_opt = Some(&event.txid);
1554+
debug_assert!(htlc_spend_tx_opt.is_none());
1555+
htlc_spend_tx_opt = event.transaction.as_ref();
15461556
debug_assert!(htlc_spend_pending.is_none());
15471557
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
15481558
},
@@ -1558,19 +1568,32 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15581568
let htlc_resolved = self.htlcs_resolved_on_chain.iter()
15591569
.find(|v| if v.commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) {
15601570
debug_assert!(htlc_spend_txid_opt.is_none());
1561-
htlc_spend_txid_opt = v.resolving_txid;
1571+
htlc_spend_txid_opt = v.resolving_txid.as_ref();
1572+
debug_assert!(htlc_spend_tx_opt.is_none());
1573+
htlc_spend_tx_opt = v.resolving_tx.as_ref();
15621574
true
15631575
} else { false });
15641576
debug_assert!(holder_timeout_spend_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
15651577

1578+
let htlc_commitment_outpoint = BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx);
15661579
let htlc_output_to_spend =
15671580
if let Some(txid) = htlc_spend_txid_opt {
1568-
debug_assert!(
1569-
self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1570-
"This code needs updating for anchors");
1571-
BitcoinOutPoint::new(txid, 0)
1581+
// Because HTLC transactions either only have 1 input and 1 output (pre-anchors) or
1582+
// are signed with SIGHASH_SINGLE|ANYONECANPAY under BIP-0143 (post-anchors), we can
1583+
// locate the correct output by ensuring its adjacent input spends the HTLC output
1584+
// in the commitment.
1585+
if let Some(ref tx) = htlc_spend_tx_opt {
1586+
let htlc_input_idx_opt = tx.input.iter().enumerate()
1587+
.find(|(_, input)| input.previous_output == htlc_commitment_outpoint)
1588+
.map(|(idx, _)| idx as u32);
1589+
debug_assert!(htlc_input_idx_opt.is_some());
1590+
BitcoinOutPoint::new(*txid, htlc_input_idx_opt.unwrap_or(0))
1591+
} else {
1592+
debug_assert!(!self.onchain_tx_handler.opt_anchors());
1593+
BitcoinOutPoint::new(*txid, 0)
1594+
}
15721595
} else {
1573-
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1596+
htlc_commitment_outpoint
15741597
};
15751598
let htlc_output_spend_pending = self.onchain_tx_handler.is_output_spend_pending(&htlc_output_to_spend);
15761599

@@ -1594,8 +1617,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15941617
} = &event.event {
15951618
if event.transaction.as_ref().map(|tx| tx.input.iter().any(|inp| {
15961619
if let Some(htlc_spend_txid) = htlc_spend_txid_opt {
1597-
Some(tx.txid()) == htlc_spend_txid_opt ||
1598-
inp.previous_output.txid == htlc_spend_txid
1620+
tx.txid() == *htlc_spend_txid || inp.previous_output.txid == *htlc_spend_txid
15991621
} else {
16001622
Some(inp.previous_output.txid) == confirmed_txid &&
16011623
inp.previous_output.vout == htlc_commitment_tx_output_idx
@@ -3074,7 +3096,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30743096
htlc_value_satoshis,
30753097
}));
30763098
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
3077-
commitment_tx_output_idx, resolving_txid: Some(entry.txid),
3099+
commitment_tx_output_idx,
3100+
resolving_txid: Some(entry.txid),
3101+
resolving_tx: entry.transaction,
30783102
payment_preimage: None,
30793103
});
30803104
},
@@ -3087,7 +3111,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30873111
},
30883112
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } => {
30893113
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
3090-
commitment_tx_output_idx: Some(commitment_tx_output_idx), resolving_txid: Some(entry.txid),
3114+
commitment_tx_output_idx: Some(commitment_tx_output_idx),
3115+
resolving_txid: Some(entry.txid),
3116+
resolving_tx: entry.transaction,
30913117
payment_preimage: preimage,
30923118
});
30933119
},

lightning/src/util/events.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub enum BumpTransactionEvent {
249249
/// with additional inputs to meet the target feerate. Failure to meet the target feerate
250250
/// decreases the confirmation odds of the transaction package (which includes the commitment
251251
/// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
252-
/// is constructed, it must be fully signed for and broadcasted by the consumer of the event
252+
/// is constructed, it must be fully signed for and broadcast by the consumer of the event
253253
/// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
254254
/// broadcast first, as the child anchor transaction depends on it.
255255
///

0 commit comments

Comments
 (0)