Skip to content

Commit c65588c

Browse files
committed
Test reconnecting after lost message(s) during the commitment dance
1 parent 17375b0 commit c65588c

File tree

1 file changed

+165
-12
lines changed

1 file changed

+165
-12
lines changed

src/ln/channelmanager.rs

Lines changed: 165 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4674,7 +4674,7 @@ mod tests {
46744674
assert_eq!(channel_state.short_to_id.len(), 0);
46754675
}
46764676

4677-
fn reconnect_nodes(node_a: &Node, node_b: &Node, pre_all_htlcs: bool, pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize)) {
4677+
fn reconnect_nodes(node_a: &Node, node_b: &Node, pre_all_htlcs: bool, pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize), pending_raa: (bool, bool)) {
46784678
let reestablish_1 = node_a.node.peer_connected(&node_b.node.get_our_node_id());
46794679
let reestablish_2 = node_b.node.peer_connected(&node_a.node.get_our_node_id());
46804680

@@ -4703,26 +4703,47 @@ mod tests {
47034703

47044704
for chan_msgs in resp_1.drain(..) {
47054705
if pre_all_htlcs {
4706-
let _announcement_sigs_opt = node_a.node.handle_funding_locked(&node_b.node.get_our_node_id(), &chan_msgs.0.unwrap()).unwrap();
4706+
let a = node_a.node.handle_funding_locked(&node_b.node.get_our_node_id(), &chan_msgs.0.unwrap());
4707+
let _announcement_sigs_opt = a.unwrap();
47074708
//TODO: Test announcement_sigs re-sending when we've implemented it
47084709
} else {
47094710
assert!(chan_msgs.0.is_none());
47104711
}
4711-
assert!(chan_msgs.1.is_none());
4712-
if pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
4712+
if pending_raa.0 {
4713+
assert!(node_a.node.handle_revoke_and_ack(&node_b.node.get_our_node_id(), &chan_msgs.1.unwrap()).unwrap().is_none());
4714+
check_added_monitors!(node_a, 1);
4715+
} else {
4716+
assert!(chan_msgs.1.is_none());
4717+
}
4718+
if pending_htlc_adds.0 != 0 || pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
47134719
let commitment_update = chan_msgs.2.unwrap();
4714-
assert!(commitment_update.update_add_htlcs.is_empty()); // We can't relay while disconnected
4720+
if pending_htlc_adds.0 != -1 { // We use -1 to denote a response commitment_signed
4721+
assert_eq!(commitment_update.update_add_htlcs.len(), pending_htlc_adds.0 as usize);
4722+
} else {
4723+
assert!(commitment_update.update_add_htlcs.is_empty());
4724+
}
47154725
assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.0);
47164726
assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.0);
47174727
assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
4728+
for update_add in commitment_update.update_add_htlcs {
4729+
node_a.node.handle_update_add_htlc(&node_b.node.get_our_node_id(), &update_add).unwrap();
4730+
}
47184731
for update_fulfill in commitment_update.update_fulfill_htlcs {
47194732
node_a.node.handle_update_fulfill_htlc(&node_b.node.get_our_node_id(), &update_fulfill).unwrap();
47204733
}
47214734
for update_fail in commitment_update.update_fail_htlcs {
47224735
node_a.node.handle_update_fail_htlc(&node_b.node.get_our_node_id(), &update_fail).unwrap();
47234736
}
47244737

4725-
commitment_signed_dance!(node_a, node_b, commitment_update.commitment_signed, false);
4738+
if pending_htlc_adds.0 != -1 { // We use -1 to denote a response commitment_signed
4739+
commitment_signed_dance!(node_a, node_b, commitment_update.commitment_signed, false);
4740+
} else {
4741+
let (as_revoke_and_ack, as_commitment_signed) = node_a.node.handle_commitment_signed(&node_b.node.get_our_node_id(), &commitment_update.commitment_signed).unwrap();
4742+
check_added_monitors!(node_a, 1);
4743+
assert!(as_commitment_signed.is_none());
4744+
assert!(node_b.node.handle_revoke_and_ack(&node_a.node.get_our_node_id(), &as_revoke_and_ack).unwrap().is_none());
4745+
check_added_monitors!(node_b, 1);
4746+
}
47264747
} else {
47274748
assert!(chan_msgs.2.is_none());
47284749
}
@@ -4735,13 +4756,23 @@ mod tests {
47354756
} else {
47364757
assert!(chan_msgs.0.is_none());
47374758
}
4738-
assert!(chan_msgs.1.is_none());
4739-
if pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
4759+
if pending_raa.1 {
4760+
assert!(node_b.node.handle_revoke_and_ack(&node_a.node.get_our_node_id(), &chan_msgs.1.unwrap()).unwrap().is_none());
4761+
check_added_monitors!(node_b, 1);
4762+
} else {
4763+
assert!(chan_msgs.1.is_none());
4764+
}
4765+
if pending_htlc_adds.1 != 0 || pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
47404766
let commitment_update = chan_msgs.2.unwrap();
4741-
assert!(commitment_update.update_add_htlcs.is_empty()); // We can't relay while disconnected
4767+
if pending_htlc_adds.1 != -1 { // We use -1 to denote a response commitment_signed
4768+
assert_eq!(commitment_update.update_add_htlcs.len(), pending_htlc_adds.1 as usize);
4769+
}
47424770
assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.0);
47434771
assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.0);
47444772
assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
4773+
for update_add in commitment_update.update_add_htlcs {
4774+
node_b.node.handle_update_add_htlc(&node_a.node.get_our_node_id(), &update_add).unwrap();
4775+
}
47454776
for update_fulfill in commitment_update.update_fulfill_htlcs {
47464777
node_b.node.handle_update_fulfill_htlc(&node_a.node.get_our_node_id(), &update_fulfill).unwrap();
47474778
}
@@ -4765,7 +4796,7 @@ mod tests {
47654796

47664797
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
47674798
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
4768-
reconnect_nodes(&nodes[0], &nodes[1], true, (0, 0), (0, 0));
4799+
reconnect_nodes(&nodes[0], &nodes[1], true, (0, 0), (0, 0), (0, 0), (false, false));
47694800

47704801
let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
47714802
let payment_hash_2 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).1;
@@ -4774,7 +4805,7 @@ mod tests {
47744805

47754806
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
47764807
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
4777-
reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (0, 0));
4808+
reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (0, 0), (0, 0), (false, false));
47784809

47794810
let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
47804811
let payment_preimage_4 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
@@ -4787,7 +4818,7 @@ mod tests {
47874818
claim_payment_along_route(&nodes[0], &vec!(&nodes[1], &nodes[2]), true, payment_preimage_3);
47884819
fail_payment_along_route(&nodes[0], &[&nodes[1], &nodes[2]], true, payment_hash_5);
47894820

4790-
reconnect_nodes(&nodes[0], &nodes[1], false, (1, 0), (1, 0));
4821+
reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (1, 0), (1, 0), (false, false));
47914822
{
47924823
let events = nodes[0].node.get_and_clear_pending_events();
47934824
assert_eq!(events.len(), 2);
@@ -4809,6 +4840,128 @@ mod tests {
48094840
fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_hash_6);
48104841
}
48114842

4843+
fn do_test_drop_messages_peer_disconnect(messages_delivered: u8) {
4844+
// Test that we can reconnect when in-flight HTLC updates get dropped
4845+
let mut nodes = create_network(3);
4846+
create_announced_chan_between_nodes(&nodes, 1, 2);
4847+
if messages_delivered == 0 {
4848+
create_chan_between_nodes_with_value_a(&nodes[0], &nodes[1], 100000, 10001);
4849+
// nodes[1] doesn't receive the funding_locked message (it'll be re-sent on reconnect)
4850+
} else {
4851+
create_announced_chan_between_nodes(&nodes, 0, 1);
4852+
}
4853+
4854+
let route = nodes[0].router.get_route(&nodes[2].node.get_our_node_id(), Some(&nodes[0].node.list_usable_channels()), &Vec::new(), 1000000, TEST_FINAL_CLTV).unwrap();
4855+
let (our_payment_preimage, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
4856+
4857+
let mut payment_event = {
4858+
nodes[0].node.send_payment(route, our_payment_hash).unwrap();
4859+
check_added_monitors!(nodes[0], 1);
4860+
4861+
let mut events = nodes[0].node.get_and_clear_pending_events();
4862+
assert_eq!(events.len(), 1);
4863+
SendEvent::from_event(events.remove(0))
4864+
};
4865+
assert_eq!(nodes[1].node.get_our_node_id(), payment_event.node_id);
4866+
4867+
if messages_delivered < 2 {
4868+
// Drop the payment_event messages, and let them get re-generated in reconnect_nodes!
4869+
} else {
4870+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]).unwrap();
4871+
let (bs_revoke_and_ack, bs_commitment_signed) = nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &payment_event.commitment_msg).unwrap();
4872+
check_added_monitors!(nodes[1], 1);
4873+
if messages_delivered >= 3 {
4874+
assert!(nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_revoke_and_ack).unwrap().is_none());
4875+
check_added_monitors!(nodes[0], 1);
4876+
if messages_delivered >= 4 {
4877+
let (as_revoke_and_ack, as_commitment_signed) = nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_commitment_signed.unwrap()).unwrap();
4878+
assert!(as_commitment_signed.is_none());
4879+
check_added_monitors!(nodes[0], 1);
4880+
if messages_delivered >= 5 {
4881+
assert!(nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_revoke_and_ack).unwrap().is_none());
4882+
check_added_monitors!(nodes[1], 1);
4883+
}
4884+
}
4885+
}
4886+
}
4887+
4888+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
4889+
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
4890+
if messages_delivered < 2 {
4891+
// Even if the funding_locked messages get exchanged, as long as nothing further was
4892+
// received on either side, both sides will need to resend them.
4893+
reconnect_nodes(&nodes[0], &nodes[1], true, (0, 1), (0, 0), (0, 0), (false, false));
4894+
} else if messages_delivered == 2 {
4895+
// nodes[0] still wants its RAA + commitment_signed
4896+
reconnect_nodes(&nodes[0], &nodes[1], false, (-1, 0), (0, 0), (0, 0), (true, false));
4897+
} else if messages_delivered == 3 {
4898+
// nodes[0] still wants its commitment_signed
4899+
reconnect_nodes(&nodes[0], &nodes[1], false, (-1, 0), (0, 0), (0, 0), (false, false));
4900+
} else if messages_delivered == 4 {
4901+
// nodes[1] still wants its final RAA
4902+
reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (0, 0), (0, 0), (false, true));
4903+
} else if messages_delivered == 5 {
4904+
// Everything was delivered...
4905+
reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (0, 0), (0, 0), (false, false));
4906+
}
4907+
4908+
let events_1 = nodes[1].node.get_and_clear_pending_events();
4909+
assert_eq!(events_1.len(), 1);
4910+
match events_1[0] {
4911+
Event::PendingHTLCsForwardable { .. } => { },
4912+
_ => panic!("Unexpected event"),
4913+
};
4914+
4915+
nodes[1].node.channel_state.lock().unwrap().next_forward = Instant::now();
4916+
nodes[1].node.process_pending_htlc_forwards();
4917+
check_added_monitors!(nodes[1], 1);
4918+
4919+
let mut events_2 = nodes[1].node.get_and_clear_pending_events();
4920+
payment_event = SendEvent::from_event(events_2.remove(0));
4921+
assert_eq!(payment_event.msgs.len(), 1);
4922+
assert_eq!(nodes[2].node.get_our_node_id(), payment_event.node_id);
4923+
4924+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &payment_event.msgs[0]).unwrap();
4925+
check_added_monitors!(nodes[2], 0);
4926+
commitment_signed_dance!(nodes[2], nodes[1], payment_event.commitment_msg, false);
4927+
4928+
let events_2 = nodes[2].node.get_and_clear_pending_events();
4929+
assert_eq!(events_2.len(), 1);
4930+
match events_2[0] {
4931+
Event::PendingHTLCsForwardable { .. } => { },
4932+
_ => panic!("Unexpected event"),
4933+
};
4934+
4935+
nodes[2].node.channel_state.lock().unwrap().next_forward = Instant::now();
4936+
nodes[2].node.process_pending_htlc_forwards();
4937+
4938+
let events_3 = nodes[2].node.get_and_clear_pending_events();
4939+
assert_eq!(events_3.len(), 1);
4940+
match events_3[0] {
4941+
Event::PaymentReceived { ref payment_hash, amt } => {
4942+
assert_eq!(our_payment_hash, *payment_hash);
4943+
assert_eq!(amt, 1000000);
4944+
},
4945+
_ => panic!("Unexpected event"),
4946+
}
4947+
4948+
claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage);
4949+
}
4950+
4951+
#[test]
4952+
fn test_drop_messages_peer_disconnect_a() {
4953+
do_test_drop_messages_peer_disconnect(0);
4954+
do_test_drop_messages_peer_disconnect(1);
4955+
do_test_drop_messages_peer_disconnect(2);
4956+
}
4957+
4958+
#[test]
4959+
fn test_drop_messages_peer_disconnect_b() {
4960+
do_test_drop_messages_peer_disconnect(3);
4961+
do_test_drop_messages_peer_disconnect(4);
4962+
do_test_drop_messages_peer_disconnect(5);
4963+
}
4964+
48124965
#[test]
48134966
fn test_invalid_channel_announcement() {
48144967
//Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs

0 commit comments

Comments
 (0)