switch to probing subscription, fix swap recovery

This commit is contained in:
Alex Bosworth 2020-07-27 20:00:47 -07:00
parent e62a39bd90
commit 46f77e64d7
No known key found for this signature in database
GPG key ID: E80D2F3F311FD87E
15 changed files with 405 additions and 161 deletions

View file

@ -1,5 +1,10 @@
# Versions
## Version 5.41.4
- `increase-inbound-liquidity`: Fix `--recovery` option
- `probe`: Rework `--find-max` methodology
## Version 5.41.3
- `increase-inbound-liquidity`: Support longer swap timeouts

117
display/describe_route.js Normal file
View file

@ -0,0 +1,117 @@
const asyncAuto = require('async/auto');
const asyncMap = require('async/map');
const {getNode} = require('ln-service');
const {green} = require('colorette');
const {returnResult} = require('asyncjs-util');
const describeConfidence = require('./describe_confidence');
const formatFeeRate = require('./format_fee_rate');
const effectiveFeeRate = (n, m) => Number(BigInt(1e6) * BigInt(n) / BigInt(m));
const flatten = arr => [].concat(...arr);
/** Describe a route
{
lnd: <Authenticated LND API Object>
route: {
[confidence]: <Route Confidence Score Out Of One Million Number>
fee: <Total Fee Tokens To Pay Number>
fee_mtokens: <Total Fee Millitokens To Pay String>
hops: [{
channel: <Standard Format Channel Id String>
channel_capacity: <Channel Capacity Tokens Number>
fee: <Fee Number>
fee_mtokens: <Fee Millitokens String>
forward: <Forward Tokens Number>
forward_mtokens: <Forward Millitokens String>
public_key: <Public Key Hex String>
timeout: <Timeout Block Height Number>
}]
[messages]: [{
type: <Message Type Number String>
value: <Message Raw Value Hex Encoded String>
}]
mtokens: <Total Millitokens To Pay String>
[payment]: <Payment Identifier Hex String>
safe_fee: <Payment Forwarding Fee Rounded Up Tokens Number>
safe_tokens: <Payment Sent Tokens Rounded Up Number>
timeout: <Expiration Block Height Number>
tokens: <Total Tokens To Pay Number>
[total_mtokens]: <Total Millitokens String>
}
}
@returns via cbk or Promise
{
description: [<Hop Description String>]
}
*/
module.exports = ({lnd, route}, cbk) => {
return new Promise((resolve, reject) => {
return asyncAuto({
// Check arguments
validate: cbk => {
if (!lnd) {
return cbk([400, 'ExpectedLndObjectToGenerateRouteDescription']);
}
if (!route) {
return cbk([400, 'ExpectedRouteToGenerateRouteDescriptionFor']);
}
return cbk();
},
// Get the node aliases
getAliases: ['validate', ({}, cbk) => {
return asyncMap(route.hops, (hop, cbk) => {
return getNode({
lnd,
is_omitting_channels: true,
public_key: hop.public_key,
},
(err, res) => {
if (!!err) {
return cbk(null, {alias: Strig(), id: hop.public_key});
}
return cbk(null, {alias: res.alias, id: hop.public_key});
});
},
cbk);
}],
// Assemble the description
description: ['getAliases', ({getAliases}, cbk) => {
const {confidence} = route;
const {description} = describeConfidence({confidence});
const path = route.hops.map((hop, i, hops) => {
const {alias} = getAliases.find(n => n.id === hop.public_key);
const feeMtokens = !i ? hop.fee_mtokens : hops[i - 1].fee_mtokens;
const forwarder = `${alias} ${hop.public_key}`.trim();
const feeRate = effectiveFeeRate(feeMtokens, hop.forward_mtokens);
const rate = formatFeeRate({rate: feeRate}).display;
const forward = `${green(forwarder)}. Hop fee rate ${rate}`;
if (!i) {
return [`${hop.channel} ${description || String()}`, forward];
} else if (i === hops.length - [i].length) {
return [`${hop.channel}`];
} else {
return [`${hop.channel}`, forward];
}
});
return cbk(null, {description: flatten(path)});
}],
},
returnResult({reject, resolve, of: 'description'}, cbk));
});
};

View file

@ -0,0 +1,80 @@
const asyncAuto = require('async/auto');
const {getNode} = require('ln-service');
const {returnResult} = require('asyncjs-util');
/** Get a description for a routing failure
{
index: <Failure Index Number>
lnd: <Authenticated LND API Object>
reason: <Failure Reason Code String>
route: {
hops: [{
channel: <Standard Format Channel Id String>
public_key: <Public Key Hex String>
}]
}
}
@returns via cbk or Promise
{
description: <Failure Description String>
}
*/
module.exports = ({index, lnd, reason, route}, cbk) => {
return new Promise((resolve, reject) => {
return asyncAuto({
// Check arguments
validate: cbk => {
if (index === undefined) {
return cbk([400, 'ExpectedIndexToDescribeRoutingFailure']);
}
if (!lnd) {
return cbk([400, 'ExpectedLndApiObjectToDescribeRoutingFailure']);
}
if (!reason) {
return cbk([400, 'ExpectedFailureReasonToDescribeRoutingFailure']);
}
if (!route) {
return cbk([400, 'ExpectedFailedRouteToDescribeRoutingFailure']);
}
return cbk();
},
// Get node alias
getAlias: ['validate', ({}, cbk) => {
const source = route.hops[index - [index].length];
if (!source) {
return cbk();
}
return getNode({
lnd,
is_omitting_channels: true,
public_key: source.public_key,
},
(err, res) => {
if (!!err) {
return cbk(null, source.public_key);
}
return cbk(null, res.alias || source.public_key);
});
}],
// Describe the routing failure
description: ['getAlias', ({getAlias}, cbk) => {
const at = `at ${route.hops[index].channel}`;
const from = !getAlias ? '' : `from ${getAlias}`;
return cbk(null, {description: `${reason} ${at} ${from}`});
}],
},
returnResult({reject, resolve, of: 'description'}, cbk));
});
};

View file

@ -1,6 +1,17 @@
const describeConfidence = require('./describe_confidence');
const describeRoute = require('./describe_route');
const describeRoutingFailure = require('./describe_routing_failure');
const formatFeeRate = require('./format_fee_rate');
const formatTokens = require('./format_tokens');
const segmentMeasure = require('./segment_measure');
const sumsForSegment = require('./sums_for_segment');
module.exports = {formatFeeRate, formatTokens, segmentMeasure, sumsForSegment};
module.exports = {
describeConfidence,
describeRoute,
describeRoutingFailure,
formatFeeRate,
formatTokens,
segmentMeasure,
sumsForSegment,
};

View file

@ -5,7 +5,7 @@ const {returnResult} = require('asyncjs-util');
const {subscribeToProbe} = require('ln-service');
const {subscribeToProbeForRoute} = require('ln-service');
const {describeConfidence} = require('./../routing');
const {describeConfidence} = require('./../display');
const {now} = Date;
const minutesAsMs = minutes => 1000 * 60 * minutes;

View file

@ -2,16 +2,23 @@ const asyncAuto = require('async/auto');
const asyncMap = require('async/map');
const asyncWhilst = require('async/whilst');
const {getChannel} = require('ln-service');
const {getNode} = require('ln-service');
const {getWalletInfo} = require('ln-service');
const {getWalletVersion} = require('ln-service');
const {parsePaymentRequest} = require('ln-service');
const {payViaRoutes} = require('ln-service');
const {returnResult} = require('asyncjs-util');
const {subscribeToMultiPathProbe} = require('probing');
const {describeRoute} = require('./../display');
const {describeRoutingFailure} = require('./../display');
const multiPathProbe = require('./multi_path_probe');
const probeDestination = require('./probe_destination');
const defaultFinalCltvDelta = 144;
const defaultMaxPaths = 5;
const flatten = arr => [].concat(...arr);
const pathTimeoutMs = 1000 * 60 * 5;
const uniq = arr => Array.from(new Set(arr));
/** Probe a destination, looking for multiple non-overlapping paths
@ -53,6 +60,14 @@ module.exports = (args, cbk) => {
return cbk([400, 'ExpectedLoggerObjectToStartProbe']);
}
if (!!args.request) {
try {
parsePaymentRequest({request: args.request});
} catch (err) {
return cbk([400, 'ExpectedValidPaymentRequestToProbe', {err}]);
}
}
return cbk();
},
@ -72,86 +87,107 @@ module.exports = (args, cbk) => {
});
}],
// Probe iteratively through multiple paths
multiProbe: ['checkLegacy', ({}, cbk) => {
// Decode payment request
decodeRequest: ['validate', ({}, cbk) => {
// Exit early and only single probe when not finding maximum
if (!args.find_max) {
return cbk();
}
let error;
const probes = [];
if (!args.request) {
return cbk(null, {});
}
return asyncWhilst(
cbk => {
if ((args.max_paths || defaultMaxPaths) === probes.length) {
return cbk(null, false);
}
const decoded = parsePaymentRequest({request: args.request});
return cbk(null, !error);
},
cbk => {
return multiPathProbe({
destination: args.destination,
find_max: args.find_max,
ignore: args.ignore,
in_through: args.in_through,
lnd: args.lnd,
logger: args.logger,
out_through: args.out_through,
probes: probes.filter(n => !!n),
request: args.request,
timeout_minutes: args.timeout_minutes,
tokens: args.tokens,
},
(err, res) => {
if (!!err) {
return cbk(err);
}
return cbk(null, {
cltv_delta: decodeRequest.cltv_delta,
destination: decodeRequest.destination,
features: decodeRequest.features,
routes: decodeRequest.routes,
});
}],
if (!!res.error) {
error = res.error;
} else {
probes.push(res.probe || null);
}
// Get probe destination name
getDestination: ['decodeRequest', ({decodeRequest}, cbk) => {
const publicKey = decodeRequest.destination || args.destination;
return cbk();
});
},
err => {
if (!!err) {
return cbk(err);
}
const completed = probes.filter(n => !!n);
if (!completed.length) {
return cbk(error);
}
const latencyMs = completed
.map(n => n.latency_ms)
.filter(n => !!n)
.reduce((sum, n) => sum + n, Number());
const max = completed
.map(n => n.route_maximum || Number())
.reduce((sum, n) => sum + n, Number());
return cbk(null, {
latency_ms: latencyMs,
probes: completed.map(probe => {
return {
channels: probe.success,
fee: probe.fee,
liquidity: probe.route_maximum,
relays: probe.relays,
};
}),
routes_max: max,
});
return getNode({
is_omitting_channels: true,
lnd: args.lnd,
public_key: publicKey,
},
(err, res) => {
if (!!err) {
return cbk(null, publicKey);
}
);
return cbk(null, `${res.alias} ${publicKey}`.trim());
});
}],
// Probe iteratively through multiple paths
multiProbe: [
'checkLegacy',
'decodeRequest',
'getDestination',
({decodeRequest, getDestination}, cbk) =>
{
// Exit early and only single probe when not finding maximum
if (!args.find_max) {
return cbk();
}
if (!!args.out_through) {
return cbk([501, 'FindMaxThroughOutPeerNotSupported']);
}
args.logger.info({probing: getDestination});
const sub = subscribeToMultiPathProbe({
cltv_delta: decodeRequest.cltv_delta || defaultFinalCltvDelta,
destination: decodeRequest.destination || args.destination,
features: decodeRequest.features,
ignore: args.ignore,
incoming_peer: args.in_through,
lnd: args.lnd,
max_paths: args.max_paths,
path_timeout_ms: pathTimeoutMs,
routes: decodeRequest.routes,
});
sub.on('error', err => cbk(err));
sub.on('evaluating', ({tokens}) => {
return args.logger.info({evaluating: tokens});
});
sub.on('failure', () => {
return cbk([503, 'FailedToFindAnyPathsToDestination']);
});
sub.on('probing', async ({route}) => {
const {description} = await describeRoute({route, lnd: args.lnd});
return args.logger.info({probing: description});
});
sub.on('routing_failure', async failure => {
const {description} = await describeRoutingFailure({
index: failure.index,
lnd: args.lnd,
reason: failure.reason,
route: failure.route,
});
return args.logger.info({failure: description});
});
sub.on('success', ({paths}) => {
return args.logger.info({paths});
});
return;
}],
// Probe just through a single path

View file

@ -13,7 +13,6 @@ const {returnResult} = require('asyncjs-util');
const {signBytes} = require('ln-service');
const {subscribeToFindMaxPayable} = require('probing');
const {authenticatedLnd} = require('./../lnd');
const executeProbe = require('./execute_probe');
const {getInboundPath} = require('./../routing');
const {sortBy} = require('./../arrays');

148
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "balanceofsatoshis",
"version": "5.41.3",
"version": "5.41.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1930,9 +1930,9 @@
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"asciichart": {
"version": "1.5.23",
"resolved": "https://registry.npmjs.org/asciichart/-/asciichart-1.5.23.tgz",
"integrity": "sha512-osTjxKgD3NrnzGNP1ePWTssJQxCir4r2D8Xkg9IaRBuePWOK2hHodWxJ5SejW0VKD92Cf5IKglJ0N4WWgBOEcg=="
"version": "1.5.24",
"resolved": "https://registry.npmjs.org/asciichart/-/asciichart-1.5.24.tgz",
"integrity": "sha512-ZvIF1uIvSsRnIygcjq9NnMUoZKGONF9bowhmHr7N/qkR34lkvEDWc/HEzmYp4osVC4/dkGEAHEAiqB2uJs+a+w=="
},
"ascli": {
"version": "1.0.1",
@ -3310,18 +3310,18 @@
"dev": true
},
"flow-parser": {
"version": "0.129.0",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.129.0.tgz",
"integrity": "sha512-kzxyoEl8vG0JF0/h/u0UjALXmsGvwU2NBfKczCSNO/It2fKb8hz1gMt05OuZAlMLYXcvgjntWJadIABeKGPK4g==",
"version": "0.130.0",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.130.0.tgz",
"integrity": "sha512-h9NATB7QsKhj2ucgEH2XzB7p+5ubk8IZX5u/qHkN+oyQoECi1diq6mYfIuYBOyL35f3AhJf/YDkBYQBTqqYK+w==",
"dev": true
},
"flow-remove-types": {
"version": "2.129.0",
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.129.0.tgz",
"integrity": "sha512-ucESHZUDQvEFzjRKstZMFBVIciRvXtKpVyPsJT+poIyOIxuPoCLiU/8HHnMBN9XHDWSJ2YJ91mv97n17NmI1Bg==",
"version": "2.130.0",
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.130.0.tgz",
"integrity": "sha512-x48wARPzBge8aRd0ZI3lQi59afHwVk7DymUIFf423bUfa3u1GJWOfpdHggPkN1f4R16oUH+YO4KldBz8Ce2ldg==",
"dev": true,
"requires": {
"flow-parser": "^0.129.0",
"flow-parser": "^0.130.0",
"pirates": "^3.0.2",
"vlq": "^0.2.1"
}
@ -3504,6 +3504,28 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz",
"integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA=="
},
"ln-service": {
"version": "49.4.0",
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-49.4.0.tgz",
"integrity": "sha512-juevEKbdDBZOFq5MtmsUULecy8AUTogEGisoWDm4H0mtoaz8uS3TtJUsZR88g+KKfvgD++OpwMMngV3VRW7kvQ==",
"requires": {
"@datastructures-js/priority-queue": "4.1.1",
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bitcoinjs-lib": "5.1.10",
"bn.js": "5.1.2",
"bolt07": "1.5.2",
"bolt09": "0.1.1",
"cors": "2.8.5",
"express": "4.17.1",
"invoices": "1.1.1",
"is-base64": "1.1.0",
"lightning": "2.0.29",
"macaroon": "3.0.4",
"morgan": "1.10.0",
"ws": "7.3.1"
}
}
}
},
@ -3764,9 +3786,9 @@
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inquirer": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.2.tgz",
"integrity": "sha512-DF4osh1FM6l0RJc5YWYhSDB6TawiBRlbV9Cox8MWlidU218Tb7fm3lQTULyUJDfJ0tjbzl0W4q651mrCCEM55w==",
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
"integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
"requires": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.0",
@ -3774,7 +3796,7 @@
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.16",
"lodash": "^4.17.19",
"mute-stream": "0.0.8",
"run-async": "^2.4.0",
"rxjs": "^6.6.0",
@ -4623,9 +4645,9 @@
}
},
"ln-service": {
"version": "49.4.0",
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-49.4.0.tgz",
"integrity": "sha512-juevEKbdDBZOFq5MtmsUULecy8AUTogEGisoWDm4H0mtoaz8uS3TtJUsZR88g+KKfvgD++OpwMMngV3VRW7kvQ==",
"version": "49.4.1",
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-49.4.1.tgz",
"integrity": "sha512-u3Ej2xVQGkkH98XfVmk8utjJVtpuZ0QtpZMFey8XwQqdopFpBjpgRGeSrGSrx52TxblCTEUznhB4Ou9+8bRtPg==",
"requires": {
"@datastructures-js/priority-queue": "4.1.1",
"async": "3.2.0",
@ -4638,7 +4660,7 @@
"express": "4.17.1",
"invoices": "1.1.1",
"is-base64": "1.1.0",
"lightning": "2.0.29",
"lightning": "2.0.30",
"macaroon": "3.0.4",
"morgan": "1.10.0",
"ws": "7.3.1"
@ -4648,6 +4670,25 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz",
"integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA=="
},
"lightning": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/lightning/-/lightning-2.0.30.tgz",
"integrity": "sha512-XZFefXdOE4kPa/C533MwnTpgfidwM6M9s0Mtg7U0jmDA5dRB9VmMU8zssBAeo+cZ46fXEx7fz4lXLGQ6V7opUw==",
"requires": {
"@grpc/proto-loader": "0.5.5",
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bitcoinjs-lib": "5.1.10",
"bn.js": "5.1.2",
"body-parser": "1.19.0",
"bolt07": "1.5.2",
"bolt09": "0.1.1",
"cbor": "5.0.2",
"express": "4.17.1",
"grpc": "1.24.3",
"invoices": "1.1.1"
}
}
}
},
@ -5798,62 +5839,15 @@
}
},
"probing": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/probing/-/probing-1.0.1.tgz",
"integrity": "sha512-llIRWvdX7I3PLDXDrUjYCSwYFuMKqHX3qFYA58qba8CRJt9FRfucPcpI84MdVS9NzpehRibKAvDm89+xzhfBLg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/probing/-/probing-1.1.0.tgz",
"integrity": "sha512-TPks2aMOIkB1o2OOOISkQLlQjqYDWj7X9A5f2Fh1gFJxu2NOUpRXyJImd54EkuewQ+sEWFSUryE7q2iorpjC3w==",
"requires": {
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bolt07": "1.5.2",
"invoices": "1.1.1",
"ln-service": "49.3.7"
},
"dependencies": {
"bn.js": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz",
"integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA=="
},
"lightning": {
"version": "2.0.28",
"resolved": "https://registry.npmjs.org/lightning/-/lightning-2.0.28.tgz",
"integrity": "sha512-nx3HPpJncS/c8BnvCwX8jEbePFzrj+gVk47VZtuYYWKTrZPn2PHqTOBnCVbHM9rkjeJjJuT3074n4pmSWpTAcw==",
"requires": {
"@grpc/proto-loader": "0.5.5",
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bitcoinjs-lib": "5.1.10",
"bn.js": "5.1.2",
"body-parser": "1.19.0",
"bolt07": "1.5.2",
"bolt09": "0.1.1",
"cbor": "5.0.2",
"express": "4.17.1",
"grpc": "1.24.3",
"invoices": "1.1.1"
}
},
"ln-service": {
"version": "49.3.7",
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-49.3.7.tgz",
"integrity": "sha512-UPWF9oJowvU6GQLkXQTM7c7Og3N1BipK+Brd4vImqXONHZTE9514UKawqpi+JU8FwNlzB75A3PgqFFbiTZriUQ==",
"requires": {
"@datastructures-js/priority-queue": "4.1.1",
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bitcoinjs-lib": "5.1.10",
"bn.js": "5.1.2",
"bolt07": "1.5.2",
"bolt09": "0.1.1",
"cors": "2.8.5",
"express": "4.17.1",
"invoices": "1.1.1",
"is-base64": "1.1.0",
"lightning": "2.0.28",
"macaroon": "3.0.4",
"morgan": "1.10.0",
"ws": "7.3.1"
}
}
"ln-service": "49.4.1"
}
},
"process-nextick-args": {
@ -5893,9 +5887,9 @@
},
"dependencies": {
"@types/node": {
"version": "13.13.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.14.tgz",
"integrity": "sha512-Az3QsOt1U/K1pbCQ0TXGELTuTkPLOiFIQf3ILzbOyo0FqgV9SxRnxbxM5QlAveERZMHpZY+7u3Jz2tKyl+yg6g=="
"version": "13.13.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz",
"integrity": "sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw=="
}
}
},
@ -6750,9 +6744,9 @@
}
},
"tap-parser": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.0.1.tgz",
"integrity": "sha512-qdT15H0DoJIi7zOqVXDn9X0gSM68JjNy1w3VemwTJlDnETjbi6SutnqmBfjDJAwkFS79NJ97gZKqie00ZCGmzg==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.1.0.tgz",
"integrity": "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==",
"dev": true,
"requires": {
"events-to-array": "^1.0.1",

View file

@ -12,7 +12,7 @@
"dependencies": {
"@alexbosworth/html2unicode": "1.1.5",
"@alexbosworth/request": "2.88.3",
"asciichart": "1.5.23",
"asciichart": "1.5.24",
"async": "3.2.0",
"asyncjs-util": "1.2.3",
"bitcoin-ops": "1.4.1",
@ -27,12 +27,12 @@
"csv-parse": "4.11.1",
"goldengate": "6.0.0",
"ini": "1.3.5",
"inquirer": "7.3.2",
"inquirer": "7.3.3",
"ln-accounting": "4.1.7",
"ln-service": "49.4.0",
"ln-service": "49.4.1",
"ln-sync": "0.0.9",
"moment": "2.27.0",
"probing": "1.0.1",
"probing": "1.1.0",
"psbt": "1.1.4",
"qrcode-terminal": "0.12.0",
"sanitize-filename": "1.6.3",
@ -65,7 +65,7 @@
"url": "https://github.com/alexbosworth/balanceofsatoshis.git"
},
"scripts": {
"test": "tap test/arrays/*.js test/balances/*.js test/chain/*.js test/encryption/*.js test/fiat/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/responses/*.js test/routing/*.js test/swaps/*.js test/telegram/*.js test/wallets/*.js"
"test": "tap test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/fiat/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/responses/*.js test/routing/*.js test/swaps/*.js test/telegram/*.js test/wallets/*.js"
},
"version": "5.41.3"
"version": "5.41.4"
}

View file

@ -70,6 +70,10 @@ module.exports = ({channels, lnd, query}, cbk) => {
return cbk();
}
if (!query.toLowerCase) {
return cbk([400, 'InvalidEmptyQuerySpecifiedForMatchSearchQuery']);
}
const keys = uniq(getChannels.channels.map(n => n.partner_public_key));
const q = query.toLowerCase();

View file

@ -1,7 +1,6 @@
const adjustFees = require('./adjust_fees');
const channelForGift = require('./channel_for_gift');
const channelsFromHints = require('./channels_from_hints');
const describeConfidence = require('./describe_confidence');
const getFeesChart = require('./get_fees_chart');
const getFeesPaid = require('./get_fees_paid');
const getInboundPath = require('./get_inbound_path');
@ -13,7 +12,6 @@ module.exports = {
adjustFees,
channelForGift,
channelsFromHints,
describeConfidence,
getFeesChart,
getFeesPaid,
getInboundPath,

View file

@ -129,7 +129,7 @@ module.exports = (args, cbk) => {
const rate = getUpdated.policies.find(n => n.public_key === args.from);
if (rate.fee_rate !== args.fee_rate) {
return cbk([503, 'FailedToUpdateChannelPolicyToNewFeeRate']);
return cbk([503, 'FailedToUpdateChannelPolicyToNewFeeRate', {rate}]);
}
return cbk();

View file

@ -397,7 +397,7 @@ module.exports = (args, cbk) => {
({getLimits, startHeight}, cbk) =>
{
// Exit early when the swap is already started
if (!!args.recover) {
if (!!args.recovery) {
return cbk();
}

View file

@ -1,6 +1,6 @@
const {test} = require('@alexbosworth/tap');
const {describeConfidence} = require('./../../routing');
const {describeConfidence} = require('./../../display');
const tests = [
{