From: Antoine Riard Date: Tue, 27 Nov 2018 00:54:00 +0000 (-0500) Subject: Track outputs fron local commitment tx X-Git-Tag: v0.0.12~256^2~16 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=664ae42257b9565db32a4b5bfebeecb594cac2e6;p=rust-lightning Track outputs fron local commitment tx Aims to detect onchain resolution of channel Modify in consequence test_txn_broadcast to still pass channel_monitor_network_test Modify some tests due to block re-scan caused by detections extensions --- diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index e0d2b9aaa..438602d8c 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -5344,7 +5344,10 @@ mod tests { false } else { true } }); - assert_eq!(res.len(), 2); + assert!(res.len() == 2 || res.len() == 3); + if res.len() == 3 { + assert_eq!(res[1], res[2]); + } } assert!(node_txn.is_empty()); @@ -8429,10 +8432,12 @@ mod tests { _ => panic!("Unexpected event"), } let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); - assert_eq!(revoked_htlc_txn.len(), 2); + assert_eq!(revoked_htlc_txn.len(), 3); + assert_eq!(revoked_htlc_txn[0], revoked_htlc_txn[2]); assert_eq!(revoked_htlc_txn[0].input.len(), 1); assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 133); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0].clone()); + check_spends!(revoked_htlc_txn[1], chan_1.3.clone()); // B will generate justice tx from A's revoked commitment/HTLC tx nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] }, 1); @@ -8479,7 +8484,8 @@ mod tests { } let revoked_htlc_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); - assert_eq!(revoked_htlc_txn.len(), 2); + assert_eq!(revoked_htlc_txn.len(), 3); + assert_eq!(revoked_htlc_txn[0], revoked_htlc_txn[2]); assert_eq!(revoked_htlc_txn[0].input.len(), 1); assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 138); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0].clone()); @@ -8540,8 +8546,9 @@ mod tests { // Verify that B is able to spend its own HTLC-Success tx thanks to spendable output event given back by its ChannelMonitor let spend_txn = check_spendable_outputs!(nodes[1], 1); - assert_eq!(spend_txn.len(), 1); + assert_eq!(spend_txn.len(), 2); check_spends!(spend_txn[0], node_txn[0].clone()); + check_spends!(spend_txn[1], node_txn[2].clone()); } #[test] @@ -8571,9 +8578,13 @@ mod tests { // Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor let spend_txn = check_spendable_outputs!(nodes[0], 1); - assert_eq!(spend_txn.len(), 4); + assert_eq!(spend_txn.len(), 8); assert_eq!(spend_txn[0], spend_txn[2]); + assert_eq!(spend_txn[0], spend_txn[4]); + assert_eq!(spend_txn[0], spend_txn[6]); assert_eq!(spend_txn[1], spend_txn[3]); + assert_eq!(spend_txn[1], spend_txn[5]); + assert_eq!(spend_txn[1], spend_txn[7]); check_spends!(spend_txn[0], local_txn[0].clone()); check_spends!(spend_txn[1], node_txn[0].clone()); } diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index 48e5c002c..ed940375b 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -1319,9 +1319,10 @@ impl ChannelMonitor { } else { (None, None) } } - fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option, delayed_payment_base_key: &Option) -> (Vec, Vec) { + fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option, delayed_payment_base_key: &Option) -> (Vec, Vec, Vec) { let mut res = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut spendable_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); + let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); macro_rules! add_dynamic_output { ($father_tx: expr, $vout: expr) => { @@ -1385,24 +1386,27 @@ impl ChannelMonitor { res.push(htlc_success_tx); } } + watch_outputs.push(local_tx.tx.output[htlc.transaction_output_index as usize].clone()); } - (res, spendable_outputs) + (res, spendable_outputs, watch_outputs) } /// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet) /// revoked using data in local_claimable_outpoints. /// Should not be used if check_spend_revoked_transaction succeeds. - fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec, Vec) { + fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec, Vec, (Sha256dHash, Vec)) { let commitment_txid = tx.txid(); if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if local_tx.txid == commitment_txid { match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { - return self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); }, Storage::Watchtower { .. } => { - return self.broadcast_by_local_state(local_tx, &None, &None); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, &None, &None); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); } } } @@ -1411,15 +1415,17 @@ impl ChannelMonitor { if local_tx.txid == commitment_txid { match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => { - return self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key)); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key)); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); }, Storage::Watchtower { .. } => { - return self.broadcast_by_local_state(local_tx, &None, &None); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, &None, &None); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); } } } } - (Vec::new(), Vec::new()) + (Vec::new(), Vec::new(), (commitment_txid, Vec::new())) } /// Generate a spendable output event when closing_transaction get registered onchain. @@ -1491,9 +1497,12 @@ impl ChannelMonitor { watch_outputs.push(new_outputs); } if txn.is_empty() { - let (remote_txn, mut outputs) = self.check_spend_local_transaction(tx, height); - spendable_outputs.append(&mut outputs); - txn = remote_txn; + let (local_txn, mut spendable_output, new_outputs) = self.check_spend_local_transaction(tx, height); + spendable_outputs.append(&mut spendable_output); + txn = local_txn; + if !new_outputs.1.is_empty() { + watch_outputs.push(new_outputs); + } } if !funding_txo.is_none() && txn.is_empty() { if let Some(spendable_output) = self.check_spend_closing_transaction(tx) { @@ -1521,15 +1530,21 @@ impl ChannelMonitor { broadcaster.broadcast_transaction(&cur_local_tx.tx); match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { - let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); - spendable_outputs.append(&mut outputs); + let (txs, mut spendable_output, new_outputs) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + spendable_outputs.append(&mut spendable_output); + if !new_outputs.is_empty() { + watch_outputs.push((cur_local_tx.txid.clone(), new_outputs)); + } for tx in txs { broadcaster.broadcast_transaction(&tx); } }, Storage::Watchtower { .. } => { - let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None); - spendable_outputs.append(&mut outputs); + let (txs, mut spendable_output, new_outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None); + spendable_outputs.append(&mut spendable_output); + if !new_outputs.is_empty() { + watch_outputs.push((cur_local_tx.txid.clone(), new_outputs)); + } for tx in txs { broadcaster.broadcast_transaction(&tx); }