From c528ff36503f3074b076caf639a7dbf14f1b1fd6 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 26 Mar 2018 16:48:18 -0400 Subject: [PATCH] Handle incoming shutdown messages --- fuzz/fuzz_targets/channel_target.rs | 8 + fuzz/fuzz_targets/full_stack_target.rs | 11 +- src/ln/channel.rs | 323 +++++++++++++++++++++++-- src/ln/channelmanager.rs | 81 +++++-- src/ln/msgs.rs | 4 +- src/ln/peer_handler.rs | 13 +- src/util/test_utils.rs | 10 + 7 files changed, 410 insertions(+), 40 deletions(-) diff --git a/fuzz/fuzz_targets/channel_target.rs b/fuzz/fuzz_targets/channel_target.rs index 0dd0d6a7..d07b342d 100644 --- a/fuzz/fuzz_targets/channel_target.rs +++ b/fuzz/fuzz_targets/channel_target.rs @@ -248,6 +248,14 @@ pub fn do_test(data: &[u8]) { let update_fee = decode_msg!(msgs::UpdateFee, 32+4); return_err!(channel.update_fee(&fee_est, &update_fee)); }, + 9 => { + let shutdown = decode_msg_with_len16!(msgs::Shutdown, 32, 1); + return_err!(channel.shutdown(&fee_est, &shutdown)); + }, + 10 => { + let closing_signed = decode_msg!(msgs::ClosingSigned, 32+8+64); + return_err!(channel.closing_signed(&fee_est, &closing_signed)); + }, _ => return, } } diff --git a/fuzz/fuzz_targets/full_stack_target.rs b/fuzz/fuzz_targets/full_stack_target.rs index 0264bbef..c7ad6d49 100644 --- a/fuzz/fuzz_targets/full_stack_target.rs +++ b/fuzz/fuzz_targets/full_stack_target.rs @@ -2,10 +2,11 @@ extern crate bitcoin; extern crate lightning; extern crate secp256k1; +use bitcoin::blockdata::transaction::Transaction; use bitcoin::network::constants::Network; use bitcoin::util::hash::Sha256dHash; -use lightning::chain::chaininterface::{ConfirmationTarget,FeeEstimator,ChainWatchInterfaceUtil}; +use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,FeeEstimator,ChainWatchInterfaceUtil}; use lightning::ln::{channelmonitor,msgs}; use lightning::ln::channelmanager::ChannelManager; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; @@ -73,6 +74,11 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { } } +struct TestBroadcaster {} +impl BroadcasterInterface for TestBroadcaster { + fn broadcast_transaction(&self, _tx: &Transaction) {} +} + #[derive(Clone, PartialEq, Eq, Hash)] struct Peer { id: u8, @@ -120,8 +126,9 @@ pub fn do_test(data: &[u8]) { let monitor = Arc::new(TestChannelMonitor{}); let watch = Arc::new(ChainWatchInterfaceUtil::new()); + let broadcast = Arc::new(TestBroadcaster{}); - let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone()).unwrap(); + let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone()).unwrap(); let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key).unwrap())); let handler = PeerManager::new(MessageHandler { diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 6f51c0a6..08fa3efb 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -149,7 +149,20 @@ enum ChannelState { /// later. /// Flag is set on ChannelFunded. AwaitingRemoteRevoke = (1 << 7), + /// Flag which is set on ChannelFunded or FundingSent after receiving a shutdown message from + /// the remote end. If set, they may not add any new HTLCs to the channel, and we are expected + /// to respond with our own shutdown message when possible. + RemoteShutdownSent = (1 << 8), + /// Flag which is set on ChannelFunded or FundingSent after sending a shutdown message. At this + /// point, we may not add any new HTLCs to the channel. + /// TODO: Investigate some kind of timeout mechanism by which point the remote end must provide + /// us their shutdown. + LocalShutdownSent = (1 << 9), + /// We've successfully negotiated a closing_signed dance. At this point ChannelManager is about + /// to drop us, but we store this anyway. + ShutdownComplete = (1 << 10), } +const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32); // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like @@ -177,6 +190,8 @@ pub struct Channel { channel_update_count: u32, feerate_per_kw: u64, + last_sent_closing_fee: Option<(u64, u64)>, // (feerate, fee) + /// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this /// to detect unconfirmation after a serialize-unserialize roudtrip where we may not see a full /// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we @@ -208,6 +223,8 @@ pub struct Channel { their_cur_commitment_point: PublicKey, their_node_id: PublicKey, + their_shutdown_scriptpubkey: Option