Skip to content

Add some helpers for routing debug #566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 90 additions & 15 deletions lightning/src/ln/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,22 @@ impl Readable for Route {
}
}

#[derive(PartialEq)]
struct DirectionalChannelInfo {
/// Details of channel routing parameters for one-direction, as stored in ChannelInfo
#[derive(Clone, PartialEq)]
pub struct DirectionalChannelInfo {
/// node_id
src_node_id: PublicKey,
/// last update on channel state sent by node_id
last_update: u32,
/// channel readiness as assess by node_id
enabled: bool,
/// CLTV delta added by node_id for an outgoing HTLC
cltv_expiry_delta: u16,
/// Minimum outgoing HLTC value
htlc_minimum_msat: u64,
/// Minimum fee payed on outgoing HTLC
fee_base_msat: u32,
/// Proportional fee payed on outgoing HTLC
fee_proportional_millionths: u32,
last_update_message: Option<msgs::ChannelUpdate>,
}
Expand All @@ -121,32 +129,42 @@ impl_writeable!(DirectionalChannelInfo, 0, {
last_update_message
});

#[derive(PartialEq)]
struct ChannelInfo {
features: ChannelFeatures,
one_to_two: DirectionalChannelInfo,
two_to_one: DirectionalChannelInfo,
/// Details of a channel, as stored in NetworkMap and returned by Router::list_edges
#[derive(Clone, PartialEq)]
pub struct ChannelInfo {
/// The short_channel_id of this channel
pub short_channel_id: u64,
/// The channel features
pub features: ChannelFeatures,
/// Alice to Bob channel routing parameters
pub one_to_two: DirectionalChannelInfo,
/// Bob to Alice channel routing parameters
pub two_to_one: DirectionalChannelInfo,
//this is cached here so we can send out it later if required by route_init_sync
//keep an eye on this to see if the extra memory is a problem
announcement_message: Option<msgs::ChannelAnnouncement>,
}

impl std::fmt::Display for ChannelInfo {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "features: {}, one_to_two: {}, two_to_one: {}", log_bytes!(self.features.encode()), self.one_to_two, self.two_to_one)?;
write!(f, "short_channel_id: {}, features: {}, one_to_two: {}, two_to_one: {}", self.short_channel_id, log_bytes!(self.features.encode()), self.one_to_two, self.two_to_one)?;
Ok(())
}
}

impl_writeable!(ChannelInfo, 0, {
short_channel_id,
features,
one_to_two,
two_to_one,
announcement_message
});

#[derive(PartialEq)]
struct NodeInfo {
/// Details of a node, as stored in NetworkMap, and returned by Router::list_vertices
#[derive(Clone, PartialEq)]
pub struct NodeInfo {
/// The node id
pub node_id: PublicKey,
#[cfg(feature = "non_bitcoin_chain_hash_routing")]
channels: Vec<(u64, Sha256dHash)>,
#[cfg(not(feature = "non_bitcoin_chain_hash_routing"))]
Expand All @@ -155,14 +173,19 @@ struct NodeInfo {
lowest_inbound_channel_fee_base_msat: u32,
lowest_inbound_channel_fee_proportional_millionths: u32,

features: NodeFeatures,
/// The node features
pub features: NodeFeatures,
/// Unlike for channels, we may have a NodeInfo entry before having received a node_update.
/// Thus, we have to be able to capture "no update has been received", which we do with an
/// Option here.
last_update: Option<u32>,
rgb: [u8; 3],
alias: [u8; 32],
addresses: Vec<NetAddress>,
/// The last tine a node announcement has been received
pub last_update: Option<u32>,
/// The custom node color
pub rgb: [u8; 3],
/// The custom node alias
pub alias: [u8; 32],
/// The network addresses
pub addresses: Vec<NetAddress>,
//this is cached here so we can send out it later if required by route_init_sync
//keep an eye on this to see if the extra memory is a problem
announcement_message: Option<msgs::NodeAnnouncement>,
Expand Down Expand Up @@ -201,6 +224,7 @@ const MAX_ALLOC_SIZE: u64 = 64*1024;
impl Readable for NodeInfo {
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<NodeInfo, DecodeError> {
let channels_count: u64 = Readable::read(reader)?;
let node_id = Readable::read(reader)?;
let mut channels = Vec::with_capacity(cmp::min(channels_count, MAX_ALLOC_SIZE / 8) as usize);
for _ in 0..channels_count {
channels.push(Readable::read(reader)?);
Expand All @@ -223,6 +247,7 @@ impl Readable for NodeInfo {
}
let announcement_message = Readable::read(reader)?;
Ok(NodeInfo {
node_id,
channels,
lowest_inbound_channel_fee_base_msat,
lowest_inbound_channel_fee_proportional_millionths,
Expand Down Expand Up @@ -427,6 +452,7 @@ impl RoutingMessageHandler for Router {
},
None => {},
}
log_trace!(self, "Announced node {}", msg.contents.node_id);

node.features = msg.contents.features.clone();
node.last_update = Some(msg.contents.timestamp);
Expand Down Expand Up @@ -484,6 +510,7 @@ impl RoutingMessageHandler for Router {
let should_relay = msg.contents.excess_data.is_empty();

let chan_info = ChannelInfo {
short_channel_id: msg.contents.short_channel_id,
features: msg.contents.features.clone(),
one_to_two: DirectionalChannelInfo {
src_node_id: msg.contents.node_id_1.clone(),
Expand Down Expand Up @@ -541,6 +568,7 @@ impl RoutingMessageHandler for Router {
},
BtreeEntry::Vacant(node_entry) => {
node_entry.insert(NodeInfo {
node_id: $node_id,
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(),
Expand All @@ -555,6 +583,7 @@ impl RoutingMessageHandler for Router {
}
};
}
log_trace!(self, "Announced channel {} between {} and {}", msg.contents.short_channel_id, msg.contents.node_id_1, msg.contents.node_id_2);

add_channel_to_node!(msg.contents.node_id_1);
add_channel_to_node!(msg.contents.node_id_2);
Expand Down Expand Up @@ -754,6 +783,7 @@ impl Router {
pub fn new(our_pubkey: PublicKey, chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>) -> Router {
let mut nodes = BTreeMap::new();
nodes.insert(our_pubkey.clone(), NodeInfo {
node_id: our_pubkey.clone(),
channels: Vec::new(),
lowest_inbound_channel_fee_base_msat: u32::max_value(),
lowest_inbound_channel_fee_proportional_millionths: u32::max_value(),
Expand Down Expand Up @@ -868,6 +898,7 @@ impl Router {
if let Some(hops) = first_hops {
for chan in hops {
let short_channel_id = chan.short_channel_id.expect("first_hops should be filled in with usable channels, not pending ones");
log_trace!(self, "First hop link {} to {}", chan.short_channel_id.unwrap(), chan.remote_network_id);
if chan.remote_network_id == *target {
return Ok(Route {
hops: vec![RouteHop {
Expand Down Expand Up @@ -955,8 +986,11 @@ impl Router {
}
}

log_trace!(self, "Node {} requires {}", $node_id, $node.features.requires_unknown_bits());
if !$node.features.requires_unknown_bits() {
log_trace!(self, "Node {} with {} links", $node_id, $node.channels.len());
for chan_id in $node.channels.iter() {
log_trace!(self, "Adding link {}", chan_id);
let chan = network.channels.get(chan_id).unwrap();
if !chan.features.requires_unknown_bits() {
if chan.one_to_two.src_node_id == *$node_id {
Expand All @@ -979,6 +1013,7 @@ impl Router {
};
}

log_trace!(self, "Tracing route to {}...", target);
match network.nodes.get(target) {
None => {},
Some(node) => {
Expand Down Expand Up @@ -1006,6 +1041,7 @@ impl Router {
}

while let Some(RouteGraphNode { pubkey, lowest_fee_to_node, .. }) = targets.pop() {
log_trace!(self, "Finding link for destination {}", pubkey);
if pubkey == network.our_node_id {
let mut res = vec!(dist.remove(&network.our_node_id).unwrap().3);
loop {
Expand Down Expand Up @@ -1049,6 +1085,28 @@ impl Router {

Err(LightningError{err: "Failed to find a path to the given destination", action: ErrorAction::IgnoreError})
}

/// Gets the list of announced channels, in random order. See ChannelInfo details field documentation for more information
pub fn list_edges(&self) -> Vec<ChannelInfo> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I didnt mean to expose the internal representation, I meant to expose the last_update_message field (if it is Some). Sadly, thats maybe not perfect here since we sometimes dont include it, but exposing the fields as-is is also not OK, since channel info is initialized with dummy values until we receive the first channel_updates - if we're gonna expose them they need to be Option<>al.

let mut edges = Vec::new();
let network = self.network_map.read().unwrap();
edges.reserve(network.channels.len());
for (_, chan) in network.channels.iter() {
edges.push((*chan).clone());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole point in using an internal representation was to avoid copying the whole thing. Just return network.channels.iter() itself. (this also means you dont have to include the short_channel_ids duplicatively in memory).

Copy link
Author

@ariard ariard Apr 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you can't return a reference to network here as it's under a lock and you can't be sure than lock taking is going to be successful?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grrrr, I forgot you can't return the lock and an interator from inside it :/. Can you remove the commit that adds the short_channel_id and just return (u64, ChannelInfo)?

}
edges
}

/// Gets the list of announced nodes, in random order. See NodeInfo details field documentation for more information
pub fn list_vertices(&self) -> Vec<NodeInfo> {
let mut vertices = Vec::new();
let network = self.network_map.read().unwrap();
vertices.reserve(network.nodes.len());
for (_, node) in network.nodes.iter() {
vertices.push((*node).clone());
}
vertices
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1177,6 +1235,7 @@ mod tests {
let mut network = router.network_map.write().unwrap();

network.nodes.insert(node1.clone(), NodeInfo {
node_id: node1.clone(),
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,
Expand All @@ -1188,6 +1247,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(1, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(1, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(1)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
Expand All @@ -1211,6 +1271,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node2.clone(), NodeInfo {
node_id: node2.clone(),
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,
Expand All @@ -1222,6 +1283,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(2, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(2, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(2)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
Expand All @@ -1245,6 +1307,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node8.clone(), NodeInfo {
node_id: node8.clone(),
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,
Expand All @@ -1256,6 +1319,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(12, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(12, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(12)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
Expand All @@ -1279,6 +1343,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node3.clone(), NodeInfo {
node_id: node3.clone(),
channels: vec!(
NetworkMap::get_key(3, zero_hash.clone()),
NetworkMap::get_key(4, zero_hash.clone()),
Expand All @@ -1296,6 +1361,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(3, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(3, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(3)),
one_to_two: DirectionalChannelInfo {
src_node_id: node1.clone(),
Expand All @@ -1319,6 +1385,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(4, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(4, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(4)),
one_to_two: DirectionalChannelInfo {
src_node_id: node2.clone(),
Expand All @@ -1342,6 +1409,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(13, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(13, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(13)),
one_to_two: DirectionalChannelInfo {
src_node_id: node8.clone(),
Expand All @@ -1365,6 +1433,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node4.clone(), NodeInfo {
node_id: node4.clone(),
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,
Expand All @@ -1376,6 +1445,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(5, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(5, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(5)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
Expand All @@ -1399,6 +1469,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node5.clone(), NodeInfo {
node_id: node5.clone(),
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,
Expand All @@ -1410,6 +1481,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(6, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(6, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(6)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
Expand All @@ -1433,6 +1505,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(11, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(11, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(11)),
one_to_two: DirectionalChannelInfo {
src_node_id: node5.clone(),
Expand All @@ -1456,6 +1529,7 @@ mod tests {
announcement_message: None,
});
network.nodes.insert(node6.clone(), NodeInfo {
node_id: node6.clone(),
channels: vec!(NetworkMap::get_key(7, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
Expand All @@ -1467,6 +1541,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(7, zero_hash.clone()), ChannelInfo {
short_channel_id: NetworkMap::get_key(7, zero_hash.clone()),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(7)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
Expand Down