From 7eab455b83d8b88622e3927357657dd1af33e813 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 1 Oct 2024 14:44:28 +0200 Subject: [PATCH 1/3] Make avoidNack hardcoded --- src/Graph.ts | 6 +++--- src/Jerboa.ts | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Graph.ts b/src/Graph.ts index 4cc61a4..67c7493 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -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) { @@ -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]; } } @@ -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') { diff --git a/src/Jerboa.ts b/src/Jerboa.ts index 4e3e1fe..a373596 100644 --- a/src/Jerboa.ts +++ b/src/Jerboa.ts @@ -117,7 +117,7 @@ export class Jerboa { receiveNack(nackSender: string, path: string[], backtracked: string[]): void { this.nack[nackSender] = true; 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 { @@ -157,7 +157,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)]; @@ -194,12 +194,13 @@ export class Jerboa { } addWeight(to: string, weight: number): void { this.balances.adjustSent(to, weight); + this.graph.messaging.sendMessage(this.name, to, ['transfer', JSON.stringify(weight)]); } - getOutgoingLinks(avoidNack: boolean): string[] { + getOutgoingLinks(): string[] { const balances = this.balances.getBalances(); return Object.keys(balances).filter((to: string) => { - if ((avoidNack) && (this.nack[to])) { + if (this.nack[to]) { return false; } return (balances[to] > MIN_LOOP_WEIGHT); @@ -215,7 +216,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; } From 79d91727cf4afd536745978dfc2f5581108a4265 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 1 Oct 2024 14:51:44 +0200 Subject: [PATCH 2/3] Cache outgoing links --- README.md | 7 +++++-- src/Jerboa.ts | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ca00f1f..2e02c54 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file +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. \ No newline at end of file diff --git a/src/Jerboa.ts b/src/Jerboa.ts index a373596..aa16696 100644 --- a/src/Jerboa.ts +++ b/src/Jerboa.ts @@ -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) { @@ -113,9 +113,13 @@ 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(); if (nodes.length === 0) { @@ -194,17 +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(): string[] { - const balances = this.balances.getBalances(); - return Object.keys(balances).filter((to: string) => { - if (this.nack[to]) { - return false; - } - return (balances[to] > MIN_LOOP_WEIGHT); - }); + return Object.keys(this.outgoingLinks); } getBalance(to: string): number { return this.balances.getBalance(to); From a2d97a4ca787588e6b403908050cba930965fe44 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 1 Oct 2024 14:53:44 +0200 Subject: [PATCH 3/3] Fix testrs --- __tests__/Jerboa.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/__tests__/Jerboa.test.ts b/__tests__/Jerboa.test.ts index dffcad8..8ef277f 100644 --- a/__tests__/Jerboa.test.ts +++ b/__tests__/Jerboa.test.ts @@ -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(); @@ -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(); @@ -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([]), '[]']); }); }); \ No newline at end of file