Skip to content

Commit 20fff12

Browse files
committed
Track HTLC resolving transaction to determine input index
1 parent 55ebaff commit 20fff12

File tree

2 files changed

+61
-32
lines changed

2 files changed

+61
-32
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ struct IrrevocablyResolvedHTLC {
643643
/// was not present in the confirmed commitment transaction), HTLC-Success, or HTLC-Timeout
644644
/// transaction.
645645
resolving_txid: Option<Txid>, // Added as optional, but always filled in, in 0.0.110
646+
resolving_tx: Option<Transaction>,
646647
/// Only set if the HTLC claim was ours using a payment preimage
647648
payment_preimage: Option<PaymentPreimage>,
648649
}
@@ -658,6 +659,7 @@ impl Writeable for IrrevocablyResolvedHTLC {
658659
(0, mapped_commitment_tx_output_idx, required),
659660
(1, self.resolving_txid, option),
660661
(2, self.payment_preimage, option),
662+
(3, self.resolving_tx, option),
661663
});
662664
Ok(())
663665
}
@@ -668,15 +670,18 @@ impl Readable for IrrevocablyResolvedHTLC {
668670
let mut mapped_commitment_tx_output_idx = 0;
669671
let mut resolving_txid = None;
670672
let mut payment_preimage = None;
673+
let mut resolving_tx = None;
671674
read_tlv_fields!(reader, {
672675
(0, mapped_commitment_tx_output_idx, required),
673676
(1, resolving_txid, option),
674677
(2, payment_preimage, option),
678+
(3, resolving_tx, option),
675679
});
676680
Ok(Self {
677681
commitment_tx_output_idx: if mapped_commitment_tx_output_idx == u32::max_value() { None } else { Some(mapped_commitment_tx_output_idx) },
678682
resolving_txid,
679683
payment_preimage,
684+
resolving_tx,
680685
})
681686
}
682687
}
@@ -1510,24 +1515,24 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15101515
let htlc_commitment_tx_output_idx =
15111516
if let Some(v) = htlc.transaction_output_index { v } else { return None; };
15121517

1513-
let mut htlc_spend_txid_opt = None;
1518+
let mut htlc_spend_tx_opt = None;
15141519
let mut holder_timeout_spend_pending = None;
15151520
let mut htlc_spend_pending = None;
15161521
let mut holder_delayed_output_pending = None;
15171522
for event in self.onchain_events_awaiting_threshold_conf.iter() {
15181523
match event.event {
15191524
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
15201525
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
1521-
debug_assert!(htlc_spend_txid_opt.is_none());
1522-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1526+
debug_assert!(htlc_spend_tx_opt.is_none());
1527+
htlc_spend_tx_opt = event.transaction.clone();
15231528
debug_assert!(holder_timeout_spend_pending.is_none());
15241529
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
15251530
holder_timeout_spend_pending = Some(event.confirmation_threshold());
15261531
},
15271532
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
15281533
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
1529-
debug_assert!(htlc_spend_txid_opt.is_none());
1530-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1534+
debug_assert!(htlc_spend_tx_opt.is_none());
1535+
htlc_spend_tx_opt = event.transaction.clone();
15311536
debug_assert!(htlc_spend_pending.is_none());
15321537
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
15331538
},
@@ -1542,20 +1547,22 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15421547
}
15431548
let htlc_resolved = self.htlcs_resolved_on_chain.iter()
15441549
.find(|v| if v.commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) {
1545-
debug_assert!(htlc_spend_txid_opt.is_none());
1546-
htlc_spend_txid_opt = v.resolving_txid;
1550+
debug_assert!(htlc_spend_tx_opt.is_none());
1551+
htlc_spend_tx_opt = v.resolving_tx.clone();
15471552
true
15481553
} else { false });
15491554
debug_assert!(holder_timeout_spend_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
15501555

1556+
let htlc_commitment_outpoint = BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx);
15511557
let htlc_output_to_spend =
1552-
if let Some(txid) = htlc_spend_txid_opt {
1553-
debug_assert!(
1554-
self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1555-
"This code needs updating for anchors");
1556-
BitcoinOutPoint::new(txid, 0)
1558+
if let Some(ref tx) = htlc_spend_tx_opt {
1559+
let htlc_input_idx = tx.input.iter().enumerate()
1560+
.find(|(_, input)| input.previous_output == htlc_commitment_outpoint)
1561+
.map(|(idx, _)| idx as u32)
1562+
.unwrap();
1563+
BitcoinOutPoint::new(tx.txid(), htlc_input_idx)
15571564
} else {
1558-
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1565+
htlc_commitment_outpoint
15591566
};
15601567
let htlc_output_spend_pending = self.onchain_tx_handler.is_output_spend_pending(&htlc_output_to_spend);
15611568

@@ -1578,9 +1585,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
15781585
descriptor: SpendableOutputDescriptor::StaticOutput { .. }
15791586
} = &event.event {
15801587
if event.transaction.as_ref().map(|tx| tx.input.iter().any(|inp| {
1581-
if let Some(htlc_spend_txid) = htlc_spend_txid_opt {
1582-
Some(tx.txid()) == htlc_spend_txid_opt ||
1583-
inp.previous_output.txid == htlc_spend_txid
1588+
if let Some(ref htlc_spend_tx) = htlc_spend_tx_opt {
1589+
let htlc_spend_txid = htlc_spend_tx.txid();
1590+
tx.txid() == htlc_spend_txid || inp.previous_output.txid == htlc_spend_txid
15841591
} else {
15851592
Some(inp.previous_output.txid) == confirmed_txid &&
15861593
inp.previous_output.vout == htlc_commitment_tx_output_idx
@@ -3048,7 +3055,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30483055
htlc_value_satoshis,
30493056
}));
30503057
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
3051-
commitment_tx_output_idx, resolving_txid: Some(entry.txid),
3058+
commitment_tx_output_idx,
3059+
resolving_txid: Some(entry.txid),
3060+
resolving_tx: entry.transaction,
30523061
payment_preimage: None,
30533062
});
30543063
},
@@ -3060,7 +3069,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
30603069
},
30613070
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } => {
30623071
self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC {
3063-
commitment_tx_output_idx: Some(commitment_tx_output_idx), resolving_txid: Some(entry.txid),
3072+
commitment_tx_output_idx: Some(commitment_tx_output_idx),
3073+
resolving_txid: Some(entry.txid),
3074+
resolving_tx: entry.transaction,
30643075
payment_preimage: preimage,
30653076
});
30663077
},

lightning/src/util/events.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,37 @@ pub struct AnchorDescriptor {
227227
pub outpoint: OutPoint,
228228
}
229229

230+
#[cfg(anchors)]
231+
/// A descriptor used to sign for a commitment transaction's HTLC output.
232+
#[derive(Clone, Debug)]
233+
pub enum HTLCDescriptor {
234+
/// A variant used to sign for HTLC inputs being spent by their pre-signed second-stage
235+
/// transactions.
236+
SecondStage {
237+
/// A unique identifier used along with `channel_value_satoshis` to re-derive the
238+
/// [`InMemorySigner`] required to sign `input`.
239+
///
240+
/// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
241+
channel_keys_id: [u8; 32],
242+
/// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
243+
/// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
244+
/// `input`.
245+
///
246+
/// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
247+
channel_value_satoshis: u64,
248+
/// The amount of the HTLC output in the commitment transaction.
249+
amount: u64,
250+
/// The number of the commitment transaction in which the HTLC output lives.
251+
per_commitment_number: u64,
252+
/// The redeem script that satisfies the HTLC output script.
253+
redeem_script: Script,
254+
/// The preimage, if one exists, to claim the HTLC output with.
255+
preimage: Option<PaymentPreimage>,
256+
/// The counterparty's signature required to spend the HTLC output.
257+
counterparty_sig: Signature
258+
}
259+
}
260+
230261
#[cfg(anchors)]
231262
/// Represents the different types of transactions, originating from LDK, to be bumped.
232263
#[derive(Clone, Debug)]
@@ -239,7 +270,7 @@ pub enum BumpTransactionEvent {
239270
/// with additional inputs to meet the target feerate. Failure to meet the target feerate
240271
/// decreases the confirmation odds of the transaction package (which includes the commitment
241272
/// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
242-
/// is constructed, it must be fully signed for and broadcasted by the consumer of the event
273+
/// is constructed, it must be fully signed for and broadcast by the consumer of the event
243274
/// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
244275
/// broadcast first, as the child anchor transaction depends on it.
245276
///
@@ -328,19 +359,6 @@ pub enum BumpTransactionEvent {
328359
},
329360
}
330361

331-
#[derive(Clone, Debug)]
332-
pub enum HTLCDescriptor {
333-
SecondStage {
334-
channel_keys_id: [u8; 32],
335-
channel_value_satoshis: u64,
336-
amount: u64,
337-
per_commitment_number: u64,
338-
redeem_script: Script,
339-
preimage: Option<PaymentPreimage>,
340-
counterparty_sig: Signature
341-
}
342-
}
343-
344362
/// An Event which you should probably take some action in response to.
345363
///
346364
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use

0 commit comments

Comments
 (0)