X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannelmanager.rs;h=2f13b80452f59c167b5c3b7c33733de5ebe49273;hb=0795b34e1067a118b21e8ecb8cfac42cab43fa21;hp=3d70b1d379a4391461b3c5a756e126716d8d701d;hpb=ab56b81acd9da3a697dfc37fc4cb43cd8fbb1a2c;p=rust-lightning diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 3d70b1d3..2f13b804 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -26,11 +26,10 @@ use crypto::digest::Digest; use crypto::symmetriccipher::SynchronousStreamCipher; use crypto::chacha20::ChaCha20; -use std::sync::{Mutex,Arc}; +use std::sync::{Mutex,MutexGuard,Arc}; use std::collections::HashMap; use std::collections::hash_map; -use std::ptr; -use std::mem; +use std::{ptr, mem}; use std::time::{Instant,Duration}; /// Stores the info we will need to send when we want to forward an HTLC onwards @@ -42,6 +41,20 @@ pub struct PendingForwardHTLCInfo { amt_to_forward: u64, outgoing_cltv_value: u32, } +//TODO: This is public, and needed to call Channel::update_add_htlc, so there needs to be a way to +//initialize it usefully...probably make it optional in Channel instead). +impl PendingForwardHTLCInfo { + pub fn dummy() -> Self { + Self { + onion_packet: None, + payment_hash: [0; 32], + short_channel_id: 0, + prev_short_channel_id: 0, + amt_to_forward: 0, + outgoing_cltv_value: 0, + } + } +} enum PendingOutboundHTLC { IntermediaryHopData { @@ -65,6 +78,7 @@ enum HTLCFailReason<'a> { }, Reason { failure_code: u16, + data: &'a[u8], } } @@ -558,6 +572,7 @@ impl ChannelManager { pub fn process_pending_htlc_forward(&self) { let mut new_events = Vec::new(); + let mut failed_forwards = Vec::new(); { let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = channel_state_lock.borrow_parts(); @@ -571,6 +586,10 @@ impl ChannelManager { let forward_chan_id = match channel_state.short_to_id.get(&short_chan_id) { Some(chan_id) => chan_id.clone(), None => { + failed_forwards.reserve(pending_forwards.len()); + for forward_info in pending_forwards { + failed_forwards.push((forward_info.payment_hash, 0x4000 | 10, None)); + } // TODO: Send a failure packet back on each pending_forward continue; } @@ -581,7 +600,8 @@ impl ChannelManager { for forward_info in pending_forwards { match forward_chan.send_htlc(forward_info.amt_to_forward, forward_info.payment_hash, forward_info.outgoing_cltv_value, forward_info.onion_packet.unwrap()) { Err(_e) => { - // TODO: Send a failure packet back + let chan_update = self.get_channel_update(forward_chan).unwrap(); + failed_forwards.push((forward_info.payment_hash, 0x4000 | 7, Some(chan_update))); continue; }, Ok(update_add) => { @@ -626,6 +646,13 @@ impl ChannelManager { } } + for failed_forward in failed_forwards.drain(..) { + match failed_forward.2 { + None => self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failed_forward.0, HTLCFailReason::Reason { failure_code: failed_forward.1, data: &[0;0] }), + Some(chan_update) => self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failed_forward.0, HTLCFailReason::Reason { failure_code: failed_forward.1, data: &chan_update.encode()[..] }), + }; + } + if new_events.is_empty() { return } let mut events = self.pending_events.lock().unwrap(); @@ -637,11 +664,10 @@ impl ChannelManager { /// Indicates that the preimage for payment_hash is unknown after a PaymentReceived event. pub fn fail_htlc_backwards(&self, payment_hash: &[u8; 32]) -> bool { - self.fail_htlc_backwards_internal(payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 15 }) + self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: &[0;0] }) } - fn fail_htlc_backwards_internal(&self, payment_hash: &[u8; 32], onion_error: HTLCFailReason) -> bool { - let mut channel_state = self.channel_state.lock().unwrap(); + fn fail_htlc_backwards_internal(&self, mut channel_state: MutexGuard, payment_hash: &[u8; 32], onion_error: HTLCFailReason) -> bool { let mut pending_htlc = { match channel_state.claimable_htlcs.remove(payment_hash) { Some(pending_htlc) => pending_htlc, @@ -660,6 +686,7 @@ impl ChannelManager { PendingOutboundHTLC::CycledRoute { .. } => { panic!("WAT"); }, PendingOutboundHTLC::OutboundRoute { .. } => { //TODO: DECRYPT route from OutboundRoute + mem::drop(channel_state); let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::PaymentFailed { payment_hash: payment_hash.clone() @@ -668,8 +695,8 @@ impl ChannelManager { }, PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret } => { let err_packet = match onion_error { - HTLCFailReason::Reason { failure_code } => { - let packet = ChannelManager::build_failure_packet(&incoming_packet_shared_secret, failure_code, &[0; 0]).encode(); + HTLCFailReason::Reason { failure_code, data } => { + let packet = ChannelManager::build_failure_packet(&incoming_packet_shared_secret, failure_code, data).encode(); ChannelManager::encrypt_failure_packet(&incoming_packet_shared_secret, &packet) }, HTLCFailReason::ErrorPacket { err } => { @@ -693,6 +720,7 @@ impl ChannelManager { } }; + mem::drop(channel_state); let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::SendFailHTLC { node_id, @@ -971,6 +999,33 @@ impl ChannelMessageHandler for ChannelManager { let associated_data = Vec::new(); //TODO: What to put here? + macro_rules! get_onion_hash { + () => { + { + let mut sha = Sha256::new(); + sha.input(&msg.onion_routing_packet.hop_data); + let mut onion_hash = [0; 32]; + sha.result(&mut onion_hash); + onion_hash + } + } + } + + macro_rules! return_err { + ($msg: expr, $err_code: expr, $data: expr) => { + return Err(msgs::HandleError { + err: $msg, + msg: Some(msgs::ErrorMessage::UpdateFailHTLC { + msg: msgs::UpdateFailHTLC { + channel_id: msg.channel_id, + htlc_id: msg.htlc_id, + reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, $err_code, $data), + } + }), + }); + } + } + if msg.onion_routing_packet.version != 0 { //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way, @@ -978,39 +1033,14 @@ impl ChannelMessageHandler for ChannelManager { //receiving node would have to brute force to figure out which version was put in the //packet by the node that send us the message, in the case of hashing the hop_data, the //node knows the HMAC matched, so they already know what is there... - let mut sha = Sha256::new(); - sha.input(&msg.onion_routing_packet.hop_data); - let mut onion_hash = [0; 32]; - sha.result(&mut onion_hash); - return Err(msgs::HandleError { - err: "Unknown onion packet version", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x8000 | 0x4000 | 4, &onion_hash), - } - }), - }); + return_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4, &get_onion_hash!()); } let mut hmac = Hmac::new(Sha256::new(), &mu); hmac.input(&msg.onion_routing_packet.hop_data); hmac.input(&associated_data[..]); if hmac.result() != MacResult::new(&msg.onion_routing_packet.hmac) { - let mut sha = Sha256::new(); - sha.input(&msg.onion_routing_packet.hop_data); - let mut onion_hash = [0; 32]; - sha.result(&mut onion_hash); - return Err(HandleError{err: "HMAC Check failed", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x8000 | 0x4000 | 5, &onion_hash), - } - }), - }); + return_err!("HMAC Check failed", 0x8000 | 0x4000 | 5, &get_onion_hash!()); } let mut chacha = ChaCha20::new(&rho, &[0u8; 8]); @@ -1023,15 +1053,7 @@ impl ChannelMessageHandler for ChannelManager { msgs::DecodeError::UnknownRealmByte => 0x4000 | 1, _ => 0x2000 | 2, // Should never happen }; - return Err(HandleError{err: "Unable to decode our hop data", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, error_code, &[0;0]), - } - }), - }); + return_err!("Unable to decode our hop data", error_code, &[0;0]); }, Ok(msg) => msg } @@ -1040,26 +1062,10 @@ impl ChannelMessageHandler for ChannelManager { let mut pending_forward_info = if next_hop_data.hmac == [0; 32] { // OUR PAYMENT! if next_hop_data.data.amt_to_forward != msg.amount_msat { - return Err(HandleError{err: "Upstream node sent less than we were supposed to receive in payment", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 19, &byte_utils::be64_to_array(msg.amount_msat)), - } - }), - }); + return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat)); } if next_hop_data.data.outgoing_cltv_value != msg.cltv_expiry { - return Err(HandleError{err: "Upstream node set CLTV to the wrong value", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 18, &byte_utils::be32_to_array(msg.cltv_expiry)), - } - }), - }); + return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry)); } // Note that we could obviously respond immediately with an update_fulfill_htlc @@ -1092,15 +1098,7 @@ impl ChannelMessageHandler for ChannelManager { Err(_) => { // Return temporary node failure as its technically our issue, not the // channel's issue. - return Err(HandleError{err: "Blinding factor is an invalid private key", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x2000 | 2, &[0;0]), - } - }), - }); + return_err!("Blinding factor is an invalid private key", 0x2000 | 2, &[0;0]); }, Ok(key) => key } @@ -1110,15 +1108,7 @@ impl ChannelMessageHandler for ChannelManager { Err(_) => { // Return temporary node failure as its technically our issue, not the // channel's issue. - return Err(HandleError{err: "New blinding factor is an invalid private key", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x2000 | 2, &[0;0]), - } - }), - }); + return_err!("New blinding factor is an invalid private key", 0x2000 | 2, &[0;0]); }, Ok(_) => {} }; @@ -1148,30 +1138,14 @@ impl ChannelMessageHandler for ChannelManager { if pending_forward_info.onion_packet.is_some() { // If short_channel_id is 0 here, we'll reject them in the body here let forwarding_id = match channel_state.short_to_id.get(&pending_forward_info.short_channel_id) { None => { - return Err(HandleError{err: "Don't have available channel for forwarding as requested.", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x4000 | 10, &[0;0]), - } - }), - }); + return_err!("Don't have available channel for forwarding as requested.", 0x4000 | 10, &[0;0]); }, Some(id) => id.clone(), }; let chan = channel_state.by_id.get_mut(&forwarding_id).unwrap(); if !chan.is_live() { let chan_update = self.get_channel_update(chan).unwrap(); - return Err(HandleError{err: "Forwarding channel is not in a ready state.", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x4000 | 10, &chan_update.encode()[..]), - } - }), - }); + return_err!("Forwarding channel is not in a ready state.", 0x4000 | 10, &chan_update.encode()[..]); } } @@ -1191,15 +1165,7 @@ impl ChannelMessageHandler for ChannelManager { _ => {}, } if !acceptable_cycle { - return Err(HandleError{err: "Payment looped through us twice", - msg: Some(msgs::ErrorMessage::UpdateFailHTLC { - msg: msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x4000 | 0x2000|2, &[0;0]), - } - }), - }); + return_err!("Payment looped through us twice", 0x4000 | 0x2000 | 2, &[0;0]); } }, _ => {}, @@ -1222,7 +1188,7 @@ impl ChannelMessageHandler for ChannelManager { match claimable_htlcs_entry { hash_map::Entry::Occupied(mut e) => { - let mut outbound_route = e.get_mut(); + let outbound_route = e.get_mut(); let route = match outbound_route { &mut PendingOutboundHTLC::OutboundRoute { ref route } => { route.clone() @@ -1265,36 +1231,34 @@ impl ChannelMessageHandler for ChannelManager { } fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { - let res = { - let mut channel_state = self.channel_state.lock().unwrap(); - match channel_state.by_id.get_mut(&msg.channel_id) { - Some(chan) => { - if chan.get_their_node_id() != *their_node_id { - return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) - } - chan.update_fail_htlc(&msg)? - }, - None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) - } - }; - self.fail_htlc_backwards_internal(&res.0, HTLCFailReason::ErrorPacket { err: &msg.reason }); + let mut channel_state = self.channel_state.lock().unwrap(); + let res; + match channel_state.by_id.get_mut(&msg.channel_id) { + Some(chan) => { + if chan.get_their_node_id() != *their_node_id { + return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) + } + res = chan.update_fail_htlc(&msg)?; + }, + None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) + } + self.fail_htlc_backwards_internal(channel_state, &res.0, HTLCFailReason::ErrorPacket { err: &msg.reason }); Ok(res.1) } fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailMalformedHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { - let res = { - let mut channel_state = self.channel_state.lock().unwrap(); - match channel_state.by_id.get_mut(&msg.channel_id) { - Some(chan) => { - if chan.get_their_node_id() != *their_node_id { - return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) - } - chan.update_fail_malformed_htlc(&msg)? - }, - None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) - } - }; - self.fail_htlc_backwards_internal(&res.0, HTLCFailReason::Reason { failure_code: msg.failure_code }); + let mut channel_state = self.channel_state.lock().unwrap(); + let res; + match channel_state.by_id.get_mut(&msg.channel_id) { + Some(chan) => { + if chan.get_their_node_id() != *their_node_id { + return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) + } + res = chan.update_fail_malformed_htlc(&msg)?; + }, + None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) + } + self.fail_htlc_backwards_internal(channel_state, &res.0, HTLCFailReason::Reason { failure_code: msg.failure_code, data: &[0;0] }); Ok(res.1) }