-
Notifications
You must be signed in to change notification settings - Fork 22
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
pathfinding #192
base: main
Are you sure you want to change the base?
pathfinding #192
Conversation
Codecov Report
@@ Coverage Diff @@
## main #192 +/- ##
==========================================
- Coverage 93.37% 92.47% -0.91%
==========================================
Files 182 183 +1
Lines 4757 4848 +91
Branches 561 581 +20
==========================================
+ Hits 4442 4483 +41
- Misses 174 214 +40
- Partials 141 151 +10
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K its coming along nicely. Some nits surrounding coding style that we can go over. The biggest issues I see are:
-
The construction of the adjacency list is only from node1 -> node2. The graph is a symmetric directed graph meaning each channel is two edges: node1->node2 and node2->node1.
-
This would be facilitated by using the
Node
'schannels
property, which is a Map. If it helps you can create a secondary property onNode
that returns a tuple containing the[Channel,ChannelSettings]
for the Node's channel setting which would aid in point 1. -
Finding the min distance should ideally use a heap, but we can get to optimizations later.
packages/graph/lib/graph.ts
Outdated
@@ -7,6 +8,8 @@ import { Node } from "./node"; | |||
* Graph represents a | |||
*/ | |||
export class Graph { | |||
public nodes_list: string[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably don't need nodes_list
. Can easily iterate over a Map type:
const map = new Map();
map.set(1, 'a');
map.set(2, 'b');
map.set(3, 'c');
// iterate over key-values since Map is an iterator
for(const [key, val] of map) {
console.log(key, val);
}
// iterate over keys as an iterator
for(const key of map.keys()) {
console.log(key);
}
// iterate over vals as an iterator
for(const val of map.values()) {
console.log(val);
}
Lastly you can covert any iterator into an Array with Array.from
:
console.log(Array.from(map));
console.log(Array.from(map.keys()));
console.log(Array.from(map.values()));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing will work with maps (;
packages/graph/lib/graph.ts
Outdated
@@ -7,6 +8,8 @@ import { Node } from "./node"; | |||
* Graph represents a | |||
*/ | |||
export class Graph { | |||
public nodes_list: string[] = []; | |||
public adjacencyList = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for adjacency list. The Node
type includes a Channels
Map that contains all of the Channels
the Node is a member of.
packages/graph/lib/graph.ts
Outdated
const str_id = dest.nodeId.toString("hex"); | ||
|
||
// Distances will store the base_fee required to traverse from the src | ||
let distances = {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Language nit: use maps over objects. Even though JS/TS allows object mutation, memory management is most effective when types remain static. As such the Set/Map types are better suited for that type of stuff.
Yes, I made a mistake it should behave like an undirected graph. Nice Catch 😓 |
Conceptually yes, channels are similar to undirected/symmetric directed graph. So both directions or every node pair where a channel exists are theoretically possible and need to be considered. For routing purposes that symmetry may break when:
|
Also just for edification, node1/node2 in the channel are just the lexicographical ordering of the identifiers. When I first starting learning this stuff I thought node1 was the opener or had some larger meaning. But it's just the node with the lower ordered nodeId. |
That's really insightful 💡 , I actually thought that node1 is probably the one who opened the channel. |
For Heap optimization, I found this package related to priority queues we can import that and workaround with it or should I build it from scratch? |
Scratch, we try to avoid external packages where possible. We'll most likely put it in the Core package but feel free to add it to this project first so we don't have to deal with deps issues while prototyping. |
Sure 🤝 |
packages/graph/lib/graph.ts
Outdated
// from dest --> src and return route from src --> dest | ||
|
||
// Convert it to corresponding node_id | ||
const str_id = dest.nodeId.toString("hex"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider calling this variable dest_str_id
or dest_id
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
min-heap looks good with a couple minors. If you want to split that into a separate PR and add tests we can merge it in.
I still need to review dijkstras using the heap.
packages/graph/lib/PriorityQueue.ts
Outdated
this._queue.push(value); | ||
let pos = this._queue.length - 1; | ||
|
||
while (pos !== 0 && this._compare(this._queue[this._parentOf(pos)], this._queue[pos])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
micro optimization but cache the call to _parentOf
since we call it 3 times. will require refactor to a do/while loop.
packages/graph/lib/PriorityQueue.ts
Outdated
} | ||
|
||
private _compare(item1: T, item2: T) { | ||
if (this._comparator) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can make the _comparator compulsory in the constructor, then we dont' need this check and can drop this whole function.
packages/graph/lib/PriorityQueue.ts
Outdated
this._queue = []; | ||
} | ||
|
||
public contains(value: T, comparator?: (item: T) => boolean) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this operation? If not then lets drop it since its extra code
separate PR would make it look neat |
fixes #190