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
This commit is contained in:
Antoine Riard 2018-11-26 19:54:00 -05:00 committed by Matt Corallo
parent 302f1314e5
commit 664ae42257
2 changed files with 46 additions and 20 deletions

View file

@ -5344,7 +5344,10 @@ mod tests {
false false
} else { true } } 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()); assert!(node_txn.is_empty());
@ -8429,10 +8432,12 @@ mod tests {
_ => panic!("Unexpected event"), _ => panic!("Unexpected event"),
} }
let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); 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.len(), 1);
assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 133); 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[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 // 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); 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(); 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.len(), 1);
assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 138); assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 138);
check_spends!(revoked_htlc_txn[0], revoked_local_txn[0].clone()); 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 // 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); 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[0], node_txn[0].clone());
check_spends!(spend_txn[1], node_txn[2].clone());
} }
#[test] #[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 // 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); 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[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[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[0], local_txn[0].clone());
check_spends!(spend_txn[1], node_txn[0].clone()); check_spends!(spend_txn[1], node_txn[0].clone());
} }

View file

@ -1319,9 +1319,10 @@ impl ChannelMonitor {
} else { (None, None) } } else { (None, None) }
} }
fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option<PublicKey>, delayed_payment_base_key: &Option<SecretKey>) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>) { fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option<PublicKey>, delayed_payment_base_key: &Option<SecretKey>) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>, Vec<TxOut>) {
let mut res = Vec::with_capacity(local_tx.htlc_outputs.len()); 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 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 { macro_rules! add_dynamic_output {
($father_tx: expr, $vout: expr) => { ($father_tx: expr, $vout: expr) => {
@ -1385,24 +1386,27 @@ impl ChannelMonitor {
res.push(htlc_success_tx); 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) /// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
/// revoked using data in local_claimable_outpoints. /// revoked using data in local_claimable_outpoints.
/// Should not be used if check_spend_revoked_transaction succeeds. /// Should not be used if check_spend_revoked_transaction succeeds.
fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>) { fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>, (Sha256dHash, Vec<TxOut>)) {
let commitment_txid = tx.txid(); let commitment_txid = tx.txid();
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
if local_tx.txid == commitment_txid { if local_tx.txid == commitment_txid {
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { 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 { .. } => { 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 { if local_tx.txid == commitment_txid {
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => { 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 { .. } => { 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. /// Generate a spendable output event when closing_transaction get registered onchain.
@ -1491,9 +1497,12 @@ impl ChannelMonitor {
watch_outputs.push(new_outputs); watch_outputs.push(new_outputs);
} }
if txn.is_empty() { if txn.is_empty() {
let (remote_txn, mut outputs) = self.check_spend_local_transaction(tx, height); let (local_txn, mut spendable_output, new_outputs) = self.check_spend_local_transaction(tx, height);
spendable_outputs.append(&mut outputs); spendable_outputs.append(&mut spendable_output);
txn = remote_txn; txn = local_txn;
if !new_outputs.1.is_empty() {
watch_outputs.push(new_outputs);
}
} }
if !funding_txo.is_none() && txn.is_empty() { if !funding_txo.is_none() && txn.is_empty() {
if let Some(spendable_output) = self.check_spend_closing_transaction(tx) { if let Some(spendable_output) = self.check_spend_closing_transaction(tx) {
@ -1521,15 +1530,21 @@ impl ChannelMonitor {
broadcaster.broadcast_transaction(&cur_local_tx.tx); broadcaster.broadcast_transaction(&cur_local_tx.tx);
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { 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)); 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 outputs); 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 { for tx in txs {
broadcaster.broadcast_transaction(&tx); broadcaster.broadcast_transaction(&tx);
} }
}, },
Storage::Watchtower { .. } => { Storage::Watchtower { .. } => {
let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None); let (txs, mut spendable_output, new_outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None);
spendable_outputs.append(&mut outputs); 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 { for tx in txs {
broadcaster.broadcast_transaction(&tx); broadcaster.broadcast_transaction(&tx);
} }