Move initial_routing_sync decision to the Router
[rust-lightning] / lightning / src / ln / router.rs
index bb20c31c35af9f868ee76c91933558b173130dc4..1791bb6f5712979c2386ecfe89ca9fa2afd1c7c2 100644 (file)
@@ -14,13 +14,15 @@ use bitcoin::blockdata::opcodes;
 
 use chain::chaininterface::{ChainError, ChainWatchInterface};
 use ln::channelmanager;
-use ln::msgs::{DecodeError,ErrorAction,HandleError,RoutingMessageHandler,NetAddress,GlobalFeatures};
+use ln::features::{ChannelFeatures, NodeFeatures};
+use ln::msgs::{DecodeError,ErrorAction,LightningError,RoutingMessageHandler,NetAddress};
 use ln::msgs;
 use util::ser::{Writeable, Readable, Writer, ReadableArgs};
 use util::logger::Logger;
 
 use std::cmp;
 use std::sync::{RwLock,Arc};
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::collections::{HashMap,BinaryHeap,BTreeMap};
 use std::collections::btree_map::Entry as BtreeEntry;
 use std;
@@ -30,8 +32,14 @@ use std;
 pub struct RouteHop {
        /// The node_id of the node at this hop.
        pub pubkey: PublicKey,
+       /// The node_announcement features of the node at this hop. For the last hop, these may be
+       /// amended to match the features present in the invoice this node generated.
+       pub node_features: NodeFeatures,
        /// The channel that should be used from the previous hop to reach this node.
        pub short_channel_id: u64,
+       /// The channel_announcement features of the channel that should be used from the previous hop
+       /// to reach this node.
+       pub channel_features: ChannelFeatures,
        /// The fee taken on this hop. For the last hop, this should be the full value of the payment.
        pub fee_msat: u64,
        /// The CLTV delta added for this hop. For the last hop, this should be the full CLTV value
@@ -53,7 +61,9 @@ impl Writeable for Route {
                (self.hops.len() as u8).write(writer)?;
                for hop in self.hops.iter() {
                        hop.pubkey.write(writer)?;
+                       hop.node_features.write(writer)?;
                        hop.short_channel_id.write(writer)?;
+                       hop.channel_features.write(writer)?;
                        hop.fee_msat.write(writer)?;
                        hop.cltv_expiry_delta.write(writer)?;
                }
@@ -68,7 +78,9 @@ impl<R: ::std::io::Read> Readable<R> for Route {
                for _ in 0..hops_count {
                        hops.push(RouteHop {
                                pubkey: Readable::read(reader)?,
+                               node_features: Readable::read(reader)?,
                                short_channel_id: Readable::read(reader)?,
+                               channel_features: Readable::read(reader)?,
                                fee_msat: Readable::read(reader)?,
                                cltv_expiry_delta: Readable::read(reader)?,
                        });
@@ -111,7 +123,7 @@ impl_writeable!(DirectionalChannelInfo, 0, {
 
 #[derive(PartialEq)]
 struct ChannelInfo {
-       features: GlobalFeatures,
+       features: ChannelFeatures,
        one_to_two: DirectionalChannelInfo,
        two_to_one: DirectionalChannelInfo,
        //this is cached here so we can send out it later if required by route_init_sync
@@ -143,7 +155,7 @@ struct NodeInfo {
        lowest_inbound_channel_fee_base_msat: u32,
        lowest_inbound_channel_fee_proportional_millionths: u32,
 
-       features: GlobalFeatures,
+       features: NodeFeatures,
        last_update: u32,
        rgb: [u8; 3],
        alias: [u8; 32],
@@ -274,21 +286,6 @@ impl<R: ::std::io::Read> Readable<R> for NetworkMap {
        }
 }
 
-struct MutNetworkMap<'a> {
-       #[cfg(feature = "non_bitcoin_chain_hash_routing")]
-       channels: &'a mut BTreeMap<(u64, Sha256dHash), ChannelInfo>,
-       #[cfg(not(feature = "non_bitcoin_chain_hash_routing"))]
-       channels: &'a mut BTreeMap<u64, ChannelInfo>,
-       nodes: &'a mut BTreeMap<PublicKey, NodeInfo>,
-}
-impl NetworkMap {
-       fn borrow_parts(&mut self) -> MutNetworkMap {
-               MutNetworkMap {
-                       channels: &mut self.channels,
-                       nodes: &mut self.nodes,
-               }
-       }
-}
 impl std::fmt::Display for NetworkMap {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                write!(f, "Node id {} network map\n[Channels]\n", log_pubkey!(self.our_node_id))?;
@@ -351,6 +348,7 @@ pub struct RouteHint {
 pub struct Router {
        secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
        network_map: RwLock<NetworkMap>,
+       full_syncs_requested: AtomicUsize,
        chain_monitor: Arc<ChainWatchInterface>,
        logger: Arc<Logger>,
 }
@@ -394,6 +392,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, RouterReadArgs> for Router {
                Ok(Router {
                        secp_ctx: Secp256k1::verification_only(),
                        network_map: RwLock::new(network_map),
+                       full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor: args.chain_monitor,
                        logger: args.logger,
                })
@@ -404,26 +403,23 @@ macro_rules! secp_verify_sig {
        ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => {
                match $secp_ctx.verify($msg, $sig, $pubkey) {
                        Ok(_) => {},
-                       Err(_) => return Err(HandleError{err: "Invalid signature from remote node", action: None}),
+                       Err(_) => return Err(LightningError{err: "Invalid signature from remote node", action: ErrorAction::IgnoreError}),
                }
        };
 }
 
 impl RoutingMessageHandler for Router {
-       fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, HandleError> {
+
+       fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, LightningError> {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
                secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id);
 
-               if msg.contents.features.requires_unknown_bits() {
-                       panic!("Unknown-required-features NodeAnnouncements should never deserialize!");
-               }
-
                let mut network = self.network_map.write().unwrap();
                match network.nodes.get_mut(&msg.contents.node_id) {
-                       None => Err(HandleError{err: "No existing channels for node_announcement", action: Some(ErrorAction::IgnoreError)}),
+                       None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}),
                        Some(node) => {
                                if node.last_update >= msg.contents.timestamp {
-                                       return Err(HandleError{err: "Update older than last processed update", action: Some(ErrorAction::IgnoreError)});
+                                       return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
                                }
 
                                node.features = msg.contents.features.clone();
@@ -432,16 +428,16 @@ impl RoutingMessageHandler for Router {
                                node.alias = msg.contents.alias;
                                node.addresses = msg.contents.addresses.clone();
 
-                               let should_relay = msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty() && !msg.contents.features.supports_unknown_bits();
+                               let should_relay = msg.contents.excess_data.is_empty() && msg.contents.excess_address_data.is_empty();
                                node.announcement_message = if should_relay { Some(msg.clone()) } else { None };
                                Ok(should_relay)
                        }
                }
        }
 
-       fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, HandleError> {
+       fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, LightningError> {
                if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 {
-                       return Err(HandleError{err: "Channel announcement node had a channel with itself", action: Some(ErrorAction::IgnoreError)});
+                       return Err(LightningError{err: "Channel announcement node had a channel with itself", action: ErrorAction::IgnoreError});
                }
 
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
@@ -450,10 +446,6 @@ impl RoutingMessageHandler for Router {
                secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1);
                secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2);
 
-               if msg.contents.features.requires_unknown_bits() {
-                       panic!("Unknown-required-features ChannelAnnouncements should never deserialize!");
-               }
-
                let checked_utxo = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
                        Ok((script_pubkey, _value)) => {
                                let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2)
@@ -462,7 +454,7 @@ impl RoutingMessageHandler for Router {
                                                                    .push_opcode(opcodes::all::OP_PUSHNUM_2)
                                                                    .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
                                if script_pubkey != expected_script {
-                                       return Err(HandleError{err: "Channel announcement keys didn't match on-chain script", action: Some(ErrorAction::IgnoreError)});
+                                       return Err(LightningError{err: "Channel announcement keys didn't match on-chain script", action: ErrorAction::IgnoreError});
                                }
                                //TODO: Check if value is worth storing, use it to inform routing, and compare it
                                //to the new HTLC max field in channel_update
@@ -473,17 +465,17 @@ impl RoutingMessageHandler for Router {
                                false
                        },
                        Err(ChainError::NotWatched) => {
-                               return Err(HandleError{err: "Channel announced on an unknown chain", action: Some(ErrorAction::IgnoreError)});
+                               return Err(LightningError{err: "Channel announced on an unknown chain", action: ErrorAction::IgnoreError});
                        },
                        Err(ChainError::UnknownTx) => {
-                               return Err(HandleError{err: "Channel announced without corresponding UTXO entry", action: Some(ErrorAction::IgnoreError)});
+                               return Err(LightningError{err: "Channel announced without corresponding UTXO entry", action: ErrorAction::IgnoreError});
                        },
                };
 
                let mut network_lock = self.network_map.write().unwrap();
-               let network = network_lock.borrow_parts();
+               let network = &mut *network_lock;
 
-               let should_relay = msg.contents.excess_data.is_empty() && !msg.contents.features.supports_unknown_bits();
+               let should_relay = msg.contents.excess_data.is_empty();
 
                let chan_info = ChannelInfo {
                                features: msg.contents.features.clone(),
@@ -524,10 +516,10 @@ impl RoutingMessageHandler for Router {
                                        // b) we don't track UTXOs of channels we know about and remove them if they
                                        //    get reorg'd out.
                                        // c) it's unclear how to do so without exposing ourselves to massive DoS risk.
-                                       Self::remove_channel_in_nodes(network.nodes, &entry.get(), msg.contents.short_channel_id);
+                                       Self::remove_channel_in_nodes(&mut network.nodes, &entry.get(), msg.contents.short_channel_id);
                                        *entry.get_mut() = chan_info;
                                } else {
-                                       return Err(HandleError{err: "Already have knowledge of channel", action: Some(ErrorAction::IgnoreError)})
+                                       return Err(LightningError{err: "Already have knowledge of channel", action: ErrorAction::IgnoreError})
                                }
                        },
                        BtreeEntry::Vacant(entry) => {
@@ -546,7 +538,7 @@ impl RoutingMessageHandler for Router {
                                                        channels: vec!(NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)),
                                                        lowest_inbound_channel_fee_base_msat: u32::max_value(),
                                                        lowest_inbound_channel_fee_proportional_millionths: u32::max_value(),
-                                                       features: GlobalFeatures::new(),
+                                                       features: NodeFeatures::empty(),
                                                        last_update: 0,
                                                        rgb: [0; 3],
                                                        alias: [0; 32],
@@ -592,19 +584,19 @@ impl RoutingMessageHandler for Router {
                }
        }
 
-       fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<bool, HandleError> {
+       fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<bool, LightningError> {
                let mut network = self.network_map.write().unwrap();
                let dest_node_id;
                let chan_enabled = msg.contents.flags & (1 << 1) != (1 << 1);
                let chan_was_enabled;
 
                match network.channels.get_mut(&NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)) {
-                       None => return Err(HandleError{err: "Couldn't find channel for update", action: Some(ErrorAction::IgnoreError)}),
+                       None => return Err(LightningError{err: "Couldn't find channel for update", action: ErrorAction::IgnoreError}),
                        Some(channel) => {
                                macro_rules! maybe_update_channel_info {
                                        ( $target: expr) => {
                                                if $target.last_update >= msg.contents.timestamp {
-                                                       return Err(HandleError{err: "Update older than last processed update", action: Some(ErrorAction::IgnoreError)});
+                                                       return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
                                                }
                                                chan_was_enabled = $target.enabled;
                                                $target.last_update = msg.contents.timestamp;
@@ -710,6 +702,17 @@ impl RoutingMessageHandler for Router {
                }
                result
        }
+
+       fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool {
+               //TODO: Determine whether to request a full sync based on the network map.
+               const FULL_SYNCS_TO_REQUEST: usize = 5;
+               if self.full_syncs_requested.load(Ordering::Acquire) < FULL_SYNCS_TO_REQUEST {
+                       self.full_syncs_requested.fetch_add(1, Ordering::AcqRel);
+                       true
+               } else {
+                       false
+               }
+       }
 }
 
 #[derive(Eq, PartialEq)]
@@ -748,7 +751,7 @@ impl Router {
                        channels: Vec::new(),
                        lowest_inbound_channel_fee_base_msat: u32::max_value(),
                        lowest_inbound_channel_fee_proportional_millionths: u32::max_value(),
-                       features: GlobalFeatures::new(),
+                       features: NodeFeatures::empty(),
                        last_update: 0,
                        rgb: [0; 3],
                        alias: [0; 32],
@@ -762,6 +765,7 @@ impl Router {
                                our_node_id: our_pubkey,
                                nodes: nodes,
                        }),
+                       full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor,
                        logger,
                }
@@ -824,17 +828,17 @@ impl Router {
        /// 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.
-       pub fn get_route(&self, target: &PublicKey, first_hops: Option<&[channelmanager::ChannelDetails]>, last_hops: &[RouteHint], final_value_msat: u64, final_cltv: u32) -> Result<Route, HandleError> {
+       pub fn get_route(&self, target: &PublicKey, first_hops: Option<&[channelmanager::ChannelDetails]>, last_hops: &[RouteHint], final_value_msat: u64, final_cltv: u32) -> Result<Route, LightningError> {
                // TODO: Obviously *only* using total fee cost sucks. We should consider weighting by
                // uptime/success in using a node in the past.
                let network = self.network_map.read().unwrap();
 
                if *target == network.our_node_id {
-                       return Err(HandleError{err: "Cannot generate a route to ourselves", action: None});
+                       return Err(LightningError{err: "Cannot generate a route to ourselves", action: ErrorAction::IgnoreError});
                }
 
                if final_value_msat > 21_000_000 * 1_0000_0000 * 1000 {
-                       return Err(HandleError{err: "Cannot generate a route of more value than all existing satoshis", action: None});
+                       return Err(LightningError{err: "Cannot generate a route of more value than all existing satoshis", action: ErrorAction::IgnoreError});
                }
 
                // We do a dest-to-source Dijkstra's sorting by each node's distance from the destination
@@ -862,16 +866,18 @@ impl Router {
                                        return Ok(Route {
                                                hops: vec![RouteHop {
                                                        pubkey: chan.remote_network_id,
+                                                       node_features: NodeFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
                                                        short_channel_id,
+                                                       channel_features: ChannelFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
                                                        fee_msat: final_value_msat,
                                                        cltv_expiry_delta: final_cltv,
                                                }],
                                        });
                                }
-                               first_hop_targets.insert(chan.remote_network_id, short_channel_id);
+                               first_hop_targets.insert(chan.remote_network_id, (short_channel_id, chan.counterparty_features.clone()));
                        }
                        if first_hop_targets.is_empty() {
-                               return Err(HandleError{err: "Cannot route when there are no outbound routes away from us", action: None});
+                               return Err(LightningError{err: "Cannot route when there are no outbound routes away from us", action: ErrorAction::IgnoreError});
                        }
                }
 
@@ -879,7 +885,7 @@ impl Router {
                        // Adds entry which goes from the node pointed to by $directional_info to
                        // $dest_node_id over the channel with id $chan_id with fees described in
                        // $directional_info.
-                       ( $chan_id: expr, $dest_node_id: expr, $directional_info: expr, $starting_fee_msat: expr ) => {
+                       ( $chan_id: expr, $dest_node_id: expr, $directional_info: expr, $chan_features: expr, $starting_fee_msat: expr ) => {
                                //TODO: Explore simply adding fee to hit htlc_minimum_msat
                                if $starting_fee_msat as u64 + final_value_msat >= $directional_info.htlc_minimum_msat {
                                        let proportional_fee_millions = ($starting_fee_msat + final_value_msat).checked_mul($directional_info.fee_proportional_millionths as u64);
@@ -895,7 +901,9 @@ impl Router {
                                                                node.lowest_inbound_channel_fee_proportional_millionths,
                                                                RouteHop {
                                                                        pubkey: $dest_node_id.clone(),
+                                                                       node_features: NodeFeatures::empty(),
                                                                        short_channel_id: 0,
+                                                                       channel_features: $chan_features.clone(),
                                                                        fee_msat: 0,
                                                                        cltv_expiry_delta: 0,
                                                        })
@@ -921,7 +929,9 @@ impl Router {
                                                        old_entry.0 = total_fee;
                                                        old_entry.3 = RouteHop {
                                                                pubkey: $dest_node_id.clone(),
+                                                               node_features: NodeFeatures::empty(),
                                                                short_channel_id: $chan_id.clone(),
+                                                               channel_features: $chan_features.clone(),
                                                                fee_msat: new_fee, // This field is ignored on the last-hop anyway
                                                                cltv_expiry_delta: $directional_info.cltv_expiry_delta as u32,
                                                        }
@@ -934,24 +944,28 @@ impl Router {
                macro_rules! add_entries_to_cheapest_to_target_node {
                        ( $node: expr, $node_id: expr, $fee_to_target_msat: expr ) => {
                                if first_hops.is_some() {
-                                       if let Some(first_hop) = first_hop_targets.get(&$node_id) {
-                                               add_entry!(first_hop, $node_id, dummy_directional_info, $fee_to_target_msat);
+                                       if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&$node_id) {
+                                               add_entry!(first_hop, $node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), $fee_to_target_msat);
                                        }
                                }
 
-                               for chan_id in $node.channels.iter() {
-                                       let chan = network.channels.get(chan_id).unwrap();
-                                       if chan.one_to_two.src_node_id == *$node_id {
-                                               // ie $node is one, ie next hop in A* is two, via the two_to_one channel
-                                               if first_hops.is_none() || chan.two_to_one.src_node_id != network.our_node_id {
-                                                       if chan.two_to_one.enabled {
-                                                               add_entry!(chan_id, chan.one_to_two.src_node_id, chan.two_to_one, $fee_to_target_msat);
-                                                       }
-                                               }
-                                       } else {
-                                               if first_hops.is_none() || chan.one_to_two.src_node_id != network.our_node_id {
-                                                       if chan.one_to_two.enabled {
-                                                               add_entry!(chan_id, chan.two_to_one.src_node_id, chan.one_to_two, $fee_to_target_msat);
+                               if !$node.features.requires_unknown_bits() {
+                                       for chan_id in $node.channels.iter() {
+                                               let chan = network.channels.get(chan_id).unwrap();
+                                               if !chan.features.requires_unknown_bits() {
+                                                       if chan.one_to_two.src_node_id == *$node_id {
+                                                               // ie $node is one, ie next hop in A* is two, via the two_to_one channel
+                                                               if first_hops.is_none() || chan.two_to_one.src_node_id != network.our_node_id {
+                                                                       if chan.two_to_one.enabled {
+                                                                               add_entry!(chan_id, chan.one_to_two.src_node_id, chan.two_to_one, chan.features, $fee_to_target_msat);
+                                                                       }
+                                                               }
+                                                       } else {
+                                                               if first_hops.is_none() || chan.one_to_two.src_node_id != network.our_node_id {
+                                                                       if chan.one_to_two.enabled {
+                                                                               add_entry!(chan_id, chan.two_to_one.src_node_id, chan.one_to_two, chan.features, $fee_to_target_msat);
+                                                                       }
+                                                               }
                                                        }
                                                }
                                        }
@@ -970,11 +984,17 @@ impl Router {
                        if first_hops.is_none() || hop.src_node_id != network.our_node_id { // first_hop overrules last_hops
                                if network.nodes.get(&hop.src_node_id).is_some() {
                                        if first_hops.is_some() {
-                                               if let Some(first_hop) = first_hop_targets.get(&hop.src_node_id) {
-                                                       add_entry!(first_hop, hop.src_node_id, dummy_directional_info, 0);
+                                               if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&hop.src_node_id) {
+                                                       // Currently there are no channel-context features defined, so we are a
+                                                       // bit lazy here. In the future, we should pull them out via our
+                                                       // ChannelManager, but there's no reason to waste the space until we
+                                                       // need them.
+                                                       add_entry!(first_hop, hop.src_node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), 0);
                                                }
                                        }
-                                       add_entry!(hop.short_channel_id, target, hop, 0);
+                                       // BOLT 11 doesn't allow inclusion of features for the last hop hints, which
+                                       // really sucks, cause we're gonna need that eventually.
+                                       add_entry!(hop.short_channel_id, target, hop, ChannelFeatures::empty(), 0);
                                }
                        }
                }
@@ -982,10 +1002,25 @@ impl Router {
                while let Some(RouteGraphNode { pubkey, lowest_fee_to_node, .. }) = targets.pop() {
                        if pubkey == network.our_node_id {
                                let mut res = vec!(dist.remove(&network.our_node_id).unwrap().3);
-                               while res.last().unwrap().pubkey != *target {
+                               loop {
+                                       if let Some(&(_, ref features)) = first_hop_targets.get(&res.last().unwrap().pubkey) {
+                                               res.last_mut().unwrap().node_features = NodeFeatures::with_known_relevant_init_flags(&features);
+                                       } else if let Some(node) = network.nodes.get(&res.last().unwrap().pubkey) {
+                                               res.last_mut().unwrap().node_features = node.features.clone();
+                                       } else {
+                                               // We should be able to fill in features for everything except the last
+                                               // hop, if the last hop was provided via a BOLT 11 invoice (though we
+                                               // should be able to extend it further as BOLT 11 does have feature
+                                               // flags for the last hop node itself).
+                                               assert!(res.last().unwrap().pubkey == *target);
+                                       }
+                                       if res.last().unwrap().pubkey == *target {
+                                               break;
+                                       }
+
                                        let new_entry = match dist.remove(&res.last().unwrap().pubkey) {
                                                Some(hop) => hop.3,
-                                               None => return Err(HandleError{err: "Failed to find a non-fee-overflowing path to the given destination", action: None}),
+                                               None => return Err(LightningError{err: "Failed to find a non-fee-overflowing path to the given destination", action: ErrorAction::IgnoreError}),
                                        };
                                        res.last_mut().unwrap().fee_msat = new_entry.fee_msat;
                                        res.last_mut().unwrap().cltv_expiry_delta = new_entry.cltv_expiry_delta;
@@ -1006,7 +1041,7 @@ impl Router {
                        }
                }
 
-               Err(HandleError{err: "Failed to find a path to the given destination", action: None})
+               Err(LightningError{err: "Failed to find a path to the given destination", action: ErrorAction::IgnoreError})
        }
 }
 
@@ -1015,7 +1050,8 @@ mod tests {
        use chain::chaininterface;
        use ln::channelmanager;
        use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint};
-       use ln::msgs::GlobalFeatures;
+       use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
+       use ln::msgs::{LightningError, ErrorAction};
        use util::test_utils;
        use util::test_utils::TestVecWriter;
        use util::logger::Logger;
@@ -1108,6 +1144,23 @@ mod tests {
 
                let zero_hash = Sha256dHash::hash(&[0; 32]);
 
+               macro_rules! id_to_feature_flags {
+                       // Set the feature flags to the id'th odd (ie non-required) feature bit so that we can
+                       // test for it later.
+                       ($id: expr) => { {
+                               let idx = ($id - 1) * 2 + 1;
+                               if idx > 8*3 {
+                                       vec![1 << (idx - 8*3), 0, 0, 0]
+                               } else if idx > 8*2 {
+                                       vec![1 << (idx - 8*2), 0, 0]
+                               } else if idx > 8*1 {
+                                       vec![1 << (idx - 8*1), 0]
+                               } else {
+                                       vec![1 << idx]
+                               }
+                       } }
+               }
+
                {
                        let mut network = router.network_map.write().unwrap();
 
@@ -1115,7 +1168,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(1, zero_hash.clone()), NetworkMap::get_key(3, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 100,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(1)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1123,7 +1176,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(1, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(1)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: our_id.clone(),
                                        last_update: 0,
@@ -1149,7 +1202,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(2, zero_hash.clone()), NetworkMap::get_key(4, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(2)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1157,7 +1210,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(2, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(2)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: our_id.clone(),
                                        last_update: 0,
@@ -1183,7 +1236,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(12, zero_hash.clone()), NetworkMap::get_key(13, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(8)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1191,7 +1244,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(12, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(12)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: our_id.clone(),
                                        last_update: 0,
@@ -1223,7 +1276,7 @@ mod tests {
                                        NetworkMap::get_key(7, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(3)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1231,7 +1284,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(3, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(3)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node1.clone(),
                                        last_update: 0,
@@ -1254,7 +1307,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(4, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(4)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node2.clone(),
                                        last_update: 0,
@@ -1277,7 +1330,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(13, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(13)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node8.clone(),
                                        last_update: 0,
@@ -1303,7 +1356,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(5, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(4)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1311,7 +1364,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(5, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(5)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node3.clone(),
                                        last_update: 0,
@@ -1337,7 +1390,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(6, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(5)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1345,7 +1398,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(6, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(6)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node3.clone(),
                                        last_update: 0,
@@ -1368,7 +1421,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(11, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(11)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node5.clone(),
                                        last_update: 0,
@@ -1394,7 +1447,7 @@ mod tests {
                                channels: vec!(NetworkMap::get_key(7, zero_hash.clone())),
                                lowest_inbound_channel_fee_base_msat: 0,
                                lowest_inbound_channel_fee_proportional_millionths: 0,
-                               features: GlobalFeatures::new(),
+                               features: NodeFeatures::from_le_bytes(id_to_feature_flags!(6)),
                                last_update: 1,
                                rgb: [0; 3],
                                alias: [0; 32],
@@ -1402,7 +1455,7 @@ mod tests {
                                announcement_message: None,
                        });
                        network.channels.insert(NetworkMap::get_key(7, zero_hash.clone()), ChannelInfo {
-                               features: GlobalFeatures::new(),
+                               features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(7)),
                                one_to_two: DirectionalChannelInfo {
                                        src_node_id: node3.clone(),
                                        last_update: 0,
@@ -1434,13 +1487,119 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 2);
                        assert_eq!(route.hops[0].fee_msat, 100);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 4);
                        assert_eq!(route.hops[1].fee_msat, 100);
                        assert_eq!(route.hops[1].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
+               }
+
+               { // Disable channels 4 and 12 by requiring unknown feature bits
+                       let mut network = router.network_map.write().unwrap();
+                       network.channels.get_mut(&NetworkMap::get_key(4, zero_hash.clone())).unwrap().features.set_require_unknown_bits();
+                       network.channels.get_mut(&NetworkMap::get_key(12, zero_hash.clone())).unwrap().features.set_require_unknown_bits();
+               }
+
+               { // If all the channels require some features we don't understand, route should fail
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = router.get_route(&node3, None, &Vec::new(), 100, 42) {
+                               assert_eq!(err, "Failed to find a path to the given destination");
+                       } else { panic!(); }
                }
 
+               { // If we specify a channel to node8, that overrides our local channel view and that gets used
+                       let our_chans = vec![channelmanager::ChannelDetails {
+                               channel_id: [0; 32],
+                               short_channel_id: Some(42),
+                               remote_network_id: node8.clone(),
+                               counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
+                               channel_value_satoshis: 0,
+                               user_id: 0,
+                               outbound_capacity_msat: 0,
+                               inbound_capacity_msat: 0,
+                               is_live: true,
+                       }];
+                       let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap();
+                       assert_eq!(route.hops.len(), 2);
+
+                       assert_eq!(route.hops[0].pubkey, node8);
+                       assert_eq!(route.hops[0].short_channel_id, 42);
+                       assert_eq!(route.hops[0].fee_msat, 200);
+                       assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
+
+                       assert_eq!(route.hops[1].pubkey, node3);
+                       assert_eq!(route.hops[1].short_channel_id, 13);
+                       assert_eq!(route.hops[1].fee_msat, 100);
+                       assert_eq!(route.hops[1].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
+               }
+
+               { // Re-enable channels 4 and 12 by wiping the unknown feature bits
+                       let mut network = router.network_map.write().unwrap();
+                       network.channels.get_mut(&NetworkMap::get_key(4, zero_hash.clone())).unwrap().features.clear_require_unknown_bits();
+                       network.channels.get_mut(&NetworkMap::get_key(12, zero_hash.clone())).unwrap().features.clear_require_unknown_bits();
+               }
+
+               { // Disable nodes 1, 2, and 8 by requiring unknown feature bits
+                       let mut network = router.network_map.write().unwrap();
+                       network.nodes.get_mut(&node1).unwrap().features.set_require_unknown_bits();
+                       network.nodes.get_mut(&node2).unwrap().features.set_require_unknown_bits();
+                       network.nodes.get_mut(&node8).unwrap().features.set_require_unknown_bits();
+               }
+
+               { // If all nodes require some features we don't understand, route should fail
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = router.get_route(&node3, None, &Vec::new(), 100, 42) {
+                               assert_eq!(err, "Failed to find a path to the given destination");
+                       } else { panic!(); }
+               }
+
+               { // If we specify a channel to node8, that overrides our local channel view and that gets used
+                       let our_chans = vec![channelmanager::ChannelDetails {
+                               channel_id: [0; 32],
+                               short_channel_id: Some(42),
+                               remote_network_id: node8.clone(),
+                               counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
+                               channel_value_satoshis: 0,
+                               user_id: 0,
+                               outbound_capacity_msat: 0,
+                               inbound_capacity_msat: 0,
+                               is_live: true,
+                       }];
+                       let route = router.get_route(&node3, Some(&our_chans), &Vec::new(), 100, 42).unwrap();
+                       assert_eq!(route.hops.len(), 2);
+
+                       assert_eq!(route.hops[0].pubkey, node8);
+                       assert_eq!(route.hops[0].short_channel_id, 42);
+                       assert_eq!(route.hops[0].fee_msat, 200);
+                       assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
+
+                       assert_eq!(route.hops[1].pubkey, node3);
+                       assert_eq!(route.hops[1].short_channel_id, 13);
+                       assert_eq!(route.hops[1].fee_msat, 100);
+                       assert_eq!(route.hops[1].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
+               }
+
+               { // Re-enable nodes 1, 2, and 8
+                       let mut network = router.network_map.write().unwrap();
+                       network.nodes.get_mut(&node1).unwrap().features.clear_require_unknown_bits();
+                       network.nodes.get_mut(&node2).unwrap().features.clear_require_unknown_bits();
+                       network.nodes.get_mut(&node8).unwrap().features.clear_require_unknown_bits();
+               }
+
+               // Note that we don't test disabling node 3 and failing to route to it, as we (somewhat
+               // naively) assume that the user checked the feature bits on the invoice, which override
+               // the node_announcement.
+
                { // Route to 1 via 2 and 3 because our channel to 1 is disabled
                        let route = router.get_route(&node1, None, &Vec::new(), 100, 42).unwrap();
                        assert_eq!(route.hops.len(), 3);
@@ -1449,16 +1608,22 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 2);
                        assert_eq!(route.hops[0].fee_msat, 200);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 4);
                        assert_eq!(route.hops[1].fee_msat, 100);
                        assert_eq!(route.hops[1].cltv_expiry_delta, (3 << 8) | 2);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
 
                        assert_eq!(route.hops[2].pubkey, node1);
                        assert_eq!(route.hops[2].short_channel_id, 3);
                        assert_eq!(route.hops[2].fee_msat, 100);
                        assert_eq!(route.hops[2].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(1));
+                       assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(3));
                }
 
                { // If we specify a channel to node8, that overrides our local channel view and that gets used
@@ -1466,6 +1631,7 @@ mod tests {
                                channel_id: [0; 32],
                                short_channel_id: Some(42),
                                remote_network_id: node8.clone(),
+                               counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
                                channel_value_satoshis: 0,
                                user_id: 0,
                                outbound_capacity_msat: 0,
@@ -1479,11 +1645,15 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 42);
                        assert_eq!(route.hops[0].fee_msat, 200);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]);
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 13);
                        assert_eq!(route.hops[1].fee_msat, 100);
                        assert_eq!(route.hops[1].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
                }
 
                let mut last_hops = vec!(RouteHint {
@@ -1517,26 +1687,38 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 2);
                        assert_eq!(route.hops[0].fee_msat, 100);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 4);
                        assert_eq!(route.hops[1].fee_msat, 0);
                        assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
 
                        assert_eq!(route.hops[2].pubkey, node5);
                        assert_eq!(route.hops[2].short_channel_id, 6);
                        assert_eq!(route.hops[2].fee_msat, 0);
                        assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1);
+                       assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5));
+                       assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6));
 
                        assert_eq!(route.hops[3].pubkey, node4);
                        assert_eq!(route.hops[3].short_channel_id, 11);
                        assert_eq!(route.hops[3].fee_msat, 0);
                        assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1);
+                       // If we have a peer in the node map, we'll use their features here since we don't have
+                       // a way of figuring out their features from the invoice:
+                       assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4));
+                       assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11));
 
                        assert_eq!(route.hops[4].pubkey, node7);
                        assert_eq!(route.hops[4].short_channel_id, 8);
                        assert_eq!(route.hops[4].fee_msat, 100);
                        assert_eq!(route.hops[4].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
+                       assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
                }
 
                { // Simple test with outbound channel to 4 to test that last_hops and first_hops connect
@@ -1544,6 +1726,7 @@ mod tests {
                                channel_id: [0; 32],
                                short_channel_id: Some(42),
                                remote_network_id: node4.clone(),
+                               counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
                                channel_value_satoshis: 0,
                                user_id: 0,
                                outbound_capacity_msat: 0,
@@ -1557,11 +1740,15 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 42);
                        assert_eq!(route.hops[0].fee_msat, 0);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (8 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]);
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
 
                        assert_eq!(route.hops[1].pubkey, node7);
                        assert_eq!(route.hops[1].short_channel_id, 8);
                        assert_eq!(route.hops[1].fee_msat, 100);
                        assert_eq!(route.hops[1].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
                }
 
                last_hops[0].fee_base_msat = 1000;
@@ -1574,21 +1761,31 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 2);
                        assert_eq!(route.hops[0].fee_msat, 200); // fee increased as its % of value transferred across node
                        assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 4);
                        assert_eq!(route.hops[1].fee_msat, 100);
                        assert_eq!(route.hops[1].cltv_expiry_delta, (7 << 8) | 1);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
 
                        assert_eq!(route.hops[2].pubkey, node6);
                        assert_eq!(route.hops[2].short_channel_id, 7);
                        assert_eq!(route.hops[2].fee_msat, 0);
                        assert_eq!(route.hops[2].cltv_expiry_delta, (10 << 8) | 1);
+                       // If we have a peer in the node map, we'll use their features here since we don't have
+                       // a way of figuring out their features from the invoice:
+                       assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(6));
+                       assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(7));
 
                        assert_eq!(route.hops[3].pubkey, node7);
                        assert_eq!(route.hops[3].short_channel_id, 10);
                        assert_eq!(route.hops[3].fee_msat, 100);
                        assert_eq!(route.hops[3].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[3].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
+                       assert_eq!(route.hops[3].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
                }
 
                { // ...but still use 8 for larger payments as 6 has a variable feerate
@@ -1599,26 +1796,38 @@ mod tests {
                        assert_eq!(route.hops[0].short_channel_id, 2);
                        assert_eq!(route.hops[0].fee_msat, 3000);
                        assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
+                       assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
+                       assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
 
                        assert_eq!(route.hops[1].pubkey, node3);
                        assert_eq!(route.hops[1].short_channel_id, 4);
                        assert_eq!(route.hops[1].fee_msat, 0);
                        assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1);
+                       assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
+                       assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
 
                        assert_eq!(route.hops[2].pubkey, node5);
                        assert_eq!(route.hops[2].short_channel_id, 6);
                        assert_eq!(route.hops[2].fee_msat, 0);
                        assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1);
+                       assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5));
+                       assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6));
 
                        assert_eq!(route.hops[3].pubkey, node4);
                        assert_eq!(route.hops[3].short_channel_id, 11);
                        assert_eq!(route.hops[3].fee_msat, 1000);
                        assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1);
+                       // If we have a peer in the node map, we'll use their features here since we don't have
+                       // a way of figuring out their features from the invoice:
+                       assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4));
+                       assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11));
 
                        assert_eq!(route.hops[4].pubkey, node7);
                        assert_eq!(route.hops[4].short_channel_id, 8);
                        assert_eq!(route.hops[4].fee_msat, 2000);
                        assert_eq!(route.hops[4].cltv_expiry_delta, 42);
+                       assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
+                       assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
                }
 
                { // Test Router serialization/deserialization