Actual no_std support
[rust-lightning] / lightning / src / ln / chanmon_update_fail_tests.rs
index 5f90b030dfb12ac78a0a089b9acf0a40e43f6166..00b6813411c657fc65656a517b3dc9fc11e767d4 100644 (file)
@@ -28,7 +28,7 @@ use ln::msgs::{ChannelMessageHandler, ErrorAction, RoutingMessageHandler};
 use routing::router::get_route;
 use util::config::UserConfig;
 use util::enforcing_trait_impls::EnforcingSigner;
-use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
+use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
 use util::errors::APIError;
 use util::ser::{ReadableArgs, Writeable};
 use util::test_utils::TestBroadcaster;
@@ -40,8 +40,9 @@ use ln::functional_test_utils::*;
 
 use util::test_utils;
 
+use io;
 use prelude::*;
-use std::sync::{Arc, Mutex};
+use sync::{Arc, Mutex};
 
 // If persister_fail is true, we have the persister return a PermanentFailure
 // instead of the higher-level ChainMonitor.
@@ -122,7 +123,7 @@ fn test_monitor_and_persister_update_fail() {
                let mut w = test_utils::TestVecWriter(Vec::new());
                monitor.write(&mut w).unwrap();
                let new_monitor = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(
-                       &mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
+                       &mut io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
                assert!(new_monitor == *monitor);
                let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
                assert!(chain_mon.watch_channel(outpoint, new_monitor).is_ok());
@@ -197,7 +198,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail
        if disconnect {
                nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-               reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        }
 
        match persister_fail {
@@ -220,11 +221,16 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail
        let events_3 = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(events_3.len(), 1);
        match events_3[0] {
-               Event::PaymentReceived { ref payment_hash, ref payment_preimage, ref payment_secret, amt, user_payment_id: _ } => {
+               Event::PaymentReceived { ref payment_hash, ref purpose, amt } => {
                        assert_eq!(payment_hash_1, *payment_hash);
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(payment_secret_1, *payment_secret);
                        assert_eq!(amt, 1000000);
+                       match &purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert!(payment_preimage.is_none());
+                                       assert_eq!(payment_secret_1, *payment_secret);
+                               },
+                               _ => panic!("expected PaymentPurpose::InvoicePayment")
+                       }
                },
                _ => panic!("Unexpected event"),
        }
@@ -251,7 +257,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail
        if disconnect {
                nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        }
 
        // ...and make sure we can force-close a frozen channel
@@ -589,11 +595,16 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
        let events_5 = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(events_5.len(), 1);
        match events_5[0] {
-               Event::PaymentReceived { ref payment_hash, ref payment_preimage, ref payment_secret, amt, user_payment_id: _ } => {
+               Event::PaymentReceived { ref payment_hash, ref purpose, amt } => {
                        assert_eq!(payment_hash_2, *payment_hash);
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(payment_secret_2, *payment_secret);
                        assert_eq!(amt, 1000000);
+                       match &purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert!(payment_preimage.is_none());
+                                       assert_eq!(payment_secret_2, *payment_secret);
+                               },
+                               _ => panic!("expected PaymentPurpose::InvoicePayment")
+                       }
                },
                _ => panic!("Unexpected event"),
        }
@@ -704,11 +715,16 @@ fn test_monitor_update_fail_cs() {
        let events = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(events.len(), 1);
        match events[0] {
-               Event::PaymentReceived { payment_hash, payment_preimage, payment_secret, amt, user_payment_id: _ } => {
+               Event::PaymentReceived { payment_hash, ref purpose, amt } => {
                        assert_eq!(payment_hash, our_payment_hash);
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(our_payment_secret, payment_secret);
                        assert_eq!(amt, 1000000);
+                       match &purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert!(payment_preimage.is_none());
+                                       assert_eq!(our_payment_secret, *payment_secret);
+                               },
+                               _ => panic!("expected PaymentPurpose::InvoicePayment")
+                       }
                },
                _ => panic!("Unexpected event"),
        };
@@ -1712,20 +1728,30 @@ fn test_monitor_update_fail_claim() {
        let events = nodes[0].node.get_and_clear_pending_events();
        assert_eq!(events.len(), 2);
        match events[0] {
-               Event::PaymentReceived { ref payment_hash, ref payment_preimage, ref payment_secret, amt, user_payment_id: _ } => {
+               Event::PaymentReceived { ref payment_hash, ref purpose, amt } => {
                        assert_eq!(payment_hash_2, *payment_hash);
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(payment_secret_2, *payment_secret);
                        assert_eq!(1_000_000, amt);
+                       match &purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert!(payment_preimage.is_none());
+                                       assert_eq!(payment_secret_2, *payment_secret);
+                               },
+                               _ => panic!("expected PaymentPurpose::InvoicePayment")
+                       }
                },
                _ => panic!("Unexpected event"),
        }
        match events[1] {
-               Event::PaymentReceived { ref payment_hash, ref payment_preimage, ref payment_secret, amt, user_payment_id: _ } => {
+               Event::PaymentReceived { ref payment_hash, ref purpose, amt } => {
                        assert_eq!(payment_hash_3, *payment_hash);
-                       assert!(payment_preimage.is_none());
-                       assert_eq!(payment_secret_3, *payment_secret);
                        assert_eq!(1_000_000, amt);
+                       match &purpose {
+                               PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+                                       assert!(payment_preimage.is_none());
+                                       assert_eq!(payment_secret_3, *payment_secret);
+                               },
+                               _ => panic!("expected PaymentPurpose::InvoicePayment")
+                       }
                },
                _ => panic!("Unexpected event"),
        }
@@ -1922,7 +1948,7 @@ fn do_during_funding_monitor_fail(confirm_a_first: bool, restore_b_before_conf:
        // Make sure nodes[1] isn't stupid enough to re-send the FundingLocked on reconnect
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-       reconnect_nodes(&nodes[0], &nodes[1], (false, confirm_a_first), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, confirm_a_first), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
        assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
 
@@ -2014,7 +2040,7 @@ fn test_path_paused_mpp() {
        // Pass the first HTLC of the payment along to nodes[3].
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
-       pass_along_path(&nodes[0], &[&nodes[1], &nodes[3]], 0, payment_hash.clone(), payment_secret, events.pop().unwrap(), false);
+       pass_along_path(&nodes[0], &[&nodes[1], &nodes[3]], 0, payment_hash.clone(), Some(payment_secret), events.pop().unwrap(), false, None);
 
        // And check that, after we successfully update the monitor for chan_2 we can pass the second
        // HTLC along to nodes[3] and claim the whole payment back to nodes[0].
@@ -2022,7 +2048,7 @@ fn test_path_paused_mpp() {
        nodes[0].node.channel_monitor_updated(&outpoint, latest_update);
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
-       pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 200_000, payment_hash.clone(), payment_secret, events.pop().unwrap(), true);
+       pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 200_000, payment_hash.clone(), Some(payment_secret), events.pop().unwrap(), true, None);
 
        claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], false, payment_preimage);
 }
@@ -2225,3 +2251,119 @@ fn channel_holding_cell_serialize() {
        do_channel_holding_cell_serialize(true, false);
        do_channel_holding_cell_serialize(false, true); // last arg doesn't matter
 }
+
+#[derive(PartialEq)]
+enum HTLCStatusAtDupClaim {
+       Received,
+       HoldingCell,
+       Cleared,
+}
+fn do_test_reconnect_dup_htlc_claims(htlc_status: HTLCStatusAtDupClaim, second_fails: bool) {
+       // When receiving an update_fulfill_htlc message, we immediately forward the claim backwards
+       // along the payment path before waiting for a full commitment_signed dance. This is great, but
+       // can cause duplicative claims if a node sends an update_fulfill_htlc message, disconnects,
+       // reconnects, and then has to re-send its update_fulfill_htlc message again.
+       // In previous code, we didn't handle the double-claim correctly, spuriously closing the
+       // channel on which the inbound HTLC was received.
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+       let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known()).2;
+
+       let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 100_000);
+
+       let mut as_raa = None;
+       if htlc_status == HTLCStatusAtDupClaim::HoldingCell {
+               // In order to get the HTLC claim into the holding cell at nodes[1], we need nodes[1] to be
+               // awaiting a remote revoke_and_ack from nodes[0].
+               let (_, second_payment_hash, second_payment_secret) = get_payment_preimage_hash!(nodes[1]);
+               let route = get_route(&nodes[0].node.get_our_node_id(), &nodes[0].net_graph_msg_handler.network_graph.read().unwrap(),
+                       &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 100_000, TEST_FINAL_CLTV, nodes[1].logger).unwrap();
+               nodes[0].node.send_payment(&route, second_payment_hash, &Some(second_payment_secret)).unwrap();
+               check_added_monitors!(nodes[0], 1);
+
+               let send_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
+               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
+               nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &send_event.commitment_msg);
+               check_added_monitors!(nodes[1], 1);
+
+               let (bs_raa, bs_cs) = get_revoke_commit_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+               nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_raa);
+               check_added_monitors!(nodes[0], 1);
+               nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_cs);
+               check_added_monitors!(nodes[0], 1);
+
+               as_raa = Some(get_event_msg!(nodes[0], MessageSendEvent::SendRevokeAndACK, nodes[1].node.get_our_node_id()));
+       }
+
+       let fulfill_msg = msgs::UpdateFulfillHTLC {
+               channel_id: chan_2,
+               htlc_id: 0,
+               payment_preimage,
+       };
+       if second_fails {
+               assert!(nodes[2].node.fail_htlc_backwards(&payment_hash));
+               expect_pending_htlcs_forwardable!(nodes[2]);
+               check_added_monitors!(nodes[2], 1);
+               get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
+       } else {
+               assert!(nodes[2].node.claim_funds(payment_preimage));
+               check_added_monitors!(nodes[2], 1);
+               let cs_updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
+               assert_eq!(cs_updates.update_fulfill_htlcs.len(), 1);
+               // Check that the message we're about to deliver matches the one generated:
+               assert_eq!(fulfill_msg, cs_updates.update_fulfill_htlcs[0]);
+       }
+       nodes[1].node.handle_update_fulfill_htlc(&nodes[2].node.get_our_node_id(), &fulfill_msg);
+       check_added_monitors!(nodes[1], 1);
+
+       let mut bs_updates = None;
+       if htlc_status != HTLCStatusAtDupClaim::HoldingCell {
+               bs_updates = Some(get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()));
+               assert_eq!(bs_updates.as_ref().unwrap().update_fulfill_htlcs.len(), 1);
+               nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &bs_updates.as_ref().unwrap().update_fulfill_htlcs[0]);
+               expect_payment_sent!(nodes[0], payment_preimage);
+               if htlc_status == HTLCStatusAtDupClaim::Cleared {
+                       commitment_signed_dance!(nodes[0], nodes[1], &bs_updates.as_ref().unwrap().commitment_signed, false);
+               }
+       } else {
+               assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       }
+
+       nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), false);
+       nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+
+       if second_fails {
+               reconnect_nodes(&nodes[1], &nodes[2], (false, false), (0, 0), (0, 0), (1, 0), (0, 0), (0, 0), (false, false));
+               expect_pending_htlcs_forwardable!(nodes[1]);
+       } else {
+               reconnect_nodes(&nodes[1], &nodes[2], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       }
+
+       if htlc_status == HTLCStatusAtDupClaim::HoldingCell {
+               nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_raa.unwrap());
+               check_added_monitors!(nodes[1], 1);
+               expect_pending_htlcs_forwardable_ignore!(nodes[1]); // We finally receive the second payment, but don't claim it
+
+               bs_updates = Some(get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()));
+               assert_eq!(bs_updates.as_ref().unwrap().update_fulfill_htlcs.len(), 1);
+               nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &bs_updates.as_ref().unwrap().update_fulfill_htlcs[0]);
+               expect_payment_sent!(nodes[0], payment_preimage);
+       }
+       if htlc_status != HTLCStatusAtDupClaim::Cleared {
+               commitment_signed_dance!(nodes[0], nodes[1], &bs_updates.as_ref().unwrap().commitment_signed, false);
+       }
+}
+
+#[test]
+fn test_reconnect_dup_htlc_claims() {
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::Received, false);
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::HoldingCell, false);
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::Cleared, false);
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::Received, true);
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::HoldingCell, true);
+       do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::Cleared, true);
+}