Skip to content

Commit d5d50a6

Browse files
author
Antoine Riard
committed
Move htlc_updated_waiting_threshold_conf to an OnchainEvent model
We need also to track claim tx until their maturation to know when we may safely remove them from could-be-bumped-txn buffer
1 parent dcd5dda commit d5d50a6

File tree

2 files changed

+141
-45
lines changed

2 files changed

+141
-45
lines changed

src/ln/channelmonitor.rs

Lines changed: 121 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,23 @@ enum InputDescriptors {
338338
RevokedOutput, // either a revoked to_local output on commitment tx, a revoked HTLC-Timeout output or a revoked HTLC-Success output
339339
}
340340

341+
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
342+
/// once they mature to enough confirmations (HTLC_FAIL_ANTI_REORG_DELAY)
343+
#[derive(Clone, PartialEq)]
344+
enum OnchainEvent {
345+
/// Outpoint under claim process by our own tx, once this one get enough confirmations, we remove it from
346+
/// bump-txn candidate buffer.
347+
Claim {
348+
outpoint: BitcoinOutPoint,
349+
},
350+
/// HTLC output getting solved by a timeout, at maturation we pass upstream payment source information to solve
351+
/// inbound HTLC in backward channel. Note, in case of preimage, we pass info to upstream without delay as we can
352+
/// only win from it, so it's never an OnchainEvent
353+
HTLCUpdate {
354+
htlc_update: (HTLCSource, PaymentHash),
355+
},
356+
}
357+
341358
const SERIALIZATION_VERSION: u8 = 1;
342359
const MIN_SERIALIZATION_VERSION: u8 = 1;
343360

@@ -388,7 +405,9 @@ pub struct ChannelMonitor {
388405

389406
destination_script: Script,
390407

391-
htlc_updated_waiting_threshold_conf: HashMap<u32, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>>,
408+
// Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which
409+
// we have to take actions once they reach enough confs. Actions depend on OnchainEvent type.
410+
onchain_events_waiting_threshold_conf: HashMap<u32, Vec<OnchainEvent>>,
392411

393412
// We simply modify last_block_hash in Channel's block_connected so that serialization is
394413
// consistent but hopefully the users' copy handles block_connected in a consistent way.
@@ -420,7 +439,7 @@ impl PartialEq for ChannelMonitor {
420439
self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
421440
self.payment_preimages != other.payment_preimages ||
422441
self.destination_script != other.destination_script ||
423-
self.htlc_updated_waiting_threshold_conf != other.htlc_updated_waiting_threshold_conf
442+
self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf
424443
{
425444
false
426445
} else {
@@ -470,7 +489,7 @@ impl ChannelMonitor {
470489
payment_preimages: HashMap::new(),
471490
destination_script: destination_script,
472491

473-
htlc_updated_waiting_threshold_conf: HashMap::new(),
492+
onchain_events_waiting_threshold_conf: HashMap::new(),
474493

475494
last_block_hash: Default::default(),
476495
secp_ctx: Secp256k1::new(),
@@ -979,14 +998,22 @@ impl ChannelMonitor {
979998
self.last_block_hash.write(writer)?;
980999
self.destination_script.write(writer)?;
9811000

982-
writer.write_all(&byte_utils::be64_to_array(self.htlc_updated_waiting_threshold_conf.len() as u64))?;
983-
for (ref target, ref updates) in self.htlc_updated_waiting_threshold_conf.iter() {
1001+
writer.write_all(&byte_utils::be64_to_array(self.onchain_events_waiting_threshold_conf.len() as u64))?;
1002+
for (ref target, ref events) in self.onchain_events_waiting_threshold_conf.iter() {
9841003
writer.write_all(&byte_utils::be32_to_array(**target))?;
985-
writer.write_all(&byte_utils::be64_to_array(updates.len() as u64))?;
986-
for ref update in updates.iter() {
987-
update.0.write(writer)?;
988-
update.1.write(writer)?;
989-
update.2.write(writer)?;
1004+
writer.write_all(&byte_utils::be64_to_array(events.len() as u64))?;
1005+
for ev in events.iter() {
1006+
match *ev {
1007+
OnchainEvent::Claim { ref outpoint } => {
1008+
writer.write_all(&[0; 1])?;
1009+
outpoint.write(writer)?;
1010+
},
1011+
OnchainEvent::HTLCUpdate { ref htlc_update } => {
1012+
writer.write_all(&[1; 1])?;
1013+
htlc_update.0.write(writer)?;
1014+
htlc_update.1.write(writer)?;
1015+
}
1016+
}
9901017
}
9911018
}
9921019

@@ -1224,14 +1251,21 @@ impl ChannelMonitor {
12241251
for &(ref htlc, ref source_option) in outpoints.iter() {
12251252
if let &Some(ref source) = source_option {
12261253
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction, waiting confirmation until {} height", log_bytes!(htlc.payment_hash.0), $commitment_tx, height + HTLC_FAIL_ANTI_REORG_DELAY - 1);
1227-
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1254+
match self.onchain_events_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
12281255
hash_map::Entry::Occupied(mut entry) => {
12291256
let e = entry.get_mut();
1230-
e.retain(|ref update| update.0 != **source);
1231-
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1257+
e.retain(|ref event| {
1258+
match **event {
1259+
OnchainEvent::HTLCUpdate { ref htlc_update } => {
1260+
return htlc_update.0 != **source
1261+
},
1262+
_ => return true
1263+
}
1264+
});
1265+
e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
12321266
}
12331267
hash_map::Entry::Vacant(entry) => {
1234-
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1268+
entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())}]);
12351269
}
12361270
}
12371271
}
@@ -1311,14 +1345,21 @@ impl ChannelMonitor {
13111345
}
13121346
}
13131347
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of remote commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx);
1314-
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1348+
match self.onchain_events_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
13151349
hash_map::Entry::Occupied(mut entry) => {
13161350
let e = entry.get_mut();
1317-
e.retain(|ref update| update.0 != **source);
1318-
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1351+
e.retain(|ref event| {
1352+
match **event {
1353+
OnchainEvent::HTLCUpdate { ref htlc_update } => {
1354+
return htlc_update.0 != **source
1355+
},
1356+
_ => return true
1357+
}
1358+
});
1359+
e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
13191360
}
13201361
hash_map::Entry::Vacant(entry) => {
1321-
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1362+
entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())}]);
13221363
}
13231364
}
13241365
}
@@ -1690,16 +1731,23 @@ impl ChannelMonitor {
16901731
let mut watch_outputs = Vec::new();
16911732

16921733
macro_rules! wait_threshold_conf {
1693-
($height: expr, $source: expr, $update: expr, $commitment_tx: expr, $payment_hash: expr) => {
1734+
($height: expr, $source: expr, $commitment_tx: expr, $payment_hash: expr) => {
16941735
log_trace!(self, "Failing HTLC with payment_hash {} from {} local commitment tx due to broadcast of transaction, waiting confirmation until {} height", log_bytes!($payment_hash.0), $commitment_tx, height + HTLC_FAIL_ANTI_REORG_DELAY - 1);
1695-
match self.htlc_updated_waiting_threshold_conf.entry($height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1736+
match self.onchain_events_waiting_threshold_conf.entry($height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
16961737
hash_map::Entry::Occupied(mut entry) => {
16971738
let e = entry.get_mut();
1698-
e.retain(|ref update| update.0 != $source);
1699-
e.push(($source, $update, $payment_hash));
1739+
e.retain(|ref event| {
1740+
match **event {
1741+
OnchainEvent::HTLCUpdate { ref htlc_update } => {
1742+
return htlc_update.0 != $source
1743+
},
1744+
_ => return true
1745+
}
1746+
});
1747+
e.push(OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)});
17001748
}
17011749
hash_map::Entry::Vacant(entry) => {
1702-
entry.insert(vec![($source, $update, $payment_hash)]);
1750+
entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)}]);
17031751
}
17041752
}
17051753
}
@@ -1717,7 +1765,7 @@ impl ChannelMonitor {
17171765
for &(ref htlc, _, ref source) in &local_tx.htlc_outputs {
17181766
if htlc.transaction_output_index.is_none() {
17191767
if let &Some(ref source) = source {
1720-
wait_threshold_conf!(height, source.clone(), None, "lastest", htlc.payment_hash.clone());
1768+
wait_threshold_conf!(height, source.clone(), "lastest", htlc.payment_hash.clone());
17211769
}
17221770
}
17231771
}
@@ -1737,7 +1785,7 @@ impl ChannelMonitor {
17371785
for &(ref htlc, _, ref source) in &local_tx.htlc_outputs {
17381786
if htlc.transaction_output_index.is_none() {
17391787
if let &Some(ref source) = source {
1740-
wait_threshold_conf!(height, source.clone(), None, "previous", htlc.payment_hash.clone());
1788+
wait_threshold_conf!(height, source.clone(), "previous", htlc.payment_hash.clone());
17411789
}
17421790
}
17431791
}
@@ -1888,19 +1936,27 @@ impl ChannelMonitor {
18881936
}
18891937
}
18901938
}
1891-
if let Some(updates) = self.htlc_updated_waiting_threshold_conf.remove(&height) {
1892-
for update in updates {
1893-
log_trace!(self, "HTLC {} failure update has get enough confirmation to be pass upstream", log_bytes!((update.2).0));
1894-
htlc_updated.push(update);
1939+
if let Some(events) = self.onchain_events_waiting_threshold_conf.remove(&height) {
1940+
for ev in events {
1941+
match ev {
1942+
OnchainEvent::Claim { outpoint } => {
1943+
},
1944+
OnchainEvent::HTLCUpdate { htlc_update } => {
1945+
log_trace!(self, "HTLC {} failure update has get enough confirmation to be pass upstream", log_bytes!((htlc_update.1).0));
1946+
htlc_updated.push((htlc_update.0, None, htlc_update.1));
1947+
},
1948+
}
18951949
}
18961950
}
18971951
self.last_block_hash = block_hash.clone();
18981952
(watch_outputs, spendable_outputs, htlc_updated)
18991953
}
19001954

19011955
fn block_disconnected(&mut self, height: u32, block_hash: &Sha256dHash) {
1902-
if let Some(_) = self.htlc_updated_waiting_threshold_conf.remove(&(height + HTLC_FAIL_ANTI_REORG_DELAY - 1)) {
1903-
//We discard htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
1956+
if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + HTLC_FAIL_ANTI_REORG_DELAY - 1)) {
1957+
//We may discard:
1958+
//- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
1959+
//- our claim tx on a commitment tx output
19041960
}
19051961
self.last_block_hash = block_hash.clone();
19061962
}
@@ -2082,14 +2138,21 @@ impl ChannelMonitor {
20822138
htlc_updated.push((source, Some(payment_preimage), payment_hash));
20832139
} else {
20842140
log_trace!(self, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting confirmation until {} height", log_bytes!(payment_hash.0), height + HTLC_FAIL_ANTI_REORG_DELAY - 1);
2085-
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
2141+
match self.onchain_events_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
20862142
hash_map::Entry::Occupied(mut entry) => {
20872143
let e = entry.get_mut();
2088-
e.retain(|ref update| update.0 != source);
2089-
e.push((source, None, payment_hash.clone()));
2144+
e.retain(|ref event| {
2145+
match **event {
2146+
OnchainEvent::HTLCUpdate { ref htlc_update } => {
2147+
return htlc_update.0 != source
2148+
},
2149+
_ => return true
2150+
}
2151+
});
2152+
e.push(OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)});
20902153
}
20912154
hash_map::Entry::Vacant(entry) => {
2092-
entry.insert(vec![(source, None, payment_hash)]);
2155+
entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)}]);
20932156
}
20942157
}
20952158
}
@@ -2312,18 +2375,31 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
23122375
let destination_script = Readable::read(reader)?;
23132376

23142377
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
2315-
let mut htlc_updated_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
2378+
let mut onchain_events_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
23162379
for _ in 0..waiting_threshold_conf_len {
23172380
let height_target = Readable::read(reader)?;
2318-
let updates_len: u64 = Readable::read(reader)?;
2319-
let mut updates = Vec::with_capacity(cmp::min(updates_len as usize, MAX_ALLOC_SIZE / 128));
2320-
for _ in 0..updates_len {
2321-
let htlc_source = Readable::read(reader)?;
2322-
let preimage = Readable::read(reader)?;
2323-
let hash = Readable::read(reader)?;
2324-
updates.push((htlc_source, preimage, hash));
2381+
let events_len: u64 = Readable::read(reader)?;
2382+
let mut events = Vec::with_capacity(cmp::min(events_len as usize, MAX_ALLOC_SIZE / 128));
2383+
for _ in 0..events_len {
2384+
let ev = match <u8 as Readable<R>>::read(reader)? {
2385+
0 => {
2386+
let outpoint = Readable::read(reader)?;
2387+
OnchainEvent::Claim {
2388+
outpoint
2389+
}
2390+
},
2391+
1 => {
2392+
let htlc_source = Readable::read(reader)?;
2393+
let hash = Readable::read(reader)?;
2394+
OnchainEvent::HTLCUpdate {
2395+
htlc_update: (htlc_source, hash)
2396+
}
2397+
},
2398+
_ => return Err(DecodeError::InvalidValue),
2399+
};
2400+
events.push(ev);
23252401
}
2326-
htlc_updated_waiting_threshold_conf.insert(height_target, updates);
2402+
onchain_events_waiting_threshold_conf.insert(height_target, events);
23272403
}
23282404

23292405
Ok((last_block_hash.clone(), ChannelMonitor {
@@ -2350,7 +2426,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
23502426

23512427
destination_script,
23522428

2353-
htlc_updated_waiting_threshold_conf,
2429+
onchain_events_waiting_threshold_conf,
23542430

23552431
last_block_hash,
23562432
secp_ctx,

src/util/ser.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::hash::Hash;
99
use secp256k1::Signature;
1010
use secp256k1::key::{PublicKey, SecretKey};
1111
use bitcoin::blockdata::script::Script;
12+
use bitcoin::blockdata::transaction::OutPoint;
1213
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
1314
use std::marker::Sized;
1415
use ln::msgs::DecodeError;
@@ -422,3 +423,22 @@ impl<R, T> Readable<R> for Option<T>
422423
}
423424
}
424425
}
426+
427+
impl Writeable for OutPoint {
428+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
429+
self.txid.write(w)?;
430+
self.vout.write(w)?;
431+
Ok(())
432+
}
433+
}
434+
435+
impl<R: Read> Readable<R> for OutPoint {
436+
fn read(r: &mut R) -> Result<Self, DecodeError> {
437+
let txid = Readable::read(r)?;
438+
let vout = Readable::read(r)?;
439+
Ok(OutPoint {
440+
txid,
441+
vout,
442+
})
443+
}
444+
}

0 commit comments

Comments
 (0)