Skip to content

Commit a63811d

Browse files
committed
Update HTLC script detection to check for anchor output variants
1 parent b765be4 commit a63811d

File tree

4 files changed

+42
-18
lines changed

4 files changed

+42
-18
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3131,7 +3131,11 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
31313131
'outer_loop: for input in &tx.input {
31323132
let mut payment_data = None;
31333133
let witness_items = input.witness.len();
3134-
let htlctype = input.witness.last().map(|w| w.len()).and_then(HTLCType::scriptlen_to_htlctype);
3134+
let htlctype = if let Some(last_item) = input.witness.last() {
3135+
HTLCType::scriptlen_to_htlctype(last_item.len(), self.onchain_tx_handler.opt_anchors())
3136+
} else {
3137+
None
3138+
};
31353139
let prev_last_witness_len = input.witness.second_to_last().map(|w| w.len()).unwrap_or(0);
31363140
let revocation_sig_claim = (witness_items == 3 && htlctype == Some(HTLCType::OfferedHTLC) && prev_last_witness_len == 33)
31373141
|| (witness_items == 3 && htlctype == Some(HTLCType::AcceptedHTLC) && prev_last_witness_len == 33);

lightning/src/ln/chan_utils.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,25 @@ pub(crate) enum HTLCType {
6767

6868
impl HTLCType {
6969
/// Check if a given tx witnessScript len matchs one of a pre-signed HTLC
70-
pub(crate) fn scriptlen_to_htlctype(witness_script_len: usize) -> Option<HTLCType> {
71-
if witness_script_len == 133 {
72-
Some(HTLCType::OfferedHTLC)
73-
} else if witness_script_len >= 136 && witness_script_len <= 139 {
74-
Some(HTLCType::AcceptedHTLC)
70+
pub(crate) fn scriptlen_to_htlctype(witness_script_len: usize, opt_anchors: bool) -> Option<HTLCType> {
71+
if opt_anchors {
72+
if witness_script_len == 136 {
73+
Some(HTLCType::OfferedHTLC)
74+
} else if witness_script_len >= 139 && witness_script_len <= 143 {
75+
// Variable length due to CLTV expiry pushed as a VarInt.
76+
Some(HTLCType::AcceptedHTLC)
77+
} else {
78+
None
79+
}
7580
} else {
76-
None
81+
if witness_script_len == 133 {
82+
Some(HTLCType::OfferedHTLC)
83+
} else if witness_script_len >= 136 && witness_script_len <= 140 {
84+
// Variable length due to CLTV expiry pushed as a VarInt.
85+
Some(HTLCType::AcceptedHTLC)
86+
} else {
87+
None
88+
}
7789
}
7890
}
7991
}
@@ -285,7 +297,7 @@ pub fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_com
285297

286298
/// Derives a per-commitment-transaction revocation key from its constituent parts.
287299
///
288-
/// Only the cheating participant owns a valid witness to propagate a revoked
300+
/// Only the cheating participant owns a valid witness to propagate a revoked
289301
/// commitment transaction, thus per_commitment_secret always come from cheater
290302
/// and revocation_base_secret always come from punisher, which is the broadcaster
291303
/// of the transaction spending with this key knowledge.
@@ -320,7 +332,7 @@ pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1
320332
/// the public equivalend of derive_private_revocation_key - using only public keys to derive a
321333
/// public key instead of private keys.
322334
///
323-
/// Only the cheating participant owns a valid witness to propagate a revoked
335+
/// Only the cheating participant owns a valid witness to propagate a revoked
324336
/// commitment transaction, thus per_commitment_point always come from cheater
325337
/// and revocation_base_point always come from punisher, which is the broadcaster
326338
/// of the transaction spending with this key knowledge.

lightning/src/ln/functional_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9454,7 +9454,7 @@ fn test_invalid_funding_tx() {
94549454
// a panic as we'd try to extract a 32 byte preimage from a witness element without checking
94559455
// its length.
94569456
let mut wit_program: Vec<u8> = channelmonitor::deliberately_bogus_accepted_htlc_witness_program();
9457-
assert!(chan_utils::HTLCType::scriptlen_to_htlctype(wit_program.len()).unwrap() ==
9457+
assert!(chan_utils::HTLCType::scriptlen_to_htlctype(wit_program.len(), false).unwrap() ==
94589458
chan_utils::HTLCType::AcceptedHTLC);
94599459

94609460
let wit_program_script: Script = wit_program.clone().into();

lightning/src/util/macro_logger.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,30 @@ pub(crate) struct DebugTx<'a>(pub &'a Transaction);
9090
impl<'a> core::fmt::Display for DebugTx<'a> {
9191
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
9292
if self.0.input.len() >= 1 && self.0.input.iter().any(|i| !i.witness.is_empty()) {
93-
if self.0.input.len() == 1 && self.0.input[0].witness.last().unwrap().len() == 71 &&
93+
let witness_script_len = self.0.input[0].witness.last().unwrap().len();
94+
let is_offered_htlc_script = HTLCType::scriptlen_to_htlctype(witness_script_len, false) == Some(HTLCType::OfferedHTLC) ||
95+
HTLCType::scriptlen_to_htlctype(witness_script_len, true) == Some(HTLCType::OfferedHTLC);
96+
let is_accepted_htlc_script = HTLCType::scriptlen_to_htlctype(witness_script_len, false) == Some(HTLCType::AcceptedHTLC) ||
97+
HTLCType::scriptlen_to_htlctype(witness_script_len, true) == Some(HTLCType::AcceptedHTLC);
98+
if self.0.input.len() == 1 && witness_script_len == 71 &&
9499
(self.0.input[0].sequence.0 >> 8*3) as u8 == 0x80 {
95100
write!(f, "commitment tx ")?;
96-
} else if self.0.input.len() == 1 && self.0.input[0].witness.last().unwrap().len() == 71 {
101+
} else if self.0.input.len() == 1 && witness_script_len == 71 {
97102
write!(f, "closing tx ")?;
98-
} else if self.0.input.len() == 1 && HTLCType::scriptlen_to_htlctype(self.0.input[0].witness.last().unwrap().len()) == Some(HTLCType::OfferedHTLC) &&
99-
self.0.input[0].witness.len() == 5 {
103+
} else if is_offered_htlc_script && self.0.input[0].witness.len() == 5 {
100104
write!(f, "HTLC-timeout tx ")?;
101-
} else if self.0.input.len() == 1 && HTLCType::scriptlen_to_htlctype(self.0.input[0].witness.last().unwrap().len()) == Some(HTLCType::AcceptedHTLC) &&
102-
self.0.input[0].witness.len() == 5 {
105+
} else if is_accepted_htlc_script && self.0.input[0].witness.len() == 5 {
103106
write!(f, "HTLC-success tx ")?;
104107
} else {
105108
for inp in &self.0.input {
106109
if !inp.witness.is_empty() {
107-
if HTLCType::scriptlen_to_htlctype(inp.witness.last().unwrap().len()) == Some(HTLCType::OfferedHTLC) { write!(f, "preimage-")?; break }
108-
else if HTLCType::scriptlen_to_htlctype(inp.witness.last().unwrap().len()) == Some(HTLCType::AcceptedHTLC) { write!(f, "timeout-")?; break }
110+
let witness_script_len = inp.witness.last().unwrap().len();
111+
let is_offered_htlc_script = HTLCType::scriptlen_to_htlctype(witness_script_len, false) == Some(HTLCType::OfferedHTLC) ||
112+
HTLCType::scriptlen_to_htlctype(witness_script_len, true) == Some(HTLCType::OfferedHTLC);
113+
let is_accepted_htlc_script = HTLCType::scriptlen_to_htlctype(witness_script_len, false) == Some(HTLCType::AcceptedHTLC) ||
114+
HTLCType::scriptlen_to_htlctype(witness_script_len, true) == Some(HTLCType::AcceptedHTLC);
115+
if is_offered_htlc_script { write!(f, "preimage-")?; break }
116+
else if is_accepted_htlc_script { write!(f, "timeout-")?; break }
109117
}
110118
}
111119
write!(f, "tx ")?;

0 commit comments

Comments
 (0)