Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Replace PublicKey with [u8; 33] in NetworkGraph by dunxen · Pull Request #1107 · lightningdevkit/rust-lightning · GitHub
Skip to content
Merged
Show file tree
Hide file tree
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
110 changes: 90 additions & 20 deletions lightning/src/routing/network_graph.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@

//! 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;
Expand DownExpand Up@@ -50,12 +51,75 @@ const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
/// 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)?;
Comment thread
dunxen marked this conversation as resolved.
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 {
Expand All@@ -73,7 +137,7 @@ impl Clone for NetworkGraph {
/// 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
Expand DownExpand Up@@ -277,11 +341,11 @@ where C::Target: chain::Access, L::Target: Logger
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() {
Expand DownExpand Up@@ -314,7 +378,7 @@ where C::Target: chain::Access, L::Target: Logger
}

// 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 ();
}

Expand DownExpand Up@@ -551,11 +615,11 @@ pub struct ChannelInfo {
/// 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.
Expand All@@ -570,7 +634,7 @@ pub struct ChannelInfo {
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(())
}
}
Expand DownExpand Up@@ -724,8 +788,8 @@ impl fmt::Display for NetworkGraph {
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(())
}
Expand DownExpand Up@@ -780,7 +844,7 @@ impl NetworkGraph {
}

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() {
Expand DownExpand Up@@ -886,9 +950,9 @@ impl NetworkGraph {

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
Expand DownExpand Up@@ -939,8 +1003,8 @@ impl NetworkGraph {
};
}

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(())
}
Expand DownExpand Up@@ -1050,13 +1114,19 @@ impl NetworkGraph {
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);
}
Expand DownExpand Up@@ -1104,7 +1174,7 @@ impl NetworkGraph {
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) {
Expand DownExpand Up@@ -1136,7 +1206,7 @@ impl ReadOnlyNetworkGraph<'_> {
/// 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
}

Expand All@@ -1146,7 +1216,7 @@ impl ReadOnlyNetworkGraph<'_> {
///
/// (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)
}
Expand Down
Loading