Skip to content

Allow unspecified alias destinations #254

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

chuksys
Copy link

@chuksys chuksys commented Apr 17, 2025

Description

This PR pulls up the network graph to make it simpler to run node lookups using public keys and aliases. This new node lookup approach is used to allow unspecified aliases in activity destinations by confirming if node(s) with unspecified alias exists in the graph.

Changes

  1. Added Graph struct to simln-lib to enable simpler node lookups.
  2. Added get_graph function to LightningNode trait and implemented it in the different LN implementations.
  3. Refactored activities validation to run lookup against Graph directly.
  4. Enabled mapping of duplicate aliases in alias_node_map and nodes_by_alias.

This PR closes #227

Copy link
Author

@chuksys chuksys left a comment

Choose a reason for hiding this comment

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

Dropped some notes. Open to suggestions.

@chuksys chuksys marked this pull request as ready for review April 22, 2025 01:25
Copy link
Contributor

@carlaKC carlaKC left a comment

Choose a reason for hiding this comment

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

Promising start, but I think that this PR has scope crept a bit. I'd really like to keep this down to just the case where we have a destination alias that isn't in our configured set of nodes. Feel free to squash and restructure as suggested, we can start with fixups when the PR's structure is in good shape.

Also think that we need to look more carefully at the design of the graph function in the LightningNode trait and move some of the more custom behavior into our validation function.

@chuksys
Copy link
Author

chuksys commented Apr 23, 2025

Promising start, but I think that this PR has scope crept a bit. I'd really like to keep this down to just the case where we have a destination alias that isn't in our configured set of nodes. Feel free to squash and restructure as suggested, we can start with fixups when the PR's structure is in good shape.

Also think that we need to look more carefully at the design of the graph function in the LightningNode trait and move some of the more custom behavior into our validation function.

Thanks for the feedback. Will sort this out asap!

chuksys added 2 commits April 30, 2025 20:36
Switches from an async closure to direct NetworkGraph usage for activity destination node lookup. This improves efficiency and maintainability, and enables destination aliases by validating against the graph and erroring on duplicates.
@chuksys chuksys force-pushed the allow-unspecified-alias-destinations branch from 3b865f6 to 9fe6a15 Compare April 30, 2025 19:42
@chuksys chuksys requested a review from carlaKC April 30, 2025 20:41
Copy link
Contributor

@carlaKC carlaKC left a comment

Choose a reason for hiding this comment

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

Moving in the right direction!

))
let graph = match clients.values().next() {
Some(client) => client.lock().await.get_graph().await?,
None => panic!("Graph is empty"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Return an error rather than panicing?

@@ -5,12 +5,11 @@ use log::LevelFilter;
use serde::{Deserialize, Serialize};
use simln_lib::{
cln, cln::ClnNode, eclair, eclair::EclairNode, lnd, lnd::LndNode, serializers,
ActivityDefinition, Amount, Interval, LightningError, LightningNode, NodeId, NodeInfo,
ActivityDefinition, Amount, Graph, Interval, LightningError, LightningNode, NodeId, NodeInfo,
Copy link
Contributor

Choose a reason for hiding this comment

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

Commit message still doesn't wrap at 72

@@ -215,9 +209,9 @@ async fn get_clients(
/// validation.
async fn add_node_to_maps(
nodes: &HashMap<PublicKey, NodeInfo>,
) -> Result<(HashMap<PublicKey, NodeInfo>, HashMap<String, NodeInfo>), LightningError> {
) -> Result<(HashMap<PublicKey, NodeInfo>, HashMap<String, Vec<NodeInfo>>), LightningError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be a vec?

Copy link
Author

Choose a reason for hiding this comment

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

You are right. It doesn't have to be a vec anymore since we aren't allowing duplicates in the user-provided aliases.

// An alias can be mapped to multiple nodes because it is not a unique identifier.
let mut graph_nodes_by_alias: HashMap<String, Vec<NodeInfo>> = HashMap::new();

// sort graph nodes by alias for easy lookups.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: unnecessary comment, can delete

alias_node_map: HashMap<String, NodeInfo>,
get_node_info: impl AsyncFn(&PublicKey) -> Result<NodeInfo, LightningError>,
alias_node_map: HashMap<String, Vec<NodeInfo>>,
mut graph: Graph,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: let's pass in the hashmap that's ready for lookups here (like we do for the other maps)

Copy link
Author

Choose a reason for hiding this comment

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

This would likely require passing in 2 hashmaps - one keyed by pk and the other by alias; we'd have 5 params in total. If this is fine by you then let's do it (or maybe use a struct?).

Copy link
Contributor

Choose a reason for hiding this comment

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

Struct sounds good 👍

@@ -441,6 +442,8 @@ trait SimNetwork: Send + Sync {

/// Looks up a node in the simulated network and a list of its channel capacities.
async fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError>;
/// fetches all nodes in the simulated network
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: capitals for docs, applies in a few places

Comment on lines +311 to +313
pub fn get_nodes(&mut self) -> Result<HashMap<PublicKey, NodeInfo>, LightningError> {
Ok(self.nodes_by_pk.clone())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like an unnecessary clone to me (for a data struct that could have around 16k entries in it).

I think it's okay to make nodes_by_pk pub and then callers can borrow rather than needing to copy all this data + have specialized getters.

Comment on lines +303 to +304
if let Some(node_infos) = alias_node_map.get(a) {
node_infos[0].clone()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see why we need to allow multiple node_infos in our alias_node_map when that's a map of the aliases that the user specified and we validated to make sure are unique?

graph_nodes_by_alias makes sense as a vec, I like the impl, but we don't need to change both.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, not making alias_node_map structured as a vec of node_infos will fix this.

described above). Activity sources and destinations may reference the
`id` defined in `nodes`, but destinations that are not listed in `nodes`
*must* provide a valid public key.
Nodes can be identified by their public key or an id string (as described above). Activity sources and destinations may reference the `id` defined in `nodes`. However, if multiple destination nodes have the same id string (alias), valid public keys *must* be used to identify the nodes.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: line wrapping incorrect

described above). Activity sources and destinations may reference the
`id` defined in `nodes`, but destinations that are not listed in `nodes`
*must* provide a valid public key.
Nodes can be identified by their public key or an id string (as described above). Activity sources and destinations may reference the `id` defined in `nodes`. However, if multiple destination nodes have the same id string (alias), valid public keys *must* be used to identify the nodes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Would also like to rephrase this a bit.

Activity sources must reference an id defined in nodes, because the simulator can
only send payments from nodes that it controls. Destinations may reference either an
id defined in nodes or provide a pubkey or alias of a node in the public network.
If the alias provided is not unique in the public network, a pubkey must be used
to identify the node.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Allow Destination nodes for un-specified aliases
2 participants