-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat: prioritize short paths during findBestHop #54
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,29 +70,31 @@ class RoutingTable { | |
return undefined | ||
} | ||
|
||
let bestHop = null | ||
let bestValue = null | ||
let bestRoute = null | ||
let bestHop | ||
routes.forEach((route, nextHop) => { | ||
const value = route.amountAt(sourceAmount) | ||
// If we have a route but not a curve, pick a route at random | ||
// and get a remote quote. In the future we may refactor this | ||
// so that multiple next hop options can be returned, and all | ||
// can be asked for a quote, but for now, it's just the last. | ||
if (value === undefined || !bestValue || value.gt(bestValue)) { | ||
bestHop = nextHop | ||
bestValue = value && value.toString() | ||
bestRoute = route | ||
} | ||
bestHop = getBetterHop(bestHop, { | ||
nextHop, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getBetterHop takes two arguments, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do all of |
||
route, | ||
value: route.amountAt(sourceAmount), | ||
pathLength: route.maxPathLength() | ||
}) | ||
}) | ||
|
||
if (bestHop) { | ||
debug('findBestHopForSourceAmount to ' + destination + ' for ' + sourceAmount + ' found route through ' + bestHop) | ||
debug('findBestHopForSourceAmount to ' + destination + ' for ' + sourceAmount + ' found route through ' + bestHop.nextHop) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above, |
||
} else { | ||
debug('findBestHopForSourceAmount could not find route to ' + destination + ' for ' + sourceAmount + '. Current routing table: ' + JSON.stringify(this.destinations.toJSON())) | ||
} | ||
|
||
return { bestHop, bestValue, bestRoute } | ||
return { | ||
bestHop: bestHop.nextHop, | ||
bestValue: bestHop.value && bestHop.value.toString(), | ||
bestRoute: bestHop.route | ||
} | ||
} | ||
|
||
findBestHopForDestinationAmount (destination, destinationAmount) { | ||
|
@@ -103,30 +105,52 @@ class RoutingTable { | |
return undefined | ||
} | ||
|
||
let bestHop = null | ||
let bestCost = Infinity | ||
let bestRoute = null | ||
let bestHop | ||
routes.forEach((route, nextHop) => { | ||
const cost = route.amountReverse(destinationAmount) | ||
if (cost.equals(Infinity)) return | ||
// If we have a route but not a curve, pick a route at random | ||
// and get a remote quote. In the future we may refactor this | ||
// so that multiple next hop options can be returned, and all | ||
// can be asked for a quote, but for now, it's just the last. | ||
if (cost === undefined || cost.lt(bestCost)) { | ||
bestHop = nextHop | ||
bestCost = cost && cost.toString() | ||
bestRoute = route | ||
} | ||
bestHop = getBetterHop(bestHop, { | ||
nextHop, | ||
route, | ||
cost, | ||
pathLength: route.maxPathLength() | ||
}) | ||
}) | ||
|
||
if (bestHop) { | ||
debug('findBestHopForDestinationAmount to ' + destination + ' for ' + destinationAmount + ' found route through ' + bestHop) | ||
return { bestHop, bestCost, bestRoute } | ||
debug('findBestHopForDestinationAmount to ' + destination + ' for ' + destinationAmount + ' found route through ' + bestHop.nextHop) | ||
return { | ||
bestHop: bestHop.nextHop, | ||
bestCost: bestHop.cost && bestHop.cost.toString(), | ||
bestRoute: bestHop.route | ||
} | ||
} else { | ||
debug('findBestHopForDestinationAmount could not find route to ' + destination + ' for ' + destinationAmount + '. Current routing table: ' + JSON.stringify(this.destinations.toJSON())) | ||
return undefined | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* If both hops score equally, return `currentHop`. | ||
* It doesn't actually matter which is returned in that case, so long as it is consistent. | ||
*/ | ||
function getBetterHop (currentHop, otherHop) { | ||
if (!currentHop) return otherHop | ||
if (currentHop.pathLength < otherHop.pathLength) return currentHop | ||
if (otherHop.pathLength < currentHop.pathLength) return otherHop | ||
if (otherHop.value !== undefined) { | ||
return otherHop.value.gt(currentHop.value) ? otherHop : currentHop | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this will throw an error if currentHop.value is undefined |
||
} | ||
if (otherHop.cost !== undefined) { | ||
return otherHop.cost.lt(currentHop.cost) ? otherHop : currentHop | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will throw an error if currentHop.cost is undefined |
||
} | ||
// No curve | ||
return currentHop | ||
} | ||
|
||
module.exports = RoutingTable |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ const Route = require('../src/lib/route') | |
|
||
const ledgerA = 'ledgerA.' | ||
const ledgerB = 'ledgerB.' | ||
const ledgerC = 'ledgerB.' | ||
const markB = ledgerB + 'mark' | ||
const maryB = ledgerB + 'mary' | ||
|
||
|
@@ -76,6 +77,16 @@ describe('RoutingTable', function () { | |
const table = new RoutingTable() | ||
assert.strictEqual(table.findBestHopForSourceAmount(ledgerB, 10), undefined) | ||
}) | ||
|
||
it('prefers short routes', function () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you have a test case for each of the comparisons in getBetterHop? |
||
const table = new RoutingTable() | ||
const routeMark = new Route([[0, 0], [100, 999]], {sourceLedger: ledgerA, nextLedger: ledgerB, destinationLedger: ledgerB}) | ||
const routeMary = new Route([[0, 0], [100, 100]], {sourceLedger: ledgerA, nextLedger: ledgerC, destinationLedger: ledgerB}) | ||
table.addRoute(ledgerB, markB, routeMark) | ||
table.addRoute(ledgerB, ledgerC + 'mary', routeMary) | ||
assert.deepEqual(table.findBestHopForSourceAmount(ledgerB, 50), | ||
{ bestHop: markB, bestValue: '499', bestRoute: routeMark }) | ||
}) | ||
}) | ||
|
||
describe('findBestHopForDestinationAmount', function () { | ||
|
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.
This means we count a route
trustLine -> localLedger
as length 2, so counting the number of ledgers involved. I originally thought of it as the number of connections, sothis.nextLedger === this.destinationLedger ? max + 1 : max + 2
but I guess your way of counting makes (more) sense.