Skip to content

Commit 72c5423

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 4b3afdd commit 72c5423

File tree

3 files changed

+95
-33
lines changed

3 files changed

+95
-33
lines changed

src/ln/channelmonitor.rs

Lines changed: 74 additions & 31 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
@@ -462,7 +459,8 @@ impl PartialEq for ChannelMonitor {
462459
self.current_remote_commitment_number != other.current_remote_commitment_number ||
463460
self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
464461
self.payment_preimages != other.payment_preimages ||
465-
self.destination_script != other.destination_script
462+
self.destination_script != other.destination_script ||
463+
self.htlc_updated_waiting_threshold_conf != other.htlc_updated_waiting_threshold_conf
466464
{
467465
false
468466
} else {
@@ -512,6 +510,8 @@ impl ChannelMonitor {
512510
payment_preimages: HashMap::new(),
513511
destination_script: destination_script,
514512

513+
htlc_updated_waiting_threshold_conf: HashMap::new(),
514+
515515
last_block_hash: Default::default(),
516516
secp_ctx: Secp256k1::new(),
517517
logger,
@@ -1019,6 +1019,17 @@ impl ChannelMonitor {
10191019
self.last_block_hash.write(writer)?;
10201020
self.destination_script.write(writer)?;
10211021

1022+
writer.write_all(&byte_utils::be64_to_array(self.htlc_updated_waiting_threshold_conf.len() as u64))?;
1023+
for (ref target, ref updates) in self.htlc_updated_waiting_threshold_conf.iter() {
1024+
writer.write_all(&byte_utils::be32_to_array(**target))?;
1025+
writer.write_all(&byte_utils::be64_to_array(updates.len() as u64))?;
1026+
for ref update in updates.iter() {
1027+
update.0.write(writer)?;
1028+
update.1.write(writer)?;
1029+
update.2.write(writer)?;
1030+
}
1031+
}
1032+
10221033
Ok(())
10231034
}
10241035

@@ -1082,13 +1093,12 @@ impl ChannelMonitor {
10821093
/// HTLC-Success/HTLC-Timeout transactions.
10831094
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
10841095
/// revoked remote commitment tx
1085-
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)>) {
1096+
fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32, fee_estimator: &FeeEstimator) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>) {
10861097
// Most secp and related errors trying to create keys means we have no hope of constructing
10871098
// a spend transaction...so we return no transactions to broadcast
10881099
let mut txn_to_broadcast = Vec::new();
10891100
let mut watch_outputs = Vec::new();
10901101
let mut spendable_outputs = Vec::new();
1091-
let mut htlc_updated = Vec::new();
10921102

10931103
let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
10941104
let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
@@ -1097,7 +1107,7 @@ impl ChannelMonitor {
10971107
( $thing : expr ) => {
10981108
match $thing {
10991109
Ok(a) => a,
1100-
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1110+
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
11011111
}
11021112
};
11031113
}
@@ -1122,7 +1132,7 @@ impl ChannelMonitor {
11221132
};
11231133
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()));
11241134
let a_htlc_key = match self.their_htlc_base_key {
1125-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1135+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
11261136
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)),
11271137
};
11281138

@@ -1204,7 +1214,7 @@ impl ChannelMonitor {
12041214
if transaction_output_index as usize >= tx.output.len() ||
12051215
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
12061216
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1207-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1217+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
12081218
}
12091219
let input = TxIn {
12101220
previous_output: BitcoinOutPoint {
@@ -1249,16 +1259,22 @@ impl ChannelMonitor {
12491259
watch_outputs.append(&mut tx.output.clone());
12501260
self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
12511261

1252-
// TODO: We really should only fail backwards after our revocation claims have been
1253-
// confirmed, but we also need to do more other tracking of in-flight pre-confirm
1254-
// on-chain claims, so we can do that at the same time.
12551262
macro_rules! check_htlc_fails {
12561263
($txid: expr, $commitment_tx: expr) => {
12571264
if let Some(ref outpoints) = self.remote_claimable_outpoints.get($txid) {
12581265
for &(ref htlc, ref source_option) in outpoints.iter() {
12591266
if let &Some(ref source) = source_option {
1260-
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);
1261-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1267+
log_info!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, height + HTLC_FAIL_ANTI_REORG_DELAY - 1);
1268+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1269+
hash_map::Entry::Occupied(mut entry) => {
1270+
let e = entry.get_mut();
1271+
e.retain(|ref update| update.0 != **source);
1272+
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1273+
}
1274+
hash_map::Entry::Vacant(entry) => {
1275+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1276+
}
1277+
}
12621278
}
12631279
}
12641280
}
@@ -1274,7 +1290,7 @@ impl ChannelMonitor {
12741290
}
12751291
// No need to check local commitment txn, symmetric HTLCSource must be present as per-htlc data on remote commitment tx
12761292
}
1277-
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
1293+
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
12781294

12791295
let outputs = vec!(TxOut {
12801296
script_pubkey: self.destination_script.clone(),
@@ -1289,7 +1305,7 @@ impl ChannelMonitor {
12891305
let predicted_weight = spend_tx.get_weight() + Self::get_witnesses_weight(&input_descriptors[..]);
12901306

12911307
if !subtract_high_prio_fee!(self, fee_estimator, spend_tx.output[0].value, predicted_weight, tx.txid()) {
1292-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated);
1308+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs);
12931309
}
12941310

12951311
let mut values_drain = values.drain(..);
@@ -1319,9 +1335,6 @@ impl ChannelMonitor {
13191335

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

1322-
// TODO: We really should only fail backwards after our revocation claims have been
1323-
// confirmed, but we also need to do more other tracking of in-flight pre-confirm
1324-
// on-chain claims, so we can do that at the same time.
13251338
macro_rules! check_htlc_fails {
13261339
($txid: expr, $commitment_tx: expr, $id: tt) => {
13271340
if let Some(ref latest_outpoints) = self.remote_claimable_outpoints.get($txid) {
@@ -1342,7 +1355,16 @@ impl ChannelMonitor {
13421355
}
13431356
}
13441357
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);
1345-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1358+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1359+
hash_map::Entry::Occupied(mut entry) => {
1360+
let e = entry.get_mut();
1361+
e.retain(|ref update| update.0 != **source);
1362+
e.push(((**source).clone(), None, htlc.payment_hash.clone()));
1363+
}
1364+
hash_map::Entry::Vacant(entry) => {
1365+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1366+
}
1367+
}
13461368
}
13471369
}
13481370
}
@@ -1375,7 +1397,7 @@ impl ChannelMonitor {
13751397
},
13761398
};
13771399
let a_htlc_key = match self.their_htlc_base_key {
1378-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1400+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
13791401
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
13801402
};
13811403

@@ -1431,7 +1453,7 @@ impl ChannelMonitor {
14311453
if transaction_output_index as usize >= tx.output.len() ||
14321454
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
14331455
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1434-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1456+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
14351457
}
14361458
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
14371459
let input = TxIn {
@@ -1499,7 +1521,7 @@ impl ChannelMonitor {
14991521
}
15001522
}
15011523

1502-
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
1524+
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
15031525

15041526
let outputs = vec!(TxOut {
15051527
script_pubkey: self.destination_script.clone(),
@@ -1513,7 +1535,7 @@ impl ChannelMonitor {
15131535
};
15141536
let predicted_weight = spend_tx.get_weight() + Self::get_witnesses_weight(&input_descriptors[..]);
15151537
if !subtract_high_prio_fee!(self, fee_estimator, spend_tx.output[0].value, predicted_weight, tx.txid()) {
1516-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated);
1538+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs);
15171539
}
15181540

15191541
let mut values_drain = values.drain(..);
@@ -1534,7 +1556,7 @@ impl ChannelMonitor {
15341556
}
15351557
}
15361558

1537-
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1559+
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
15381560
}
15391561

15401562
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1811,7 +1833,7 @@ impl ChannelMonitor {
18111833
}
18121834
};
18131835
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) {
1814-
let (remote_txn, new_outputs, mut spendable_output, mut updated) = self.check_spend_remote_transaction(tx, height, fee_estimator);
1836+
let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height, fee_estimator);
18151837
txn = remote_txn;
18161838
spendable_outputs.append(&mut spendable_output);
18171839
if !new_outputs.1.is_empty() {
@@ -1830,9 +1852,6 @@ impl ChannelMonitor {
18301852
spendable_outputs.push(spendable_output);
18311853
}
18321854
}
1833-
if updated.len() > 0 {
1834-
htlc_updated.append(&mut updated);
1835-
}
18361855
} else {
18371856
if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) {
18381857
let (tx, spendable_output) = self.check_spend_remote_htlc(tx, commitment_number, fee_estimator);
@@ -1883,6 +1902,12 @@ impl ChannelMonitor {
18831902
}
18841903
}
18851904
}
1905+
if let Some(updates) = self.htlc_updated_waiting_threshold_conf.remove(&height) {
1906+
for update in updates {
1907+
log_trace!(self, "HTLC {} failure update has get enough confirmation to be pass upstream", log_bytes!((update.2).0));
1908+
htlc_updated.push(update);
1909+
}
1910+
}
18861911
self.last_block_hash = block_hash.clone();
18871912
(watch_outputs, spendable_outputs, htlc_updated)
18881913
}
@@ -2283,6 +2308,21 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
22832308
let last_block_hash: Sha256dHash = Readable::read(reader)?;
22842309
let destination_script = Readable::read(reader)?;
22852310

2311+
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
2312+
let mut htlc_updated_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
2313+
for _ in 0..waiting_threshold_conf_len {
2314+
let height_target = Readable::read(reader)?;
2315+
let updates_len: u64 = Readable::read(reader)?;
2316+
let mut updates = Vec::with_capacity(cmp::min(updates_len as usize, MAX_ALLOC_SIZE / 128));
2317+
for _ in 0..updates_len {
2318+
let htlc_source = Readable::read(reader)?;
2319+
let preimage = Readable::read(reader)?;
2320+
let hash = Readable::read(reader)?;
2321+
updates.push((htlc_source, preimage, hash));
2322+
}
2323+
htlc_updated_waiting_threshold_conf.insert(height_target, updates);
2324+
}
2325+
22862326
Ok((last_block_hash.clone(), ChannelMonitor {
22872327
commitment_transaction_number_obscure_factor,
22882328

@@ -2306,6 +2346,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
23062346
payment_preimages,
23072347

23082348
destination_script,
2349+
2350+
htlc_updated_waiting_threshold_conf,
2351+
23092352
last_block_hash,
23102353
secp_ctx,
23112354
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 + 1 {
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)