Skip to content

Commit eb88d69

Browse files
author
Antoine Riard
committed
Implement fail backward in case of detection of revoked tx
Refactor block_connected to ease output resolution Add test_commitment_revoked_fail_backward Close #137
1 parent 501bba3 commit eb88d69

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/ln/channelmanager.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6239,6 +6239,54 @@ mod tests {
62396239
assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), 133);
62406240
}
62416241

6242+
#[test]
6243+
fn test_commitment_revoked_fail_backward() {
6244+
// Test that in case of a revoked commitment tx, we detect the resolution of output by justice tx
6245+
// and fail backward accordingly.
6246+
6247+
let nodes = create_network(3);
6248+
6249+
// Create some initial channels
6250+
create_announced_chan_between_nodes(&nodes, 0, 1);
6251+
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
6252+
6253+
// Rebalance the network a bit by relaying one payment through all the channels...
6254+
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
6255+
send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
6256+
6257+
let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 3000000);
6258+
// Get the will-be-revoked local txn from nodes[2]
6259+
let revoked_local_txn = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
6260+
// Revoke the old state
6261+
claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], payment_preimage);
6262+
6263+
route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 3000000);
6264+
6265+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
6266+
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
6267+
{
6268+
let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap();
6269+
assert_eq!(added_monitors.len(), 1);
6270+
added_monitors.clear();
6271+
}
6272+
let events = nodes[1].node.get_and_clear_pending_msg_events();
6273+
assert_eq!(events.len(), 2);
6274+
match events[0] {
6275+
MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {},
6276+
_ => panic!("Unexpected event"),
6277+
}
6278+
match events[1] {
6279+
MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => {
6280+
assert!(update_add_htlcs.is_empty());
6281+
assert!(!update_fail_htlcs.is_empty());
6282+
assert!(update_fulfill_htlcs.is_empty());
6283+
assert!(update_fail_malformed_htlcs.is_empty());
6284+
assert_eq!(nodes[0].node.get_our_node_id(), *node_id);
6285+
},
6286+
_ => panic!("Unexpected event"),
6287+
}
6288+
}
6289+
62426290
#[test]
62436291
fn test_htlc_ignore_latest_remote_commitment() {
62446292
// Test that HTLC transactions spending the latest remote commitment transaction are simply

src/ln/channelmonitor.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ impl<Key : Send + cmp::Eq + hash::Hash + 'static> SimpleManyChannelMonitor<Key>
230230
monitors.insert(key, monitor);
231231
Ok(())
232232
}
233+
233234
}
234235

235236
impl ManyChannelMonitor for SimpleManyChannelMonitor<OutPoint> {
@@ -1560,6 +1561,16 @@ impl ChannelMonitor {
15601561
pub(crate) fn is_resolving_output(&self, tx: &Transaction) -> Option<Vec<(Option<[u8;32]>, [u8;32])>> {
15611562
let mut hash_to_remove = Vec::new();
15621563
if tx.input.len() > 0 {
1564+
let commitment_number = 0xffffffffffff - ((((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor);
1565+
if commitment_number >= self.get_min_seen_secret() {
1566+
if let Some(ref local_commitment_tx) = self.current_local_signed_commitment_tx {
1567+
for &(ref htlc_output, _, _) in &local_commitment_tx.htlc_outputs {
1568+
if htlc_output.offered {
1569+
hash_to_remove.push((None, htlc_output.payment_hash.clone()));
1570+
}
1571+
}
1572+
}
1573+
}
15631574
for input in &tx.input {
15641575
let mut payment_data = (None, None);
15651576
if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx {
@@ -1610,6 +1621,7 @@ impl ChannelMonitor {
16101621
}
16111622
None
16121623
}
1624+
16131625
}
16141626

16151627
const MAX_ALLOC_SIZE: usize = 64*1024;

0 commit comments

Comments
 (0)