Skip to content

Commit

Permalink
Merge pull request #13 from ledgerloops/cache-outgoing-links
Browse files Browse the repository at this point in the history
Cache outgoing links
  • Loading branch information
michielbdejong authored Oct 1, 2024
2 parents a9c143c + a2d97a4 commit 2cedb72
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 25 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,18 @@ npm run build
time node build/src/birdsEyeAnalysis.js __tests__/fixture-300.csv > birdseye-30.log
time node build/src/birdsEyeAnalysis.js __tests__/fixture-300.csv > birdseye-300.log
time node build/src/birdsEyeAnalysis.js __tests__/fixture-3000.csv > birdseye-3k.log
time node build/src/birdsEyeAnalysis.js __tests__/fixture-30000.csv > birdseye-3k.log
time node build/src/analysis.js __tests__/fixture-300.csv > jerboa-30.log
time node build/src/analysis.js __tests__/fixture-30.csv > jerboa-30.log
time node build/src/analysis.js __tests__/fixture-300.csv > jerboa-300.log
time node build/src/analysis.js __tests__/fixture-3000.csv > jerboa-3k.log
time node build/src/analysis.js __tests__/fixture-3000.csv > jerboa-30k.log
diff ./jerboa-30.log ./birdseye-30.log
diff ./jerboa-300.log ./birdseye-300.log
diff ./jerboa-3k.log ./birdseye-3k.log
diff ./jerboa-3k.log ./birdseye-30k.log
```

The diff output is expected to show that BirdsEyeAnalysis does more netting, because it nets after every transfer, and Jerboa only nets the balances after all transfers are finished.
Other than that, Jerboa takes about 5 seconds on 3k transactions which is really quite slow. We're working on improving that to get it closer to the BirdsEye performance.
Other than that, Jerboa takes about 15 seconds on 30k transactions which is really quite slow. We're working on improving that to get it closer to the BirdsEye performance.
14 changes: 7 additions & 7 deletions __tests__/Jerboa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Jerboa', () => {
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['transfer', '9']);
const result = a.startProbe();
expect(result).toEqual(true);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', '[]']);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', '[]', '[]']);
});
it('forwards a probe if it can', () => {
const graph = new Graph();
Expand All @@ -31,8 +31,8 @@ describe('Jerboa', () => {
const a = new Jerboa('a', graph);
a.addWeight('b', 9);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['transfer', '9']);
a.receiveMessage('x', ['probe', JSON.stringify(['b', 'c'])]);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', JSON.stringify(['b', 'c', 'x'])]);
a.receiveMessage('x', ['probe', JSON.stringify(['b', 'c']), '[]']);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', JSON.stringify(['b', 'c', 'x']), '[]']);
});
it('splices off a loop if it can', () => {
const graph = new Graph();
Expand All @@ -41,15 +41,15 @@ describe('Jerboa', () => {
const a = new Jerboa('a', graph);
a.addWeight('b', 9);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['transfer', '9']);
a.receiveMessage('x', ['probe', JSON.stringify(['b', 'c', 'a', 'd'])]); // so the loop is a-d-x-a and b-c-a is the old prefix
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', JSON.stringify(['b', 'c'])]);
a.receiveMessage('x', ['probe', JSON.stringify(['b', 'c', 'a', 'd']), '[]']); // so the loop is a-d-x-a and b-c-a is the old prefix
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'b', ['probe', JSON.stringify(['b', 'c']), '[]']);
});
it ('replies with nack if it is a leaf', () => {
const graph = new Graph();
graph.messaging = new Messaging(graph);
graph.messaging.sendMessage = jest.fn();
const a = new Jerboa('a', graph);
a.receiveMessage('x', ['probe', '[]']);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'x', ['nack', JSON.stringify([])]);
a.receiveMessage('x', ['probe', '[]', '[]']);
expect(graph.messaging.sendMessage).toHaveBeenCalledWith('a', 'x', ['nack', JSON.stringify([]), '[]']);
});
});
6 changes: 3 additions & 3 deletions src/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class Graph {
if (typeof nodesObj === 'undefined') {
throw new Error(`No outgoing links from node ${after}`);
}
nodes = nodesObj.getOutgoingLinks(true);
nodes = nodesObj.getOutgoingLinks();
} else {
nodes = Object.keys(this.nodes);
if (nodes.length === 0) {
Expand All @@ -58,7 +58,7 @@ export class Graph {
}
if (withOutgoingLinks) {
for (let i = 0; i < nodes.length; i++) {
if ((typeof this.nodes[nodes[i]] !== 'undefined') && (this.nodes[nodes[i]].getOutgoingLinks(true).length >= 1)) {
if ((typeof this.nodes[nodes[i]] !== 'undefined') && (this.nodes[nodes[i]].getOutgoingLinks().length >= 1)) {
return nodes[i];
}
}
Expand All @@ -71,7 +71,7 @@ export class Graph {
if (typeof after !== 'string') {
throw new Error(`after param ${JSON.stringify(after)} is not a string in call to hasOutgoingLinks`);
}
return ((typeof this.nodes[after] !== 'undefined') && (this.nodes[after].getOutgoingLinks(true).length >= 1));
return ((typeof this.nodes[after] !== 'undefined') && (this.nodes[after].getOutgoingLinks().length >= 1));
}
public getWeight(from: string, to: string): number {
if (typeof from !== 'string') {
Expand Down
31 changes: 18 additions & 13 deletions src/Jerboa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Jerboa {
private balances: Balances = new Balances();
private graph: Graph;
private name: string;
private nack: {
private outgoingLinks: {
[friend: string]: boolean
} = {};
constructor(name: string, graph: Graph) {
Expand Down Expand Up @@ -113,11 +113,15 @@ export class Jerboa {
receiveTransfer(sender: string, amount: number): void {
// console.log(`${sender}->${this.name}: ${amount}`);
this.balances.adjustReceived(sender, amount);
const newBalance = this.balances.getBalance(sender);
if (newBalance < MIN_LOOP_WEIGHT) {
delete this.outgoingLinks[sender];
}
}
receiveNack(nackSender: string, path: string[], backtracked: string[]): void {
this.nack[nackSender] = true;
delete this.outgoingLinks[nackSender];
if (path.length === 0) {
const nodes = this.getOutgoingLinks(true);
const nodes = this.getOutgoingLinks();
if (nodes.length === 0) {
console.log('finished ', [], [this.name, nackSender].concat(backtracked));
} else {
Expand Down Expand Up @@ -157,7 +161,7 @@ export class Jerboa {
return;
}
// console.log('path after splicing', path);
const nodes = this.getOutgoingLinks(true);
const nodes = this.getOutgoingLinks();
if (nodes.length === 0) {
// console.log(` combining self, sending nack ${this.name}->${sender}`, path, backtracked);
const task = ['nack', JSON.stringify(path), JSON.stringify(backtracked)];
Expand Down Expand Up @@ -194,16 +198,17 @@ export class Jerboa {
}
addWeight(to: string, weight: number): void {
this.balances.adjustSent(to, weight);
const newBalance = this.balances.getBalance(to);
if (newBalance > MIN_LOOP_WEIGHT) {
this.outgoingLinks[to] = true;
} else {
delete this.outgoingLinks[to];
}

this.graph.messaging.sendMessage(this.name, to, ['transfer', JSON.stringify(weight)]);
}
getOutgoingLinks(avoidNack: boolean): string[] {
const balances = this.balances.getBalances();
return Object.keys(balances).filter((to: string) => {
if ((avoidNack) && (this.nack[to])) {
return false;
}
return (balances[to] > MIN_LOOP_WEIGHT);
});
getOutgoingLinks(): string[] {
return Object.keys(this.outgoingLinks);
}
getBalance(to: string): number {
return this.balances.getBalance(to);
Expand All @@ -215,7 +220,7 @@ export class Jerboa {
return this.balances.getArchiveWeights(this.name);
}
startProbe(): boolean {
const nodes = this.getOutgoingLinks(true);
const nodes = this.getOutgoingLinks();
if (nodes.length === 0) {
return false;
}
Expand Down

0 comments on commit 2cedb72

Please sign in to comment.