X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannelmanager.rs;h=ddd6b2f214afbf54910e7a6ba38a2de383484e17;hb=dfbcacfe0ef446234d0d40400fc818908311da7b;hp=20a3779899a620b185723bdf78d7513017321ee4;hpb=86944d34a1fb845fd01772f591422026d393a38d;p=rust-lightning diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 20a37798..ddd6b2f2 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -404,6 +404,38 @@ pub struct ChannelDetails { pub user_id: u64, } +macro_rules! handle_error { + ($self: ident, $internal: expr, $their_node_id: expr) => { + match $internal { + Ok(msg) => Ok(msg), + Err(MsgHandleErrInternal { err, needs_channel_force_close }) => { + if needs_channel_force_close { + match &err.action { + &Some(msgs::ErrorAction::DisconnectPeer { msg: Some(ref msg) }) => { + if msg.channel_id == [0; 32] { + $self.peer_disconnected(&$their_node_id, true); + } else { + $self.force_close_channel(&msg.channel_id); + } + }, + &Some(msgs::ErrorAction::DisconnectPeer { msg: None }) => {}, + &Some(msgs::ErrorAction::IgnoreError) => {}, + &Some(msgs::ErrorAction::SendErrorMessage { ref msg }) => { + if msg.channel_id == [0; 32] { + $self.peer_disconnected(&$their_node_id, true); + } else { + $self.force_close_channel(&msg.channel_id); + } + }, + &None => {}, + } + } + Err(err) + }, + } + } +} + impl ChannelManager { /// Constructs a new ChannelManager to hold several channels and route between them. /// @@ -1203,7 +1235,17 @@ impl ChannelManager { route: route.clone(), session_priv: session_priv.clone(), first_hop_htlc_msat: htlc_msat, - }, onion_packet).map_err(|he| APIError::ChannelUnavailable{err: he.err})? + }, onion_packet).map_err(|he| + match he { + ChannelError::Close(err) => { + // TODO: We need to close the channel here, but for that to be safe we have + // to do all channel closure inside the channel_state lock which is a + // somewhat-larger refactor, so we leave that for later. + APIError::ChannelUnavailable { err } + }, + ChannelError::Ignore(err) => APIError::ChannelUnavailable { err }, + } + )? }; match res { Some((update_add, commitment_signed, chan_monitor)) => { @@ -1243,24 +1285,30 @@ impl ChannelManager { let _ = self.total_consistency_lock.read().unwrap(); let (chan, msg, chan_monitor) = { - let mut channel_state = self.channel_state.lock().unwrap(); - match channel_state.by_id.remove(temporary_channel_id) { - Some(mut chan) => { - match chan.get_outbound_funding_created(funding_txo) { - Ok(funding_msg) => { - (chan, funding_msg.0, funding_msg.1) - }, - Err(e) => { - log_error!(self, "Got bad signatures: {}!", e.err); - channel_state.pending_msg_events.push(events::MessageSendEvent::HandleError { - node_id: chan.get_their_node_id(), - action: e.action, - }); - return; - }, - } + let (res, chan) = { + let mut channel_state = self.channel_state.lock().unwrap(); + match channel_state.by_id.remove(temporary_channel_id) { + Some(mut chan) => { + (chan.get_outbound_funding_created(funding_txo) + .map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, chan.channel_id())) + , chan) + }, + None => return + } + }; + match handle_error!(self, res, chan.get_their_node_id()) { + Ok(funding_msg) => { + (chan, funding_msg.0, funding_msg.1) + }, + Err(e) => { + log_error!(self, "Got bad signatures: {}!", e.err); + let mut channel_state = self.channel_state.lock().unwrap(); + channel_state.pending_msg_events.push(events::MessageSendEvent::HandleError { + node_id: chan.get_their_node_id(), + action: e.action, + }); + return; }, - None => return } }; // Because we have exclusive ownership of the channel here we can release the channel_state @@ -1372,9 +1420,7 @@ impl ChannelManager { let (commitment_msg, monitor) = match forward_chan.send_commitment() { Ok(res) => res, Err(e) => { - if let &Some(msgs::ErrorAction::DisconnectPeer{msg: Some(ref _err_msg)}) = &e.action { - } else if let &Some(msgs::ErrorAction::SendErrorMessage{msg: ref _err_msg}) = &e.action { - } else { + if let ChannelError::Ignore(_) = e { panic!("Stated return value requirements in send_commitment() were not met"); } //TODO: Handle...this is bad! @@ -1745,7 +1791,7 @@ impl ChannelManager { (chan.remove(), funding_msg, monitor_update) }, Err(e) => { - return Err(e).map_err(|e| MsgHandleErrInternal::from_maybe_close(e)) + return Err(e).map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.temporary_channel_id)) } } }, @@ -1783,7 +1829,7 @@ impl ChannelManager { //TODO: here and below MsgHandleErrInternal, #153 case return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.channel_id)); } - let chan_monitor = chan.funding_signed(&msg).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?; + let chan_monitor = chan.funding_signed(&msg).map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.channel_id))?; if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { unimplemented!(); } @@ -1942,10 +1988,20 @@ impl ChannelManager { // but if we've sent a shutdown and they haven't acknowledged it yet, we just // want to reject the new HTLC and fail it backwards instead of forwarding. if let PendingHTLCStatus::Forward(PendingForwardHTLCInfo { incoming_shared_secret, .. }) = pending_forward_info { + let chan_update = self.get_channel_update(chan); pending_forward_info = PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC { channel_id: msg.channel_id, htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&incoming_shared_secret, 0x1000|20, &self.get_channel_update(chan).unwrap().encode_with_len()[..]), + reason: if let Ok(update) = chan_update { + ChannelManager::build_first_hop_failure_packet(&incoming_shared_secret, 0x1000|20, &update.encode_with_len()[..]) + } else { + // This can only happen if the channel isn't in the fully-funded + // state yet, implying our counterparty is trying to route payments + // over the channel back to themselves (cause no one else should + // know the short_id is a lightning channel yet). We should have no + // problem just calling this unknown_next_peer + ChannelManager::build_first_hop_failure_packet(&incoming_shared_secret, 0x4000|10, &[]) + }, })); } } @@ -2213,7 +2269,8 @@ impl ChannelManager { //TODO: here and below MsgHandleErrInternal, #153 case return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.channel_id)); } - let (revoke_and_ack, commitment_signed, closing_signed, chan_monitor) = chan.commitment_signed(&msg, &*self.fee_estimator).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?; + let (revoke_and_ack, commitment_signed, closing_signed, chan_monitor) = chan.commitment_signed(&msg, &*self.fee_estimator) + .map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.channel_id))?; if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { unimplemented!(); } @@ -2289,7 +2346,8 @@ impl ChannelManager { //TODO: here and below MsgHandleErrInternal, #153 case return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.channel_id)); } - let (commitment_update, pending_forwards, pending_failures, closing_signed, chan_monitor) = chan.revoke_and_ack(&msg, &*self.fee_estimator).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?; + let (commitment_update, pending_forwards, pending_failures, closing_signed, chan_monitor) = chan.revoke_and_ack(&msg, &*self.fee_estimator) + .map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.channel_id))?; if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { unimplemented!(); } @@ -2455,7 +2513,16 @@ impl ChannelManager { if !chan.is_live() { return Err(APIError::ChannelUnavailable{err: "Channel is either not yet fully established or peer is currently disconnected"}); } - if let Some((update_fee, commitment_signed, chan_monitor)) = chan.send_update_fee_and_commit(feerate_per_kw).map_err(|e| APIError::APIMisuseError{err: e.err})? { + if let Some((update_fee, commitment_signed, chan_monitor)) = chan.send_update_fee_and_commit(feerate_per_kw) + .map_err(|e| match e { + ChannelError::Ignore(err) => APIError::APIMisuseError{err}, + ChannelError::Close(err) => { + // TODO: We need to close the channel here, but for that to be safe we have + // to do all channel closure inside the channel_state lock which is a + // somewhat-larger refactor, so we leave that for later. + APIError::APIMisuseError{err} + }, + })? { if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { unimplemented!(); } @@ -2608,38 +2675,6 @@ impl ChainListener for ChannelManager { } } -macro_rules! handle_error { - ($self: ident, $internal: expr, $their_node_id: expr) => { - match $internal { - Ok(msg) => Ok(msg), - Err(MsgHandleErrInternal { err, needs_channel_force_close }) => { - if needs_channel_force_close { - match &err.action { - &Some(msgs::ErrorAction::DisconnectPeer { msg: Some(ref msg) }) => { - if msg.channel_id == [0; 32] { - $self.peer_disconnected(&$their_node_id, true); - } else { - $self.force_close_channel(&msg.channel_id); - } - }, - &Some(msgs::ErrorAction::DisconnectPeer { msg: None }) => {}, - &Some(msgs::ErrorAction::IgnoreError) => {}, - &Some(msgs::ErrorAction::SendErrorMessage { ref msg }) => { - if msg.channel_id == [0; 32] { - $self.peer_disconnected(&$their_node_id, true); - } else { - $self.force_close_channel(&msg.channel_id); - } - }, - &None => {}, - } - } - Err(err) - }, - } - } -} - impl ChannelMessageHandler for ChannelManager { //TODO: Handle errors and close channel (or so) fn handle_open_channel(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<(), HandleError> { @@ -4446,7 +4481,7 @@ mod tests { #[test] fn test_update_fee_that_funder_cannot_afford() { - let mut nodes = create_network(2); + let nodes = create_network(2); let channel_value = 1888; let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 700000); let channel_id = chan.2; @@ -4481,7 +4516,7 @@ mod tests { let update2_msg = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); - nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update2_msg.update_fee.unwrap()); + nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update2_msg.update_fee.unwrap()).unwrap(); //While producing the commitment_signed response after handling a received update_fee request the //check to see if the funder, who sent the update_fee request, can afford the new fee (funder_balance >= fee+channel_reserve) @@ -5334,8 +5369,7 @@ mod tests { }} } - #[test] - fn channel_reserve_test() { + fn do_channel_reserve_test(test_recv: bool) { use util::rng; use std::sync::atomic::Ordering; use ln::msgs::HandleError; @@ -5492,9 +5526,23 @@ mod tests { onion_routing_packet: onion_packet, }; - let err = nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &msg).err().unwrap(); - match err { - HandleError{err, .. } => assert_eq!(err, "Remote HTLC add would put them over their reserve value"), + if test_recv { + let err = nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &msg).err().unwrap(); + match err { + HandleError{err, .. } => assert_eq!(err, "Remote HTLC add would put them over their reserve value"), + } + // If we send a garbage message, the channel should get closed, making the rest of this test case fail. + /*assert_eq!(nodes[1].node.list_channels().len(), 1); + assert_eq!(nodes[1].node.list_channels().len(), 1); + let channel_close_broadcast = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(channel_close_broadcast.len(), 1); + match channel_close_broadcast[0] { + MessageSendEvent::BroadcastChannelUpdate { ref msg } => { + assert_eq!(msg.contents.flags & 2, 2); + }, + _ => panic!("Unexpected event"), + }*/ + return; } } @@ -5602,6 +5650,12 @@ mod tests { assert_eq!(stat2.value_to_self_msat, stat22.value_to_self_msat + recv_value_1 + recv_value_21 + recv_value_22); } + #[test] + fn channel_reserve_test() { + do_channel_reserve_test(false); + do_channel_reserve_test(true); + } + #[test] fn channel_monitor_network_test() { // Simple test which builds a network of ChannelManagers, connects them to each other, and