//! The top-level network map tracking logic lives here.
+use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
use bitcoin::secp256k1::key::PublicKey;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::secp256k1;
/// This value ensures a reply fits within the 65k payload limit and is consistent with other implementations.
const MAX_SCIDS_PER_REPLY: usize = 8000;
+/// Represents the compressed public key of a node
+#[derive(Clone, Copy)]
+pub struct NodeId([u8; PUBLIC_KEY_SIZE]);
+
+impl NodeId {
+ /// Create a new NodeId from a public key
+ pub fn from_pubkey(pubkey: &PublicKey) -> Self {
+ NodeId(pubkey.serialize())
+ }
+
+ /// Get the public key slice from this NodeId
+ pub fn as_slice(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+impl fmt::Debug for NodeId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "NodeId({})", log_bytes!(self.0))
+ }
+}
+
+impl core::hash::Hash for NodeId {
+ fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
+ self.0.hash(hasher);
+ }
+}
+
+impl Eq for NodeId {}
+
+impl PartialEq for NodeId {
+ fn eq(&self, other: &Self) -> bool {
+ self.0[..] == other.0[..]
+ }
+}
+
+impl cmp::PartialOrd for NodeId {
+ fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for NodeId {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ self.0[..].cmp(&other.0[..])
+ }
+}
+
+impl Writeable for NodeId {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+ writer.write_all(&self.0)?;
+ Ok(())
+ }
+}
+
+impl Readable for NodeId {
+ fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ let mut buf = [0; PUBLIC_KEY_SIZE];
+ reader.read_exact(&mut buf)?;
+ Ok(Self(buf))
+ }
+}
+
/// Represents the network as nodes and channels between them
pub struct NetworkGraph {
genesis_hash: BlockHash,
// Lock order: channels -> nodes
channels: RwLock<BTreeMap<u64, ChannelInfo>>,
- nodes: RwLock<BTreeMap<PublicKey, NodeInfo>>,
+ nodes: RwLock<BTreeMap<NodeId, NodeInfo>>,
+}
+
+impl Clone for NetworkGraph {
+ fn clone(&self) -> Self {
+ let channels = self.channels.read().unwrap();
+ let nodes = self.nodes.read().unwrap();
+ Self {
+ genesis_hash: self.genesis_hash.clone(),
+ channels: RwLock::new(channels.clone()),
+ nodes: RwLock::new(nodes.clone()),
+ }
+ }
}
/// A read-only view of [`NetworkGraph`].
pub struct ReadOnlyNetworkGraph<'a> {
channels: RwLockReadGuard<'a, BTreeMap<u64, ChannelInfo>>,
- nodes: RwLockReadGuard<'a, BTreeMap<PublicKey, NodeInfo>>,
+ nodes: RwLockReadGuard<'a, BTreeMap<NodeId, NodeInfo>>,
}
/// Update to the [`NetworkGraph`] based on payment failure information conveyed via the Onion
let mut result = Vec::with_capacity(batch_amount as usize);
let nodes = self.network_graph.nodes.read().unwrap();
let mut iter = if let Some(pubkey) = starting_point {
- let mut iter = nodes.range((*pubkey)..);
+ let mut iter = nodes.range(NodeId::from_pubkey(pubkey)..);
iter.next();
iter
} else {
- nodes.range(..)
+ nodes.range::<NodeId, _>(..)
};
while result.len() < batch_amount as usize {
if let Some((_, ref node)) = iter.next() {
}
// Check if we need to perform a full synchronization with this peer
- if !self.should_request_full_sync(their_node_id) {
+ if !self.should_request_full_sync(&their_node_id) {
return ();
}
/// Protocol features of a channel communicated during its announcement
pub features: ChannelFeatures,
/// Source node of the first direction of a channel
- pub node_one: PublicKey,
+ pub node_one: NodeId,
/// Details about the first direction of a channel
pub one_to_two: Option<DirectionalChannelInfo>,
/// Source node of the second direction of a channel
- pub node_two: PublicKey,
+ pub node_two: NodeId,
/// Details about the second direction of a channel
pub two_to_one: Option<DirectionalChannelInfo>,
/// The channel capacity as seen on-chain, if chain lookup is available.
impl fmt::Display for ChannelInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "features: {}, node_one: {}, one_to_two: {:?}, node_two: {}, two_to_one: {:?}",
- log_bytes!(self.features.encode()), log_pubkey!(self.node_one), self.one_to_two, log_pubkey!(self.node_two), self.two_to_one)?;
+ log_bytes!(self.features.encode()), log_bytes!(self.node_one.as_slice()), self.one_to_two, log_bytes!(self.node_two.as_slice()), self.two_to_one)?;
Ok(())
}
}
writeln!(f, " {}: {}", key, val)?;
}
writeln!(f, "[Nodes]")?;
- for (key, val) in self.nodes.read().unwrap().iter() {
- writeln!(f, " {}: {}", log_pubkey!(key), val)?;
+ for (&node_id, val) in self.nodes.read().unwrap().iter() {
+ writeln!(f, " {}: {}", log_bytes!(node_id.as_slice()), val)?;
}
Ok(())
}
}
fn update_node_from_announcement_intern(&self, msg: &msgs::UnsignedNodeAnnouncement, full_msg: Option<&msgs::NodeAnnouncement>) -> Result<(), LightningError> {
- match self.nodes.write().unwrap().get_mut(&msg.node_id) {
+ match self.nodes.write().unwrap().get_mut(&NodeId::from_pubkey(&msg.node_id)) {
None => Err(LightningError{err: "No existing channels for node_announcement".to_owned(), action: ErrorAction::IgnoreError}),
Some(node) => {
if let Some(node_info) = node.announcement_info.as_ref() {
let chan_info = ChannelInfo {
features: msg.features.clone(),
- node_one: msg.node_id_1.clone(),
+ node_one: NodeId::from_pubkey(&msg.node_id_1),
one_to_two: None,
- node_two: msg.node_id_2.clone(),
+ node_two: NodeId::from_pubkey(&msg.node_id_2),
two_to_one: None,
capacity_sats: utxo_value,
announcement_message: if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY
};
}
- add_channel_to_node!(msg.node_id_1);
- add_channel_to_node!(msg.node_id_2);
+ add_channel_to_node!(NodeId::from_pubkey(&msg.node_id_1));
+ add_channel_to_node!(NodeId::from_pubkey(&msg.node_id_2));
Ok(())
}
if msg.flags & 1 == 1 {
dest_node_id = channel.node_one.clone();
if let Some((sig, ctx)) = sig_info {
- secp_verify_sig!(ctx, &msg_hash, &sig, &channel.node_two);
+ secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_two.as_slice()).map_err(|_| LightningError{
+ err: "Couldn't parse source node pubkey".to_owned(),
+ action: ErrorAction::IgnoreAndLog(Level::Debug)
+ })?);
}
maybe_update_channel_info!(channel.two_to_one, channel.node_two);
} else {
dest_node_id = channel.node_two.clone();
if let Some((sig, ctx)) = sig_info {
- secp_verify_sig!(ctx, &msg_hash, &sig, &channel.node_one);
+ secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_one.as_slice()).map_err(|_| LightningError{
+ err: "Couldn't parse destination node pubkey".to_owned(),
+ action: ErrorAction::IgnoreAndLog(Level::Debug)
+ })?);
}
maybe_update_channel_info!(channel.one_to_two, channel.node_one);
}
Ok(())
}
- fn remove_channel_in_nodes(nodes: &mut BTreeMap<PublicKey, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
+ fn remove_channel_in_nodes(nodes: &mut BTreeMap<NodeId, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
macro_rules! remove_from_node {
($node_id: expr) => {
if let BtreeEntry::Occupied(mut entry) = nodes.entry($node_id) {
/// Returns all known nodes' public keys along with announced node info.
///
/// (C-not exported) because we have no mapping for `BTreeMap`s
- pub fn nodes(&self) -> &BTreeMap<PublicKey, NodeInfo> {
+ pub fn nodes(&self) -> &BTreeMap<NodeId, NodeInfo> {
&*self.nodes
}
///
/// (C-not exported) as there is no practical way to track lifetimes of returned values.
pub fn get_addresses(&self, pubkey: &PublicKey) -> Option<&Vec<NetAddress>> {
- if let Some(node) = self.nodes.get(pubkey) {
+ if let Some(node) = self.nodes.get(&NodeId::from_pubkey(&pubkey)) {
if let Some(node_info) = node.announcement_info.as_ref() {
return Some(&node_info.addresses)
}
payment_hash: PaymentHash([0; 32]),
rejected_by_dest: false,
all_paths_failed: true,
+ path: vec![],
network_update: Some(NetworkUpdate::ChannelUpdateMessage {
msg: valid_channel_update,
}),
+ short_channel_id: None,
error_code: None,
error_data: None,
});
payment_hash: PaymentHash([0; 32]),
rejected_by_dest: false,
all_paths_failed: true,
+ path: vec![],
network_update: Some(NetworkUpdate::ChannelClosed {
short_channel_id,
is_permanent: false,
}),
+ short_channel_id: None,
error_code: None,
error_data: None,
});
payment_hash: PaymentHash([0; 32]),
rejected_by_dest: false,
all_paths_failed: true,
+ path: vec![],
network_update: Some(NetworkUpdate::ChannelClosed {
short_channel_id,
is_permanent: true,
}),
+ short_channel_id: None,
error_code: None,
error_data: None,
});