Fix + test funding tx confirmation while peer is disconnected 2018-10-funding-disconnected
authorMatt Corallo <git@bluematt.me>
Tue, 16 Oct 2018 20:36:03 +0000 (16:36 -0400)
committerMatt Corallo <git@bluematt.me>
Tue, 16 Oct 2018 20:36:29 +0000 (16:36 -0400)
src/ln/channel.rs
src/ln/channelmanager.rs

index 188e1c7256da194e2d81f1694250be7fe1cba584..5c861b2eae7b4dec8293815fdab53f28535c79eb 100644 (file)
@@ -269,6 +269,7 @@ enum ChannelState {
        ShutdownComplete = 2048,
 }
 const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32);
+const MULTI_STATE_FLAGS: u32 = (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDisconnected as u32);
 
 const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
 
@@ -2560,7 +2561,7 @@ impl Channel {
        /// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
        /// Only returns an ErrorAction of DisconnectPeer, if Err.
        pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, HandleError> {
-               let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
+               let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
                if self.funding_tx_confirmations > 0 {
                        if header.bitcoin_hash() != self.last_block_connected {
                                self.last_block_connected = header.bitcoin_hash();
@@ -2570,10 +2571,10 @@ impl Channel {
                                                self.channel_state |= ChannelState::OurFundingLocked as u32;
                                                true
                                        } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
-                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
+                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
                                                self.channel_update_count += 1;
                                                true
-                                       } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
                                                // We got a reorg but not enough to trigger a force close, just update
                                                // funding_tx_confirmed_in and return.
                                                false
index 9cca16a4278e0b66a2abf22bec64c46da656f237..8bc5bf88d9a9e8ba0e7241e5555fd574beb91932 100644 (file)
@@ -2574,7 +2574,7 @@ mod tests {
                (announcement, as_update, bs_update, channel_id, tx)
        }
 
-       fn create_chan_between_nodes_with_value_a(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32], Transaction) {
+       fn create_chan_between_nodes_with_value_init(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> Transaction {
                node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42).unwrap();
 
                let events_1 = node_a.node.get_and_clear_pending_events();
@@ -2647,7 +2647,11 @@ mod tests {
                        _ => panic!("Unexpected event"),
                };
 
-               confirm_transaction(&node_b.chain_monitor, &tx, chan_id);
+               tx
+       }
+
+       fn create_chan_between_nodes_with_value_confirm(node_a: &Node, node_b: &Node, tx: &Transaction) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32]) {
+               confirm_transaction(&node_b.chain_monitor, &tx, tx.version);
                let events_5 = node_b.node.get_and_clear_pending_events();
                assert_eq!(events_5.len(), 1);
                match events_5[0] {
@@ -2661,7 +2665,7 @@ mod tests {
 
                let channel_id;
 
-               confirm_transaction(&node_a.chain_monitor, &tx, chan_id);
+               confirm_transaction(&node_a.chain_monitor, &tx, tx.version);
                let events_6 = node_a.node.get_and_clear_pending_events();
                assert_eq!(events_6.len(), 1);
                (match events_6[0] {
@@ -2671,7 +2675,13 @@ mod tests {
                                (msg.clone(), announcement_sigs.clone().unwrap())
                        },
                        _ => panic!("Unexpected event"),
-               }, channel_id, tx)
+               }, channel_id)
+       }
+
+       fn create_chan_between_nodes_with_value_a(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32], Transaction) {
+               let tx = create_chan_between_nodes_with_value_init(node_a, node_b, channel_value, push_msat);
+               let (msgs, chan_id) = create_chan_between_nodes_with_value_confirm(node_a, node_b, &tx);
+               (msgs, chan_id, tx)
        }
 
        fn create_chan_between_nodes_with_value_b(node_a: &Node, node_b: &Node, as_funding_msgs: &(msgs::FundingLocked, msgs::AnnouncementSignatures)) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate) {
@@ -5038,6 +5048,47 @@ mod tests {
                do_test_drop_messages_peer_disconnect(5);
        }
 
+       #[test]
+       fn test_funding_peer_disconnect() {
+               // Test that we can lock in our funding tx while disconnected
+               let nodes = create_network(2);
+               let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001);
+
+               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);
+
+               confirm_transaction(&nodes[0].chain_monitor, &tx, tx.version);
+               let events_1 = nodes[0].node.get_and_clear_pending_events();
+               assert_eq!(events_1.len(), 1);
+               match events_1[0] {
+                       Event::SendFundingLocked { ref node_id, msg: _, ref announcement_sigs } => {
+                               assert_eq!(*node_id, nodes[1].node.get_our_node_id());
+                               assert!(announcement_sigs.is_none());
+                       },
+                       _ => panic!("Unexpected event"),
+               }
+
+               confirm_transaction(&nodes[1].chain_monitor, &tx, tx.version);
+               let events_2 = nodes[1].node.get_and_clear_pending_events();
+               assert_eq!(events_2.len(), 1);
+               match events_2[0] {
+                       Event::SendFundingLocked { ref node_id, msg: _, ref announcement_sigs } => {
+                               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+                               assert!(announcement_sigs.is_none());
+                       },
+                       _ => panic!("Unexpected event"),
+               }
+
+               reconnect_nodes(&nodes[0], &nodes[1], true, (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+
+               // TODO: We shouldn't need to manually pass list_usable_chanels here once we support
+               // rebroadcasting announcement_signatures upon reconnect.
+
+               let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), Some(&nodes[0].node.list_usable_channels()), &Vec::new(), 1000000, TEST_FINAL_CLTV).unwrap();
+               let (payment_preimage, _) = send_along_route(&nodes[0], route, &[&nodes[1]], 1000000);
+               claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
+       }
+
        #[test]
        fn test_invalid_channel_announcement() {
                //Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs