From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Mon, 2 Apr 2018 22:14:24 +0000 (-0400) Subject: Merge pull request #17 from TheBlueMatt/2017-04-channel-close X-Git-Tag: v0.0.12~415 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=f7dd69240afcd3a0087f7796824a9e2697ed85cf;hp=2018782d119219d9dbde3b993e165b687c3ec268;p=rust-lightning Merge pull request #17 from TheBlueMatt/2017-04-channel-close Add support for channel closure (based on new upstream rust-bitcoin) --- diff --git a/Cargo.toml b/Cargo.toml index f5aa85db4..8e1946b1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning" -version = "0.0.1" +version = "0.0.2" authors = ["Matt Corallo"] license = "Apache-2.0" repository = "https://github.com/TheBlueMatt/rust-lightning/" @@ -15,7 +15,7 @@ non_bitcoin_chain_hash_routing = [] fuzztarget = ["secp256k1/fuzztarget", "bitcoin/fuzztarget"] [dependencies] -bitcoin = "0.12" +bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin" } rust-crypto = "0.2" rand = "0.4" secp256k1 = "0.9" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 6b45066e8..7ed7533a3 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -13,7 +13,7 @@ honggfuzz_fuzz = ["honggfuzz"] [dependencies] lightning = { path = "..", features = ["fuzztarget"] } -bitcoin = { version = "0.12", features = ["fuzztarget"] } +bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin", features = ["fuzztarget"] } secp256k1 = { version = "0.9", features = ["fuzztarget"] } honggfuzz = { version = "0.5", optional = true } afl = { version = "0.3", optional = true } diff --git a/fuzz/fuzz_targets/channel_target.rs b/fuzz/fuzz_targets/channel_target.rs index ec82fbd65..d07b342da 100644 --- a/fuzz/fuzz_targets/channel_target.rs +++ b/fuzz/fuzz_targets/channel_target.rs @@ -163,7 +163,7 @@ pub fn do_test(data: &[u8]) { let their_pubkey = get_pubkey!(); - let tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new(), witness: Vec::new() }; + let tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() }; let funding_output = (Sha256dHash::from_data(&serialize(&tx).unwrap()[..]), 0); let mut channel = if get_slice!(1)[0] != 0 { @@ -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 0264bbefd..c7ad6d49d 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 fe1cfd24a..c9c9e4143 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