Skip to content

Commit 6ee473c

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
1 parent 5764634 commit 6ee473c

File tree

3 files changed

+89
-21
lines changed

3 files changed

+89
-21
lines changed

src/ln/channelmonitor.rs

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ pub struct ChannelMonitor {
385385

386386
destination_script: Script,
387387

388+
htlc_updated_waiting_threshold_conf: HashMap<u32, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>>,
389+
388390
// We simply modify last_block_hash in Channel's block_connected so that serialization is
389391
// consistent but hopefully the users' copy handles block_connected in a consistent way.
390392
// (we do *not*, however, update them in insert_combine to ensure any local user copies keep
@@ -414,7 +416,8 @@ impl PartialEq for ChannelMonitor {
414416
self.current_remote_commitment_number != other.current_remote_commitment_number ||
415417
self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
416418
self.payment_preimages != other.payment_preimages ||
417-
self.destination_script != other.destination_script
419+
self.destination_script != other.destination_script ||
420+
self.htlc_updated_waiting_threshold_conf != other.htlc_updated_waiting_threshold_conf
418421
{
419422
false
420423
} else {
@@ -464,6 +467,8 @@ impl ChannelMonitor {
464467
payment_preimages: HashMap::new(),
465468
destination_script: destination_script,
466469

470+
htlc_updated_waiting_threshold_conf: HashMap::new(),
471+
467472
last_block_hash: Default::default(),
468473
secp_ctx: Secp256k1::new(),
469474
logger,
@@ -951,6 +956,17 @@ impl ChannelMonitor {
951956
self.last_block_hash.write(writer)?;
952957
self.destination_script.write(writer)?;
953958

959+
writer.write_all(&byte_utils::be64_to_array(self.htlc_updated_waiting_threshold_conf.len() as u64))?;
960+
for (ref target, ref updates) in self.htlc_updated_waiting_threshold_conf.iter() {
961+
writer.write_all(&byte_utils::be32_to_array(**target))?;
962+
writer.write_all(&byte_utils::be64_to_array(updates.len() as u64))?;
963+
for ref update in updates.iter() {
964+
update.0.write(writer)?;
965+
update.1.write(writer)?;
966+
update.2.write(writer)?;
967+
}
968+
}
969+
954970
Ok(())
955971
}
956972

@@ -1014,13 +1030,12 @@ impl ChannelMonitor {
10141030
/// HTLC-Success/HTLC-Timeout transactions.
10151031
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
10161032
/// revoked remote commitment tx
1017-
fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>) {
1033+
fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>), Vec<SpendableOutputDescriptor>) {
10181034
// Most secp and related errors trying to create keys means we have no hope of constructing
10191035
// a spend transaction...so we return no transactions to broadcast
10201036
let mut txn_to_broadcast = Vec::new();
10211037
let mut watch_outputs = Vec::new();
10221038
let mut spendable_outputs = Vec::new();
1023-
let mut htlc_updated = Vec::new();
10241039

10251040
let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
10261041
let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
@@ -1029,7 +1044,7 @@ impl ChannelMonitor {
10291044
( $thing : expr ) => {
10301045
match $thing {
10311046
Ok(a) => a,
1032-
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1047+
Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
10331048
}
10341049
};
10351050
}
@@ -1054,7 +1069,7 @@ impl ChannelMonitor {
10541069
};
10551070
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()));
10561071
let a_htlc_key = match self.their_htlc_base_key {
1057-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1072+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
10581073
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)),
10591074
};
10601075

@@ -1134,7 +1149,7 @@ impl ChannelMonitor {
11341149
if transaction_output_index as usize >= tx.output.len() ||
11351150
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
11361151
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1137-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1152+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
11381153
}
11391154
let input = TxIn {
11401155
previous_output: BitcoinOutPoint {
@@ -1182,8 +1197,15 @@ impl ChannelMonitor {
11821197
if let Some(ref outpoints) = self.remote_claimable_outpoints.get(&$txid) {
11831198
for &(ref htlc, ref source_option) in outpoints.iter() {
11841199
if let &Some(ref source) = source_option {
1185-
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);
1186-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1200+
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);
1201+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1202+
hash_map::Entry::Occupied(mut entry) => {
1203+
entry.get_mut().push(((**source).clone(), None, htlc.payment_hash.clone()));
1204+
}
1205+
hash_map::Entry::Vacant(entry) => {
1206+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1207+
}
1208+
}
11871209
}
11881210
}
11891211
}
@@ -1199,7 +1221,7 @@ impl ChannelMonitor {
11991221
}
12001222
// No need to check local commitment txn, symmetric HTLCSource must be present as per-htlc data on remote commitment tx
12011223
}
1202-
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
1224+
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx
12031225

12041226
let outputs = vec!(TxOut {
12051227
script_pubkey: self.destination_script.clone(),
@@ -1261,7 +1283,14 @@ impl ChannelMonitor {
12611283
}
12621284
}
12631285
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);
1264-
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
1286+
match self.htlc_updated_waiting_threshold_conf.entry(height + HTLC_FAIL_ANTI_REORG_DELAY - 1) {
1287+
hash_map::Entry::Occupied(mut entry) => {
1288+
entry.get_mut().push(((**source).clone(), None, htlc.payment_hash.clone()));
1289+
}
1290+
hash_map::Entry::Vacant(entry) => {
1291+
entry.insert(vec![((**source).clone(), None, htlc.payment_hash.clone())]);
1292+
}
1293+
}
12651294
}
12661295
}
12671296
}
@@ -1294,7 +1323,7 @@ impl ChannelMonitor {
12941323
},
12951324
};
12961325
let a_htlc_key = match self.their_htlc_base_key {
1297-
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated),
1326+
None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs),
12981327
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
12991328
};
13001329

@@ -1349,7 +1378,7 @@ impl ChannelMonitor {
13491378
if transaction_output_index as usize >= tx.output.len() ||
13501379
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
13511380
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
1352-
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
1381+
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user
13531382
}
13541383
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
13551384
let input = TxIn {
@@ -1412,7 +1441,7 @@ impl ChannelMonitor {
14121441
}
14131442
}
14141443

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

14171446
let outputs = vec!(TxOut {
14181447
script_pubkey: self.destination_script.clone(),
@@ -1442,7 +1471,7 @@ impl ChannelMonitor {
14421471
}
14431472
}
14441473

1445-
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated)
1474+
(txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
14461475
}
14471476

14481477
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1714,7 +1743,7 @@ impl ChannelMonitor {
17141743
}
17151744
};
17161745
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) {
1717-
let (remote_txn, new_outputs, mut spendable_output, mut updated) = self.check_spend_remote_transaction(tx, height);
1746+
let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height);
17181747
txn = remote_txn;
17191748
spendable_outputs.append(&mut spendable_output);
17201749
if !new_outputs.1.is_empty() {
@@ -1733,9 +1762,6 @@ impl ChannelMonitor {
17331762
spendable_outputs.push(spendable_output);
17341763
}
17351764
}
1736-
if updated.len() > 0 {
1737-
htlc_updated.append(&mut updated);
1738-
}
17391765
} else {
17401766
if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) {
17411767
let (tx, spendable_output) = self.check_spend_remote_htlc(tx, commitment_number);
@@ -1786,6 +1812,12 @@ impl ChannelMonitor {
17861812
}
17871813
}
17881814
}
1815+
if let Some(updates) = self.htlc_updated_waiting_threshold_conf.remove(&height) {
1816+
for update in updates {
1817+
log_trace!(self, "HTLC {} failure update has get enough confirmation to be pass upstream", log_bytes!((update.2).0));
1818+
htlc_updated.push(update);
1819+
}
1820+
}
17891821
self.last_block_hash = block_hash.clone();
17901822
(watch_outputs, spendable_outputs, htlc_updated)
17911823
}
@@ -2159,6 +2191,21 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
21592191
let last_block_hash: Sha256dHash = Readable::read(reader)?;
21602192
let destination_script = Readable::read(reader)?;
21612193

2194+
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
2195+
let mut htlc_updated_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
2196+
for _ in 0..waiting_threshold_conf_len {
2197+
let height_target = Readable::read(reader)?;
2198+
let updates_len: u64 = Readable::read(reader)?;
2199+
let mut updates = Vec::with_capacity(cmp::min(updates_len as usize, MAX_ALLOC_SIZE / 128));
2200+
for _ in 0..updates_len {
2201+
let htlc_source = Readable::read(reader)?;
2202+
let preimage = Readable::read(reader)?;
2203+
let hash = Readable::read(reader)?;
2204+
updates.push((htlc_source, preimage, hash));
2205+
}
2206+
htlc_updated_waiting_threshold_conf.insert(height_target, updates);
2207+
}
2208+
21622209
Ok((last_block_hash.clone(), ChannelMonitor {
21632210
commitment_transaction_number_obscure_factor,
21642211

@@ -2182,6 +2229,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
21822229
payment_preimages,
21832230

21842231
destination_script,
2232+
2233+
htlc_updated_waiting_threshold_conf,
2234+
21852235
last_block_hash,
21862236
secp_ctx,
21872237
logger,

src/ln/functional_test_utils.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use util::errors::APIError;
1414
use util::logger::Logger;
1515
use util::config::UserConfig;
1616

17-
use bitcoin::util::hash::BitcoinHash;
17+
use bitcoin::util::hash::{BitcoinHash, Sha256dHash};
1818
use bitcoin::blockdata::block::BlockHeader;
1919
use bitcoin::blockdata::transaction::{Transaction, TxOut};
2020
use bitcoin::network::constants::Network;
@@ -46,6 +46,15 @@ pub fn confirm_transaction(chain: &chaininterface::ChainWatchInterfaceUtil, tx:
4646
}
4747
}
4848

49+
pub fn connect_blocks(chain: &chaininterface::ChainWatchInterfaceUtil, depth: u32, height: u32, parent: bool, prev_blockhash: Sha256dHash) {
50+
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 };
51+
chain.block_connected_checked(&header, height + 1, &Vec::new(), &Vec::new());
52+
for i in 2..depth {
53+
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
54+
chain.block_connected_checked(&header, height + i, &Vec::new(), &Vec::new());
55+
}
56+
}
57+
4958
pub struct Node {
5059
pub chain_monitor: Arc<chaininterface::ChainWatchInterfaceUtil>,
5160
pub tx_broadcaster: Arc<test_utils::TestBroadcaster>,

src/ln/functional_tests.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
88
use chain::keysinterface;
99
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, BREAKDOWN_TIMEOUT};
1010
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash};
11-
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor};
11+
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor, HTLC_FAIL_ANTI_REORG_DELAY};
1212
use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT};
1313
use ln::onion_utils;
1414
use ln::router::{Route, RouteHop};
@@ -1723,6 +1723,7 @@ fn claim_htlc_outputs_shared_tx() {
17231723
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
17241724
nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
17251725
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
1726+
connect_blocks(&nodes[1].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY, 1, true, header.bitcoin_hash());
17261727

17271728
let events = nodes[1].node.get_and_clear_pending_events();
17281729
assert_eq!(events.len(), 1);
@@ -1790,6 +1791,7 @@ fn claim_htlc_outputs_single_tx() {
17901791
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
17911792
nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200);
17921793
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200);
1794+
connect_blocks(&nodes[1].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY, 200, true, header.bitcoin_hash());
17931795

17941796
let events = nodes[1].node.get_and_clear_pending_events();
17951797
assert_eq!(events.len(), 1);
@@ -1801,7 +1803,7 @@ fn claim_htlc_outputs_single_tx() {
18011803
}
18021804

18031805
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
1804-
assert_eq!(node_txn.len(), 12); // ChannelManager : 2, ChannelMontitor: 8 (1 standard revoked output, 2 revocation htlc tx, 1 local commitment tx + 1 htlc timeout tx) * 2 (block-rescan)
1806+
assert_eq!(node_txn.len(), 22); // ChannelManager : 2, ChannelMontitor: 8 (1 standard revoked output, 2 revocation htlc tx, 1 local commitment tx + 1 htlc timeout tx) * 2 (block-rescan) + 5 * (1 local commitment tx + 1 htlc timeout tx)
18051807

18061808
assert_eq!(node_txn[0], node_txn[7]);
18071809
assert_eq!(node_txn[1], node_txn[8]);
@@ -1811,6 +1813,10 @@ fn claim_htlc_outputs_single_tx() {
18111813
assert_eq!(node_txn[3], node_txn[5]); //local commitment tx + htlc timeout tx broadcasted by ChannelManger
18121814
assert_eq!(node_txn[4], node_txn[6]);
18131815

1816+
for i in 12..22 {
1817+
if i % 2 == 0 { assert_eq!(node_txn[3], node_txn[i]); } else { assert_eq!(node_txn[4], node_txn[i]); }
1818+
}
1819+
18141820
assert_eq!(node_txn[0].input.len(), 1);
18151821
assert_eq!(node_txn[1].input.len(), 1);
18161822
assert_eq!(node_txn[2].input.len(), 1);
@@ -2145,6 +2151,7 @@ fn test_simple_commitment_revoked_fail_backward() {
21452151

21462152
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
21472153
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
2154+
connect_blocks(&nodes[1].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY, 1, true, header.bitcoin_hash());
21482155
check_added_monitors!(nodes[1], 0);
21492156
check_closed_broadcast!(nodes[1]);
21502157

@@ -2297,6 +2304,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
22972304

22982305
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
22992306
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
2307+
connect_blocks(&nodes[1].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY, 1, true, header.bitcoin_hash());
23002308

23012309
let events = nodes[1].node.get_and_clear_pending_events();
23022310
assert_eq!(events.len(), if deliver_bs_raa { 1 } else { 2 });
@@ -3958,6 +3966,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
39583966
} else {
39593967
nodes[2].chain_monitor.block_connected_checked(&header, 1, &[&ds_prev_commitment_tx[0]], &[1; 1]);
39603968
}
3969+
connect_blocks(&nodes[2].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY, 1, true, header.bitcoin_hash());
39613970
check_closed_broadcast!(nodes[2]);
39623971
expect_pending_htlcs_forwardable!(nodes[2]);
39633972
check_added_monitors!(nodes[2], 2);

0 commit comments

Comments
 (0)