]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add support for initiating channel closure to Channel{,Manager}
authorMatt Corallo <git@bluematt.me>
Tue, 27 Mar 2018 15:16:53 +0000 (11:16 -0400)
committerMatt Corallo <git@bluematt.me>
Mon, 2 Apr 2018 22:07:03 +0000 (18:07 -0400)
src/ln/channel.rs
src/ln/channelmanager.rs
src/util/test_utils.rs

index 08fa3efb1300e5cc07c1938f92d8f21a9e2e1db4..c9c9e41430d014ba6d6d62ee9d21c4a1a6bde230 100644 (file)
@@ -1955,6 +1955,42 @@ impl Channel {
                        None => Ok(None)
                }
        }
+
+       /// Begins the shutdown process, getting a message for the remote peer and returning all
+       /// holding cell HTLCs for payment failure.
+       pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<[u8; 32]>), HandleError> {
+               for htlc in self.pending_htlcs.iter() {
+                       if htlc.state == HTLCState::LocalAnnounced {
+                               return Err(HandleError{err: "Cannot begin shutdown with pending HTLCs, call send_commitment first", msg: None});
+                       }
+               }
+               if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0 {
+                       return Err(HandleError{err: "Shutdown already in progress", msg: None});
+               }
+               assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+
+               let our_closing_script = self.get_closing_scriptpubkey();
+
+               // From here on out, we may not fail!
+               if self.channel_state < ChannelState::FundingSent as u32 {
+                       self.channel_state = ChannelState::ShutdownComplete as u32;
+               } else {
+                       self.channel_state |= ChannelState::LocalShutdownSent as u32;
+               }
+
+               // We can't send our shutdown until we've committed all of our pending HTLCs, but the
+               // remote side is unlikely to accept any new HTLCs, so we go ahead and "free" any holding
+               // cell HTLCs and return them to fail the payment.
+               let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlcs.len());
+               for htlc in self.holding_cell_htlcs.drain(..) {
+                       dropped_outbound_htlcs.push(htlc.payment_hash);
+               }
+
+               Ok((msgs::Shutdown {
+                       channel_id: self.channel_id,
+                       scriptpubkey: our_closing_script,
+               }, dropped_outbound_htlcs))
+       }
 }
 
 #[cfg(test)]
index 4f165317639b55dcde1bd6066ad62f98505c665b..8be2348a7e1e5374ba82bc063a3c7ac25a668bb8 100644 (file)
@@ -160,6 +160,21 @@ struct OnionKeys {
        mu: [u8; 32],
 }
 
+pub struct ChannelDetails {
+       /// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
+       /// thereafter this is the txid of the funding transaction xor the funding transaction output).
+       /// Note that this means this value is *not* persistent - it can change once during the
+       /// lifetime of the channel.
+       pub channel_id: Uint256,
+       /// The position of the funding transaction in the chain. None if the funding transaction has
+       /// not yet been confirmed and the channel fully opened.
+       pub short_channel_id: Option<u64>,
+       pub remote_network_id: PublicKey,
+       pub channel_value_satoshis: u64,
+       /// The user_id passed in to create_channel, or 0 if the channel was inbound.
+       pub user_id: u64,
+}
+
 impl ChannelManager {
        /// Constructs a new ChannelManager to hold several channels and route between them. This is
        /// the main "logic hub" for all channel-related actions, and implements ChannelMessageHandler.
@@ -206,6 +221,47 @@ impl ChannelManager {
                }
        }
 
+       /// Gets the list of open channels, in random order. See ChannelDetail field documentation for
+       /// more information.
+       pub fn list_channels(&self) -> Vec<ChannelDetails> {
+               let channel_state = self.channel_state.lock().unwrap();
+               let mut res = Vec::with_capacity(channel_state.by_id.len());
+               for (channel_id, channel) in channel_state.by_id.iter() {
+                       res.push(ChannelDetails {
+                               channel_id: (*channel_id).clone(),
+                               short_channel_id: channel.get_short_channel_id(),
+                               remote_network_id: channel.get_their_node_id(),
+                               channel_value_satoshis: channel.get_value_satoshis(),
+                               user_id: channel.get_user_id(),
+                       });
+               }
+               res
+       }
+
+       /// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs
+       /// will be accepted on the given channel, and after additional timeout/the closing of all
+       /// pending HTLCs, the channel will be closed on chain.
+       pub fn close_channel(&self, channel_id: &Uint256) -> Result<msgs::Shutdown, HandleError> {
+               let res = {
+                       let mut channel_state = self.channel_state.lock().unwrap();
+                       match channel_state.by_id.entry(channel_id.clone()) {
+                               hash_map::Entry::Occupied(mut chan_entry) => {
+                                       let res = chan_entry.get_mut().get_shutdown()?;
+                                       if chan_entry.get().is_shutdown() {
+                                               chan_entry.remove_entry();
+                                       }
+                                       res
+                               },
+                               hash_map::Entry::Vacant(_) => return Err(HandleError{err: "No such channel", msg: None})
+                       }
+               };
+               for payment_hash in res.1 {
+                       // unknown_next_peer...I dunno who that is anymore....
+                       self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: &[0; 0] });
+               }
+               Ok(res.0)
+       }
+
        #[inline]
        fn gen_rho_mu_from_shared_secret(shared_secret: &SharedSecret) -> ([u8; 32], [u8; 32]) {
                ({
@@ -1438,6 +1494,7 @@ mod tests {
 
        use bitcoin::util::misc::hex_bytes;
        use bitcoin::util::hash::Sha256dHash;
+       use bitcoin::util::uint::Uint256;
        use bitcoin::blockdata::block::BlockHeader;
        use bitcoin::blockdata::transaction::Transaction;
        use bitcoin::network::constants::Network;
@@ -1452,7 +1509,7 @@ mod tests {
 
        use rand::{thread_rng,Rng};
 
-       use std::sync::Arc;
+       use std::sync::{Arc, Mutex};
        use std::default::Default;
        use std::time::Instant;
 
@@ -1617,7 +1674,7 @@ mod tests {
                }
        }
 
-       fn create_chan_between_nodes(node_a: &ChannelManager, chain_a: &chaininterface::ChainWatchInterfaceUtil, node_b: &ChannelManager, chain_b: &chaininterface::ChainWatchInterfaceUtil) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate) {
+       fn create_chan_between_nodes(node_a: &ChannelManager, chain_a: &chaininterface::ChainWatchInterfaceUtil, node_b: &ChannelManager, chain_b: &chaininterface::ChainWatchInterfaceUtil) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256) {
                let open_chan = node_a.create_channel(node_b.get_our_node_id(), 100000, 42).unwrap();
                let accept_chan = node_b.handle_open_channel(&node_a.get_our_node_id(), &open_chan).unwrap();
                node_a.handle_accept_channel(&node_b.get_our_node_id(), &accept_chan).unwrap();
@@ -1674,12 +1731,15 @@ mod tests {
                        _ => panic!("Unexpected event"),
                };
 
+               let channel_id;
+
                confirm_transaction(&chain_b, &tx);
                let events_5 = node_b.get_and_clear_pending_events();
                assert_eq!(events_5.len(), 1);
                let as_announcement_sigs = match events_5[0] {
                        Event::SendFundingLocked { ref node_id, ref msg, ref announcement_sigs } => {
                                assert_eq!(*node_id, node_a.get_our_node_id());
+                               channel_id = msg.channel_id.clone();
                                let as_announcement_sigs = node_a.handle_funding_locked(&node_b.get_our_node_id(), msg).unwrap().unwrap();
                                node_a.handle_announcement_signatures(&node_b.get_our_node_id(), &(*announcement_sigs).clone().unwrap()).unwrap();
                                as_announcement_sigs
@@ -1711,7 +1771,42 @@ mod tests {
                        CHAN_COUNT += 1;
                }
 
-               ((*announcement).clone(), (*as_update).clone(), (*bs_update).clone())
+               ((*announcement).clone(), (*as_update).clone(), (*bs_update).clone(), channel_id)
+       }
+
+       fn close_channel(outbound_node: &ChannelManager, outbound_broadcaster: &test_utils::TestBroadcaster, inbound_node: &ChannelManager, inbound_broadcaster: &test_utils::TestBroadcaster, channel_id: &Uint256, close_inbound_first: bool) {
+               let (node_a, broadcaster_a) = if close_inbound_first { (inbound_node, inbound_broadcaster) } else { (outbound_node, outbound_broadcaster) };
+               let (node_b, broadcaster_b) = if close_inbound_first { (outbound_node, outbound_broadcaster) } else { (inbound_node, inbound_broadcaster) };
+               let (tx_a, tx_b);
+
+               let shutdown_a = node_a.close_channel(channel_id).unwrap();
+               let (shutdown_b, mut closing_signed_b) = node_b.handle_shutdown(&node_a.get_our_node_id(), &shutdown_a).unwrap();
+               if !close_inbound_first {
+                       assert!(closing_signed_b.is_none());
+               }
+               let (empty_a, mut closing_signed_a) = node_a.handle_shutdown(&node_b.get_our_node_id(), &shutdown_b.unwrap()).unwrap();
+               assert!(empty_a.is_none());
+               if close_inbound_first {
+                       assert!(closing_signed_a.is_none());
+                       closing_signed_a = node_a.handle_closing_signed(&node_b.get_our_node_id(), &closing_signed_b.unwrap()).unwrap();
+                       assert_eq!(broadcaster_a.txn_broadcasted.lock().unwrap().len(), 1);
+                       tx_a = broadcaster_a.txn_broadcasted.lock().unwrap().remove(0);
+
+                       let empty_b = node_b.handle_closing_signed(&node_a.get_our_node_id(), &closing_signed_a.unwrap()).unwrap();
+                       assert!(empty_b.is_none());
+                       assert_eq!(broadcaster_b.txn_broadcasted.lock().unwrap().len(), 1);
+                       tx_b = broadcaster_b.txn_broadcasted.lock().unwrap().remove(0);
+               } else {
+                       closing_signed_b = node_b.handle_closing_signed(&node_a.get_our_node_id(), &closing_signed_a.unwrap()).unwrap();
+                       assert_eq!(broadcaster_b.txn_broadcasted.lock().unwrap().len(), 1);
+                       tx_b = broadcaster_b.txn_broadcasted.lock().unwrap().remove(0);
+
+                       let empty_a2 = node_a.handle_closing_signed(&node_b.get_our_node_id(), &closing_signed_b.unwrap()).unwrap();
+                       assert!(empty_a2.is_none());
+                       assert_eq!(broadcaster_a.txn_broadcasted.lock().unwrap().len(), 1);
+                       tx_a = broadcaster_a.txn_broadcasted.lock().unwrap().remove(0);
+               }
+               assert_eq!(tx_a, tx_b);
        }
 
        struct SendEvent {
@@ -1925,7 +2020,7 @@ mod tests {
                let feeest_1 = Arc::new(test_utils::TestFeeEstimator { sat_per_vbyte: 1 });
                let chain_monitor_1 = Arc::new(chaininterface::ChainWatchInterfaceUtil::new());
                let chan_monitor_1 = Arc::new(test_utils::TestChannelMonitor{});
-               let tx_broadcaster_1 = Arc::new(test_utils::TestBroadcaster{});
+               let tx_broadcaster_1 = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
                let node_id_1 = {
                        let mut key_slice = [0; 32];
                        rng.fill_bytes(&mut key_slice);
@@ -1937,7 +2032,7 @@ mod tests {
                let feeest_2 = Arc::new(test_utils::TestFeeEstimator { sat_per_vbyte: 1 });
                let chain_monitor_2 = Arc::new(chaininterface::ChainWatchInterfaceUtil::new());
                let chan_monitor_2 = Arc::new(test_utils::TestChannelMonitor{});
-               let tx_broadcaster_2 = Arc::new(test_utils::TestBroadcaster{});
+               let tx_broadcaster_2 = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
                let node_id_2 = {
                        let mut key_slice = [0; 32];
                        rng.fill_bytes(&mut key_slice);
@@ -1949,7 +2044,7 @@ mod tests {
                let feeest_3 = Arc::new(test_utils::TestFeeEstimator { sat_per_vbyte: 1 });
                let chain_monitor_3 = Arc::new(chaininterface::ChainWatchInterfaceUtil::new());
                let chan_monitor_3 = Arc::new(test_utils::TestChannelMonitor{});
-               let tx_broadcaster_3 = Arc::new(test_utils::TestBroadcaster{});
+               let tx_broadcaster_3 = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
                let node_id_3 = {
                        let mut key_slice = [0; 32];
                        rng.fill_bytes(&mut key_slice);
@@ -1961,7 +2056,7 @@ mod tests {
                let feeest_4 = Arc::new(test_utils::TestFeeEstimator { sat_per_vbyte: 1 });
                let chain_monitor_4 = Arc::new(chaininterface::ChainWatchInterfaceUtil::new());
                let chan_monitor_4 = Arc::new(test_utils::TestChannelMonitor{});
-               let tx_broadcaster_4 = Arc::new(test_utils::TestBroadcaster{});
+               let tx_broadcaster_4 = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
                let node_id_4 = {
                        let mut key_slice = [0; 32];
                        rng.fill_bytes(&mut key_slice);
@@ -2093,6 +2188,12 @@ mod tests {
                claim_payment(&node_1, &vec!(&*node_2, &*node_4)[..], payment_preimage_4);
                claim_payment(&node_1, &vec!(&*node_2, &*node_4)[..], payment_preimage_5);
 
+               // Close down the channels...
+               close_channel(&node_1, &tx_broadcaster_1, &node_2, &tx_broadcaster_2, &chan_announcement_1.3, true);
+               close_channel(&node_2, &tx_broadcaster_2, &node_3, &tx_broadcaster_3, &chan_announcement_2.3, false);
+               close_channel(&node_3, &tx_broadcaster_3, &node_4, &tx_broadcaster_4, &chan_announcement_3.3, true);
+               close_channel(&node_2, &tx_broadcaster_2, &node_4, &tx_broadcaster_4, &chan_announcement_4.3, false);
+
                // Check that we processed all pending events
                for node in vec!(&node_1, &node_2, &node_3, &node_4) {
                        assert_eq!(node.get_and_clear_pending_events().len(), 0);
index 00f944d0a5fb4cc3348803202756c8e9a60ea256..5d657b13df585922626d37c9950d303838c3d8ae 100644 (file)
@@ -6,6 +6,8 @@ use ln::msgs::HandleError;
 use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::util::hash::Sha256dHash;
 
+use std::sync::Mutex;
+
 pub struct TestFeeEstimator {
        pub sat_per_vbyte: u64,
 }
@@ -26,10 +28,10 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
 }
 
 pub struct TestBroadcaster {
-
+       pub txn_broadcasted: Mutex<Vec<Transaction>>,
 }
 impl chaininterface::BroadcasterInterface for TestBroadcaster {
-       fn broadcast_transaction(&self, _tx: &Transaction) {
-               //TODO
+       fn broadcast_transaction(&self, tx: &Transaction) {
+               self.txn_broadcasted.lock().unwrap().push(tx.clone());
        }
 }