use chain::chaininterface::{BroadcasterInterface,ChainListener,ChainWatchInterface,FeeEstimator};
use ln::channel::{Channel, ChannelKeys};
use ln::channelmonitor::ManyChannelMonitor;
-use ln::router::Route;
+use ln::router::{Route,RouteHop};
use ln::msgs;
use ln::msgs::{HandleError,ChannelMessageHandler,MsgEncodable,MsgDecodable};
use util::{byte_utils, events, internal_traits, rng};
use util::sha2::Sha256;
+use crypto;
use crypto::mac::{Mac,MacResult};
use crypto::hmac::Hmac;
use crypto::digest::Digest;
},
OutboundRoute {
route: Route,
+ session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {
source_short_channel_id: u64,
incoming_packet_shared_secret: SharedSecret,
route: Route,
+ session_priv: SecretKey,
}
}
res
}
- fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, HandleError> {
- let mut res = Vec::with_capacity(route.hops.len());
+ // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
+ #[inline]
+ fn construct_onion_keys_callback<FType: FnMut(SharedSecret, [u8; 32], PublicKey, &RouteHop)> (secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), HandleError> {
let mut blinded_priv = session_priv.clone();
let mut blinded_pub = secp_call!(PublicKey::from_secret_key(secp_ctx, &blinded_priv));
let mut first_iteration = true;
secp_call!(blinded_priv.mul_assign(secp_ctx, &secp_call!(SecretKey::from_slice(secp_ctx, &blinding_factor))));
blinded_pub = secp_call!(PublicKey::from_secret_key(secp_ctx, &blinded_priv));
+ callback(shared_secret, blinding_factor, ephemeral_pubkey, hop);
+ }
+
+ Ok(())
+ }
+
+ // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
+ fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, HandleError> {
+ let mut res = Vec::with_capacity(route.hops.len());
+
+ Self::construct_onion_keys_callback(secp_ctx, route, session_priv, |shared_secret, _blinding_factor, ephemeral_pubkey, _| {
let (rho, mu) = ChannelManager::gen_rho_mu_from_shared_secret(&shared_secret);
res.push(OnionKeys {
#[cfg(test)]
- shared_secret: shared_secret,
+ shared_secret,
#[cfg(test)]
- blinding_factor: blinding_factor,
- ephemeral_pubkey: ephemeral_pubkey,
- rho: rho,
- mu: mu,
+ blinding_factor: _blinding_factor,
+ ephemeral_pubkey,
+ rho,
+ mu,
});
- }
+ })?;
Ok(res)
}
};
if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute {
- route: route,
+ route,
+ session_priv,
}).is_some() {
// TODO: We need to track these better, we're not generating these, so a
// third-party might make this happen:
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: Vec::new() }),
- 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() }),
+ 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_with_len() }),
};
}
};
match pending_htlc {
- PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, .. } => {
+ PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route, session_priv } => {
+ channel_state.claimable_htlcs.insert(payment_hash.clone(), PendingOutboundHTLC::OutboundRoute {
+ route,
+ session_priv,
+ });
pending_htlc = PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret };
},
_ => {}
match pending_htlc {
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()
};
match pending_htlc {
- PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route } => {
+ PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route, session_priv } => {
if from_user { // This was the end hop back to us
pending_htlc = PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret };
- channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { route });
+ channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { route, session_priv });
} else { // This came from the first upstream node
// Bank error in our favor! Maybe we should tell the user this somehow???
- pending_htlc = PendingOutboundHTLC::OutboundRoute { route };
+ pending_htlc = PendingOutboundHTLC::OutboundRoute { route, session_priv };
channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret });
}
},
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!("Forwarding channel is not in a ready state.", 0x4000 | 10, &chan_update.encode()[..]);
+ return_err!("Forwarding channel is not in a ready state.", 0x4000 | 7, &chan_update.encode_with_len()[..]);
}
}
match claimable_htlcs_entry {
hash_map::Entry::Occupied(mut e) => {
let outbound_route = e.get_mut();
- let route = match outbound_route {
- &mut PendingOutboundHTLC::OutboundRoute { ref route } => {
- route.clone()
+ let (route, session_priv) = match outbound_route {
+ &mut PendingOutboundHTLC::OutboundRoute { ref route, ref session_priv } => {
+ (route.clone(), session_priv.clone())
},
_ => { panic!("WAT") },
};
*outbound_route = PendingOutboundHTLC::CycledRoute {
source_short_channel_id,
incoming_packet_shared_secret: shared_secret,
- route
+ route,
+ session_priv,
};
},
hash_map::Entry::Vacant(e) => {
Ok(())
}
- fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<(), HandleError> {
+ fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<Option<msgs::HTLCFailChannelUpdate>, HandleError> {
let mut channel_state = self.channel_state.lock().unwrap();
- match channel_state.by_id.get_mut(&msg.channel_id) {
+ let payment_hash = 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, HTLCFailReason::ErrorPacket { err: msg.reason.clone() })
},
None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ }?;
+
+ if let Some(pending_htlc) = channel_state.claimable_htlcs.get(&payment_hash) {
+ match pending_htlc {
+ &PendingOutboundHTLC::OutboundRoute { ref route, ref session_priv } => {
+ // Handle packed channel/node updates for passing back for the route handler
+ let mut packet_decrypted = msg.reason.data.clone();
+ let mut res = None;
+ Self::construct_onion_keys_callback(&self.secp_ctx, &route, &session_priv, |shared_secret, _, _, route_hop| {
+ if res.is_some() { return; }
+
+ let ammag = ChannelManager::gen_ammag_from_shared_secret(&shared_secret);
+
+ let mut decryption_tmp = Vec::with_capacity(packet_decrypted.len());
+ decryption_tmp.resize(packet_decrypted.len(), 0);
+ let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]);
+ chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
+ packet_decrypted = decryption_tmp;
+
+ if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::decode(&packet_decrypted) {
+ if err_packet.failuremsg.len() >= 2 {
+ let um = ChannelManager::gen_um_from_shared_secret(&shared_secret);
+
+ let mut hmac = Hmac::new(Sha256::new(), &um);
+ hmac.input(&err_packet.encode()[32..]);
+ let mut calc_tag = [0u8; 32];
+ hmac.raw_result(&mut calc_tag);
+ if crypto::util::fixed_time_eq(&calc_tag, &err_packet.hmac) {
+ const UNKNOWN_CHAN: u16 = 0x4000|10;
+ const TEMP_CHAN_FAILURE: u16 = 0x4000|7;
+ match byte_utils::slice_to_be16(&err_packet.failuremsg[0..2]) {
+ TEMP_CHAN_FAILURE => {
+ if err_packet.failuremsg.len() >= 4 {
+ let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[2..4]) as usize;
+ if err_packet.failuremsg.len() >= 4 + update_len {
+ if let Ok(chan_update) = msgs::ChannelUpdate::decode(&err_packet.failuremsg[4..4 + update_len]) {
+ res = Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
+ msg: chan_update,
+ });
+ }
+ }
+ }
+ },
+ UNKNOWN_CHAN => {
+ // No such next-hop. We know this came from the
+ // current node as the HMAC validated.
+ res = Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
+ short_channel_id: route_hop.short_channel_id
+ });
+ },
+ _ => {}, //TODO: Enumerate all of these!
+ }
+ }
+ }
+ }
+ }).unwrap();
+ Ok(res)
+ },
+ _ => { Ok(None) },
+ }
+ } else {
+ Ok(None)
}
}
claim_payment(&origin, expected_route, our_payment_preimage);
}
- fn send_failed_payment(origin_node: &Node, expected_route: &[&Node]) {
- let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), 1000000, 142).unwrap();
- assert_eq!(route.hops.len(), expected_route.len());
- for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
- assert_eq!(hop.pubkey, node.node.get_our_node_id());
- }
- let our_payment_hash = send_along_route(origin_node, route, expected_route, 1000000).1;
-
+ fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: [u8; 32]) {
assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash));
let mut next_msgs: Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)> = None;
send_payment(&nodes[3], &vec!(&nodes[2], &nodes[1])[..], 1000000);
// Test failure packets
- send_failed_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..]);
+ let payment_hash_1 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], 1000000).1;
+ fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], payment_hash_1);
// Add a new channel that skips 3
let chan_4 = create_announced_chan_between_nodes(&nodes, 1, 3);
});
hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
- let payment_preimage_2 = send_along_route(&nodes[1], Route { hops }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).0;
+ let payment_hash_2 = send_along_route(&nodes[1], Route { hops }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).1;
// Claim the rebalances...
- claim_payment(&nodes[1], &vec!(&nodes[3], &nodes[2], &nodes[1])[..], payment_preimage_2);
+ fail_payment(&nodes[1], &vec!(&nodes[3], &nodes[2], &nodes[1])[..], payment_hash_2);
claim_payment(&nodes[1], &vec!(&nodes[2], &nodes[3], &nodes[1])[..], payment_preimage_1);
// Add a duplicate new channel from 2 to 4
fn encode(&self) -> Vec<u8>;
#[inline]
fn encoded_len(&self) -> usize { self.encode().len() }
+ #[inline]
+ fn encode_with_len(&self) -> Vec<u8> {
+ let enc = self.encode();
+ let mut res = Vec::with_capacity(enc.len() + 2);
+ res.extend_from_slice(&byte_utils::be16_to_array(enc.len() as u16));
+ res.extend_from_slice(&enc);
+ res
+ }
}
#[derive(Debug)]
pub enum DecodeError {
pub commitment_signed: CommitmentSigned,
}
+pub enum HTLCFailChannelUpdate {
+ ChannelUpdateMessage {
+ msg: ChannelUpdate,
+ },
+ ChannelClosed {
+ short_channel_id: u64,
+ },
+}
+
/// A trait to describe an object which can receive channel messages. Messages MAY be called in
/// paralell when they originate from different their_node_ids, however they MUST NOT be called in
/// paralell when the two calls have the same their_node_id.
// HTLC handling:
fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC) -> Result<(), HandleError>;
fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillHTLC) -> Result<(), HandleError>;
- fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC) -> Result<(), HandleError>;
+ fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC) -> Result<Option<HTLCFailChannelUpdate>, HandleError>;
fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailMalformedHTLC) -> Result<(), HandleError>;
fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &CommitmentSigned) -> Result<(RevokeAndACK, Option<CommitmentSigned>), HandleError>;
fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &RevokeAndACK) -> Result<Option<CommitmentUpdate>, HandleError>;
/// or returning an Err otherwise.
fn handle_channel_announcement(&self, msg: &ChannelAnnouncement) -> Result<bool, HandleError>;
fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result<(), HandleError>;
+ fn handle_htlc_fail_channel_update(&self, update: &HTLCFailChannelUpdate);
}
pub struct OnionRealm0HopData {
}
impl MsgDecodable for DecodedOnionErrorPacket {
- fn decode(_v: &[u8]) -> Result<Self, DecodeError> {
- unimplemented!();
+ fn decode(v: &[u8]) -> Result<Self, DecodeError> {
+ if v.len() < 32 + 4 {
+ return Err(DecodeError::WrongLength);
+ }
+ let failuremsg_len = byte_utils::slice_to_be16(&v[32..34]) as usize;
+ if v.len() < 32 + 4 + failuremsg_len {
+ return Err(DecodeError::WrongLength);
+ }
+ let padding_len = byte_utils::slice_to_be16(&v[34 + failuremsg_len..]) as usize;
+ if v.len() < 32 + 4 + failuremsg_len + padding_len {
+ return Err(DecodeError::WrongLength);
+ }
+
+ let mut hmac = [0; 32];
+ hmac.copy_from_slice(&v[0..32]);
+ Ok(Self {
+ hmac,
+ failuremsg: v[34..34 + failuremsg_len].to_vec(),
+ pad: v[36 + failuremsg_len..36 + failuremsg_len + padding_len].to_vec(),
+ })
}
}
impl MsgEncodable for DecodedOnionErrorPacket {