From: Matt Corallo Date: Tue, 16 Oct 2018 20:36:03 +0000 (-0400) Subject: Fix + test funding tx confirmation while peer is disconnected X-Git-Tag: v0.0.12~293^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=refs%2Fheads%2F2018-10-funding-disconnected;p=rust-lightning Fix + test funding tx confirmation while peer is disconnected --- diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 188e1c725..5c861b2ea 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -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, 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 diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 9cca16a42..8bc5bf88d 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -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