+//! The top-level routing/network map tracking logic lives here.
+//!
+//! You probably want to create a Router and use that as your RoutingMessageHandler and then
+//! interrogate it to get routes for your own payments.
+
use secp256k1::key::PublicKey;
use secp256k1::{Secp256k1,Message};
use secp256k1;
use chain::chaininterface::{ChainError, ChainWatchInterface};
use ln::channelmanager;
-use ln::msgs::{ErrorAction,HandleError,RoutingMessageHandler,MsgEncodable,NetAddress,GlobalFeatures};
+use ln::msgs::{DecodeError,ErrorAction,HandleError,RoutingMessageHandler,NetAddress,GlobalFeatures};
use ln::msgs;
+use util::ser::{Writeable, Readable};
use util::logger::Logger;
use std::cmp;
/// A hop in a route
#[derive(Clone)]
pub struct RouteHop {
+ /// The node_id of the node at this hop.
pub pubkey: PublicKey,
/// The channel that should be used from the previous hop to reach this node.
pub short_channel_id: u64,
pub hops: Vec<RouteHop>,
}
+impl Writeable for Route {
+ fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+ (self.hops.len() as u8).write(writer)?;
+ for hop in self.hops.iter() {
+ hop.pubkey.write(writer)?;
+ hop.short_channel_id.write(writer)?;
+ hop.fee_msat.write(writer)?;
+ hop.cltv_expiry_delta.write(writer)?;
+ }
+ Ok(())
+ }
+}
+
+impl<R: ::std::io::Read> Readable<R> for Route {
+ fn read(reader: &mut R) -> Result<Route, DecodeError> {
+ let hops_count: u8 = Readable::read(reader)?;
+ let mut hops = Vec::with_capacity(hops_count as usize);
+ for _ in 0..hops_count {
+ hops.push(RouteHop {
+ pubkey: Readable::read(reader)?,
+ short_channel_id: Readable::read(reader)?,
+ fee_msat: Readable::read(reader)?,
+ cltv_expiry_delta: Readable::read(reader)?,
+ });
+ }
+ Ok(Route {
+ hops
+ })
+ }
+}
+
struct DirectionalChannelInfo {
src_node_id: PublicKey,
last_update: u32,
/// A channel descriptor which provides a last-hop route to get_route
pub struct RouteHint {
+ /// The node_id of the non-target end of the route
pub src_node_id: PublicKey,
+ /// The short_channel_id of this channel
pub short_channel_id: u64,
+ /// The static msat-denominated fee which must be paid to use this channel
pub fee_base_msat: u32,
+ /// The dynamic proportional fee which must be paid to use this channel, denominated in
+ /// millionths of the value being forwarded to the next hop.
pub fee_proportional_millionths: u32,
+ /// The difference in CLTV values between this node and the next node.
pub cltv_expiry_delta: u16,
+ /// The minimum value, in msat, which must be relayed to the next hop.
pub htlc_minimum_msat: u64,
}
&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => {
let _ = self.handle_channel_update(msg);
},
- &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id } => {
+ &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => {
let mut network = self.network_map.write().unwrap();
- if let Some(chan) = network.channels.remove(short_channel_id) {
- Self::remove_channel_in_nodes(&mut network.nodes, &chan, *short_channel_id);
+ if *is_permanent {
+ if let Some(chan) = network.channels.remove(short_channel_id) {
+ Self::remove_channel_in_nodes(&mut network.nodes, &chan, *short_channel_id);
+ }
+ } else {
+ if let Some(chan) = network.channels.get_mut(short_channel_id) {
+ chan.one_to_two.enabled = false;
+ chan.two_to_one.enabled = false;
+ }
+ }
+ },
+ &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => {
+ if *is_permanent {
+ //TODO: Wholly remove the node
+ } else {
+ self.mark_node_bad(node_id, false);
}
},
}
}
impl Router {
+ /// Creates a new router with the given node_id to be used as the source for get_route()
pub fn new(our_pubkey: PublicKey, chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>) -> Router {
let mut nodes = HashMap::new();
nodes.insert(our_pubkey.clone(), NodeInfo {
}
/// Gets a route from us to the given target node.
+ ///
/// Extra routing hops between known nodes and the target will be used if they are included in
/// last_hops.
+ ///
/// If some channels aren't announced, it may be useful to fill in a first_hops with the
/// results from a local ChannelManager::list_usable_channels() call. If it is filled in, our
/// (this Router's) view of our local channels will be ignored, and only those in first_hops
- /// will be used. Panics if first_hops contains channels without short_channel_ids
+ /// will be used.
+ ///
+ /// Panics if first_hops contains channels without short_channel_ids
/// (ChannelManager::list_usable_channels will never include such channels).
+ ///
/// The fees on channels from us to next-hops are ignored (as they are assumed to all be
/// equal), however the enabled/disabled bit on such channels as well as the htlc_minimum_msat
/// *is* checked as they may change based on the receiving node.