Skip to content

Commit b5cac14

Browse files
author
Antoine Riard
committed
Track HTLC-failure trigger tx until anti-reorg delay reached
Broadcasting a commitment tx means that we have to fail inbound HTLC in backward channel. Doing it prematurely would put us at risk in case of reorg. So we delay passing failure update upstream until solving tx mature to HTLC_FAIL_ANTI_ REORG_DELAY. Requirements differ if HTLC is a revoked/non-revoked dust/ non-revoked non-dust one. Add connect_blocks in test_utils to fix broken tests due to anti-reorg delay enforcement Remove anti-duplicate htlc update stuff in ManySimpleChannelMonitor
1 parent 06eddc3 commit b5cac14

File tree

3 files changed

+93
-31
lines changed

3 files changed

+93
-31
lines changed

src/ln/channelmonitor.rs

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,6 @@ impl<Key : Send + cmp::Eq + hash::Hash> ChainListener for SimpleManyChannelMonit
178178
// In case of reorg we may have htlc outputs solved in a different way so
179179
// we prefer to keep claims but don't store duplicate updates for a given
180180
// (payment_hash, HTLCSource) pair.
181-
// TODO: Note that we currently don't really use this as ChannelManager
182-
// will fail/claim backwards after the first block. We really should delay
183-
// a few blocks before failing backwards (but can claim backwards
184-
// immediately) as long as we have a few blocks of headroom.
185181
let mut existing_claim = false;
186182
e.get_mut().retain(|htlc_data| {
187183
if htlc.0 == htlc_data.0 {
@@ -306,7 +302,6 @@ pub(crate) const HTLC_FAIL_TIMEOUT_BLOCKS: u32 = 3;
306302
/// Number of blocks we wait on seeing a confirmed HTLC-Timeout or previous revoked commitment
307303
/// transaction before we fail corresponding inbound HTLCs. This prevents us from failing backwards
308304
/// and then getting a reorg resulting in us losing money.
309-
//TODO: We currently don't actually use this...we should
310305
pub(crate) const HTLC_FAIL_ANTI_REORG_DELAY: u32 = 6;
311306

312307
#[derive(Clone, PartialEq)]
@@ -401,6 +396,8 @@ pub struct ChannelMonitor {
401396

402397
destination_script: Script,
403398

399+
htlc_updated_waiting_threshold_conf: HashMap<u32, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>>,
400+
404401
// We simply modify last_block_hash in Channel's block_connected so that serialization is
405402
// consistent but hopefully the users' copy handles block_connected in a consistent way.
406403
// (we do *not*, however, update them in insert_combine to ensure any local user copies keep
@@ -430,7 +427,8 @@ impl PartialEq for ChannelMonitor {
430427
self.current_remote_commitment_number != other.current_remote_commitment_number ||
431428
self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
432429
self.payment_preimages != other.payment_preimages ||
433-
self.destination_script != other.destination_script
430+
self.destination_script != other.destination_script ||
431+
self.htlc_updated_waiting_threshold_conf != other.htlc_updated_waiting_threshold_conf
434432
{
435433
false
436434
} else {
@@ -480,6 +478,8 @@ impl ChannelMonitor {
480478
payment_preimages: HashMap::new(),
481479
destination_script: destination_script,
482480

481+
htlc_updated_waiting_threshold_conf: HashMap::new(),
482+
483483
last_block_hash: Default::default(),
484484
secp_ctx: Secp256k1::new(),
485485
logger,
@@ -987,6 +987,17 @@ impl ChannelMonitor {
987987
self.last_block_hash.write(writer)?;
988988
self.destination_script.write(writer)?;
989989

990+
writer.write_all(&byte_utils::be64_to_array(self.htlc_updated_waiting_threshold_conf.len() as u64))?;
991+
for (ref target, ref updates) in self.htlc_updated_waiting_threshold_conf.iter() {
992+
writer.write_all(&byte_utils::be32_to_array(**target))?;
993+
writer.write_all(&byte_utils::be64_to_array(updates.len() as u64))?;
994+
for ref update in updates.iter() {
995+
update.0.write(writer)?;
996+
update.1.write(writer)?;
997+
update.2.write(writer)?;
998+
}
999+
}
1000+
9901001
Ok(())
9911002
}
9921003

@@ -1050,13 +1061,12 @@ impl ChannelMonitor {
10501061
/// HTLC-Success/HTLC-Timeout transactions.
10511062
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
10521063
/// revoked remote commitment tx
1053-
fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32, fee_estimator: &FeeEstimator) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>) {
1064+
fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32, fee_estimator: &FeeEstimator) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>) {
10541065
// Most secp and related errors trying to create keys means we have no hope of constructing
10551066
// a spend transaction...so we return no transactions to broadcast
10561067
let mut txn_to_broadcast = Vec::new();
10571068
let mut watch_outputs = Vec::new();
10581069
let mut spendable_outputs = Vec::new();
1059-
let mut htlc_updated = Vec::new();
10601070

10611071
let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
10621072
let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
@@ -1065,7 +1075,7 @@ impl ChannelMonitor {
10651075
( $thing : expr ) => {
10661076
match $thing {
10671077
Ok(a) => a,
1068-
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1078+
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
10691079
}
10701080
};
10711081
}
@@ -1090,7 +1100,7 @@ impl ChannelMonitor {
10901100
};
10911101
let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key.unwrap()));
10921102
let a_htlc_key = match self.their_htlc_base_key {
1093-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1103+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
10941104
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &their_htlc_base_key)),
10951105
};
10961106

@@ -1172,7 +1182,7 @@ impl ChannelMonitor {
11721182
if transaction_output_index as usize >= tx.output.len() ||
11731183
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
11741184
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1175-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1185+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
11761186
}
11771187
let input = TxIn {
11781188
previous_output: BitcoinOutPoint {
@@ -1216,16 +1226,22 @@ impl ChannelMonitor {
12161226
watch_outputs.append(&mut tx.output.clone());
12171227
self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
12181228

1219-
// TODO: We really should only fail backwards after our revocation claims have been
1220-
// confirmed, but we also need to do more other tracking of in-flight pre-confirm
1221-
// on-chain claims, so we can do that at the same time.
12221229
macro_rules! check_htlc_fails {
12231230
($txid: expr, $commitment_tx: expr) => {
12241231
if let Some(ref outpoints) = self.remote_claimable_outpoints.get($txid) {
12251232
for &(ref htlc, ref source_option) in outpoints.iter() {
12261233
if let &Some(ref source) = source_option {
1227-
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx);
1228-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1234+
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);
1235+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1236+
hash_map::Entry::Occupied(mut entry) => {
1237+
let e = entry.get_mut();
1238+
e.retain(|ref update| update.0 != **source);
1239+
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1240+
}
1241+
hash_map::Entry::Vacant(entry) => {
1242+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1243+
}
1244+
}
12291245
}
12301246
}
12311247
}
@@ -1241,7 +1257,7 @@ impl ChannelMonitor {
12411257
}
12421258
// No need to check local commitment txn, symmetric HTLCSource must be present as per-htlc data on remote commitment tx
12431259
}
1244-
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); } // Nothing to be done...probably a false positive/local tx
1260+
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
12451261

12461262
let outputs = vec!(TxOut {
12471263
script_pubkey: self.destination_script.clone(),
@@ -1283,9 +1299,6 @@ impl ChannelMonitor {
12831299

12841300
log_trace!(self, "Got broadcast of non-revoked remote commitment transaction {}", commitment_txid);
12851301

1286-
// TODO: We really should only fail backwards after our revocation claims have been
1287-
// confirmed, but we also need to do more other tracking of in-flight pre-confirm
1288-
// on-chain claims, so we can do that at the same time.
12891302
macro_rules! check_htlc_fails {
12901303
($txid: expr, $commitment_tx: expr, $id: tt) => {
12911304
if let Some(ref latest_outpoints) = self.remote_claimable_outpoints.get($txid) {
@@ -1306,7 +1319,16 @@ impl ChannelMonitor {
13061319
}
13071320
}
13081321
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);
1309-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1322+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1323+
hash_map::Entry::Occupied(mut entry) => {
1324+
let e = entry.get_mut();
1325+
e.retain(|ref update| update.0 != **source);
1326+
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1327+
}
1328+
hash_map::Entry::Vacant(entry) => {
1329+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1330+
}
1331+
}
13101332
}
13111333
}
13121334
}
@@ -1339,7 +1361,7 @@ impl ChannelMonitor {
13391361
},
13401362
};
13411363
let a_htlc_key = match self.their_htlc_base_key {
1342-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1364+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
13431365
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
13441366
};
13451367

@@ -1395,7 +1417,7 @@ impl ChannelMonitor {
13951417
if transaction_output_index as usize >= tx.output.len() ||
13961418
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
13971419
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1398-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1420+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
13991421
}
14001422
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
14011423
let input = TxIn {
@@ -1462,7 +1484,7 @@ impl ChannelMonitor {
14621484
}
14631485
}
14641486

1465-
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); } // Nothing to be done...probably a false positive/local tx
1487+
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
14661488

14671489
let outputs = vec!(TxOut {
14681490
script_pubkey: self.destination_script.clone(),
@@ -1495,7 +1517,7 @@ impl ChannelMonitor {
14951517
}
14961518
}
14971519

1498-
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1520+
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
14991521
}
15001522

15011523
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1770,7 +1792,7 @@ impl ChannelMonitor {
17701792
}
17711793
};
17721794
if funding_txo.is_none() || (prevout.txid == funding_txo.as_ref().unwrap().0.txid && prevout.vout == funding_txo.as_ref().unwrap().0.index as u32) {
1773-
let (remote_txn, new_outputs, mut spendable_output, mut updated) = self.check_spend_remote_transaction(tx, height, fee_estimator);
1795+
let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height, fee_estimator);
17741796
txn = remote_txn;
17751797
spendable_outputs.append(&mut spendable_output);
17761798
if !new_outputs.1.is_empty() {
@@ -1789,9 +1811,6 @@ impl ChannelMonitor {
17891811
spendable_outputs.push(spendable_output);
17901812
}
17911813
}
1792-
if updated.len() > 0 {
1793-
htlc_updated.append(&mut updated);
1794-
}
17951814
} else {
17961815
if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) {
17971816
let (tx, spendable_output) = self.check_spend_remote_htlc(tx, commitment_number, fee_estimator);
@@ -1842,6 +1861,12 @@ impl ChannelMonitor {
18421861
}
18431862
}
18441863
}
1864+
if let Some(updates) = self.htlc_updated_waiting_threshold_conf.remove(&height) {
1865+
for update in updates {
1866+
log_trace!(self, "HTLC {} failure update has get enough confirmation to be pass upstream", log_bytes!((update.2).0));
1867+
htlc_updated.push(update);
1868+
}
1869+
}
18451870
self.last_block_hash = block_hash.clone();
18461871
(watch_outputs, spendable_outputs, htlc_updated)
18471872
}
@@ -2242,6 +2267,21 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
22422267
let last_block_hash: Sha256dHash = Readable::read(reader)?;
22432268
let destination_script = Readable::read(reader)?;
22442269

2270+
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
2271+
let mut htlc_updated_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
2272+
for _ in 0..waiting_threshold_conf_len {
2273+
let height_target = Readable::read(reader)?;
2274+
let updates_len: u64 = Readable::read(reader)?;
2275+
let mut updates = Vec::with_capacity(cmp::min(updates_len as usize, MAX_ALLOC_SIZE / 128));
2276+
for _ in 0..updates_len {
2277+
let htlc_source = Readable::read(reader)?;
2278+
let preimage = Readable::read(reader)?;
2279+
let hash = Readable::read(reader)?;
2280+
updates.push((htlc_source, preimage, hash));
2281+
}
2282+
htlc_updated_waiting_threshold_conf.insert(height_target, updates);
2283+
}
2284+
22452285
Ok((last_block_hash.clone(), ChannelMonitor {
22462286
commitment_transaction_number_obscure_factor,
22472287

@@ -2265,6 +2305,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
22652305
payment_preimages,
22662306

22672307
destination_script,
2308+
2309+
htlc_updated_waiting_threshold_conf,
2310+
22682311
last_block_hash,
22692312
secp_ctx,
22702313
logger,

src/ln/functional_test_utils.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use bitcoin::blockdata::transaction::{Transaction, TxOut};
2020
use bitcoin::network::constants::Network;
2121

2222
use bitcoin_hashes::sha256::Hash as Sha256;
23+
use bitcoin_hashes::sha256d::Hash as Sha256d;
2324
use bitcoin_hashes::Hash;
2425

2526
use secp256k1::Secp256k1;
@@ -46,6 +47,15 @@ pub fn confirm_transaction(chain: &chaininterface::ChainWatchInterfaceUtil, tx:
4647
}
4748
}
4849

50+
pub fn connect_blocks(chain: &chaininterface::ChainWatchInterfaceUtil, depth: u32, height: u32, parent: bool, prev_blockhash: Sha256d) {
51+
let mut header = BlockHeader { version: 0x2000000, prev_blockhash: if parent { prev_blockhash } else { Default::default() }, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
52+
chain.block_connected_checked(&header, height + 1, &Vec::new(), &Vec::new());
53+
for i in 2..depth {
54+
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
55+
chain.block_connected_checked(&header, height + i, &Vec::new(), &Vec::new());
56+
}
57+
}
58+
4959
pub struct Node {
5060
pub chain_monitor: Arc<chaininterface::ChainWatchInterfaceUtil>,
5161
pub tx_broadcaster: Arc<test_utils::TestBroadcaster>,

0 commit comments

Comments
 (0)