-
Notifications
You must be signed in to change notification settings - Fork 412
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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>, | ||
} | ||
|
@@ -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"))] | ||
|
@@ -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>, | ||
|
@@ -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)?); | ||
|
@@ -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, | ||
|
@@ -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); | ||
|
@@ -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(), | ||
|
@@ -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(), | ||
|
@@ -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); | ||
|
@@ -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(), | ||
|
@@ -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 { | ||
|
@@ -955,8 +986,11 @@ impl Router { | |
} | ||
} | ||
|
||
log_trace!(self, "Node {} requires {}", $node_id, $node.features.requires_unknown_bits()); | ||
ariard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 { | ||
|
@@ -979,6 +1013,7 @@ impl Router { | |
}; | ||
} | ||
|
||
log_trace!(self, "Tracing route to {}...", target); | ||
match network.nodes.get(target) { | ||
None => {}, | ||
Some(node) => { | ||
|
@@ -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 { | ||
|
@@ -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> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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). There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)] | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
@@ -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()), | ||
|
@@ -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(), | ||
|
@@ -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(), | ||
|
@@ -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(), | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
@@ -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(), | ||
|
@@ -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, | ||
|
@@ -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(), | ||
|
Uh oh!
There was an error while loading. Please reload this page.