balanceofsatoshis 23.1.7 → 23.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/bos +4 -3
- package/package.json +8 -8
- package/peers/find_peer_match.js +109 -0
- package/peers/find_tag_match.js +22 -78
- package/swaps/find_rebalance_peer.js +149 -0
- package/swaps/get_avoid_list.js +53 -0
- package/swaps/manage_rebalance.js +71 -37
- package/swaps/rebalance.js +20 -73
- package/swaps/write_avoid_list.js +68 -0
- package/test/peers/test_find_tag_match.js +8 -1
- package/test/swaps/test_find_rebalance_peer.js +329 -0
- package/test/swaps/test_get_avoid_list.js +62 -0
- package/test/swaps/test_write_avoid_list.js +83 -0
package/CHANGELOG.md
CHANGED
package/bos
CHANGED
|
@@ -4,6 +4,7 @@ const {lstat} = require('fs');
|
|
|
4
4
|
const {mkdir} = require('fs');
|
|
5
5
|
const {readdir} = require('fs');
|
|
6
6
|
const {readFile} = require('fs');
|
|
7
|
+
const {rename} = require('fs');
|
|
7
8
|
const {rmdir} = require('fs');
|
|
8
9
|
const {spawn} = require('child_process');
|
|
9
10
|
const {statSync} = require('fs');
|
|
@@ -1734,7 +1735,7 @@ prog
|
|
|
1734
1735
|
.option('--avoid-high-fee-routes', 'Avoid trying routes above max-fee-rate')
|
|
1735
1736
|
.option('--avoid-list', 'Path to file with newline separated list of avoids')
|
|
1736
1737
|
.option('--in <pubkey_or_alias>', 'Route in through a specific peer')
|
|
1737
|
-
.option('--in-filter <in_filter>', 'Filter inbound tag
|
|
1738
|
+
.option('--in-filter <in_filter>', 'Filter inbound peer/tag', REPEATABLE)
|
|
1738
1739
|
.option('--in-target-outbound <amt>', 'Balance up to outbound amount')
|
|
1739
1740
|
.option('--max-fee <max_fee>', 'Maximum fee to pay')
|
|
1740
1741
|
.option('--max-fee-rate <max_fee_rate>', 'Max fee rate to pay')
|
|
@@ -1742,7 +1743,7 @@ prog
|
|
|
1742
1743
|
.option('--no-color', 'Mute all colors')
|
|
1743
1744
|
.option('--node <node_name>', 'Saved node to use for rebalance')
|
|
1744
1745
|
.option('--out <pubkey_or_alias>', 'Route out through a specific peer')
|
|
1745
|
-
.option('--out-filter <out_filter>', 'Filter outbound tag
|
|
1746
|
+
.option('--out-filter <out_filter>', 'Filter outbound peer/tag', REPEATABLE)
|
|
1746
1747
|
.option('--out-target-inbound <amount>', 'Balance up to inbound amount')
|
|
1747
1748
|
.action((args, options, logger) => {
|
|
1748
1749
|
return new Promise(async (resolve, reject) => {
|
|
@@ -1752,7 +1753,7 @@ prog
|
|
|
1752
1753
|
avoid: flatten([options.avoid].filter(n => !!n)),
|
|
1753
1754
|
avoid_append: options.avoidAppend || undefined,
|
|
1754
1755
|
avoid_list: options.avoidList || undefined,
|
|
1755
|
-
fs: {appendFile, writeFile, getFile: readFile},
|
|
1756
|
+
fs: {appendFile, writeFile, getFile: readFile, renameFile: rename},
|
|
1756
1757
|
in_filters: flatten([options.inFilter].filter(n => !!n)),
|
|
1757
1758
|
in_outbound: options.inTargetOutbound || undefined,
|
|
1758
1759
|
in_through: options.in || undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"allowScripts": {
|
|
3
|
-
"protobufjs@7.6.
|
|
3
|
+
"protobufjs@7.6.6": true,
|
|
4
4
|
"ssh2@1.17.0": true,
|
|
5
5
|
"cpu-features@0.0.10": true
|
|
6
6
|
},
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"url": "https://github.com/alexbosworth/balanceofsatoshis/issues"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@alexbosworth/blockchain": "4.5.
|
|
18
|
+
"@alexbosworth/blockchain": "4.5.3",
|
|
19
19
|
"@alexbosworth/caporal": "2.0.0",
|
|
20
20
|
"@alexbosworth/fiat": "2.0.0",
|
|
21
21
|
"@alexbosworth/formulas": "1.4.0",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"colorette": "2.0.20",
|
|
36
36
|
"csv-parse": "7.0.2",
|
|
37
37
|
"goldengate": "16.0.6",
|
|
38
|
-
"grammy": "1.
|
|
38
|
+
"grammy": "1.46.0",
|
|
39
39
|
"import-lazy": "4.0.0",
|
|
40
40
|
"ini": "7.0.0",
|
|
41
|
-
"inquirer": "14.
|
|
41
|
+
"inquirer": "14.2.0",
|
|
42
42
|
"ln-accounting": "10.0.5",
|
|
43
|
-
"ln-service": "59.3.
|
|
44
|
-
"ln-sync": "8.0.
|
|
43
|
+
"ln-service": "59.3.5",
|
|
44
|
+
"ln-sync": "8.0.6",
|
|
45
45
|
"ln-telegram": "8.0.5",
|
|
46
46
|
"moment": "2.30.1",
|
|
47
47
|
"paid-services": "8.0.6",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"description": "Lightning balance CLI",
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"invoices": "6.1.
|
|
58
|
+
"invoices": "6.1.4",
|
|
59
59
|
"ln-docker-daemons": "8.0.4"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64 -t alexbosworth/balanceofsatoshis -t alexbosworth/balanceofsatoshis:$npm_package_version --push .",
|
|
84
84
|
"test": "node --experimental-test-coverage --test test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/tags/*.js test/telegram/*.js test/wallets/*.js"
|
|
85
85
|
},
|
|
86
|
-
"version": "23.1.
|
|
86
|
+
"version": "23.1.9"
|
|
87
87
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const {decodeChanId} = require('bolt07');
|
|
2
|
+
|
|
3
|
+
const {shuffle} = require('./../arrays');
|
|
4
|
+
const {isMatchingFilters} = require('./../display');
|
|
5
|
+
|
|
6
|
+
const channelHeight = channel => decodeChanId({channel}).block_height;
|
|
7
|
+
const {max} = Math;
|
|
8
|
+
const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
|
|
9
|
+
const tok = n => Number(BigInt(n) / BigInt(1e3));
|
|
10
|
+
const uniq = arr => Array.from(new Set(arr));
|
|
11
|
+
|
|
12
|
+
/** Find a peer that matches filters
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
channels: [{
|
|
16
|
+
capacity: <Channel Token Capacity Number>
|
|
17
|
+
id: <Standard Format Channel Id String>
|
|
18
|
+
local_balance: <Channel Local Balance Tokens Number>
|
|
19
|
+
partner_public_key: <Peer Public Key Hex String>
|
|
20
|
+
pending_payments: [<Pending Payment Object>]
|
|
21
|
+
remote_balance: <Channel Remote Balance Tokens Number>
|
|
22
|
+
}]
|
|
23
|
+
[filters]: [<Filter Expression String>]
|
|
24
|
+
policies: [{
|
|
25
|
+
[base_fee_mtokens]: <Remote Base Fee Charged In Millitokens Number>
|
|
26
|
+
[fee_rate]: <Remote Fees Charged in Millitokens Per Million Number>
|
|
27
|
+
[is_disabled]: <Remote Channel Forwarding Is Disabled Bool>
|
|
28
|
+
public_key: <Remote Public Key Hex String>
|
|
29
|
+
}]
|
|
30
|
+
nodes: [<Candidate Peer Public Key Hex String>]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@returns
|
|
34
|
+
{
|
|
35
|
+
[failure]: {
|
|
36
|
+
error: <Error String>
|
|
37
|
+
formula: <Errored Formula String>
|
|
38
|
+
}
|
|
39
|
+
[match]: <Matching Peer Public Key Hex String>
|
|
40
|
+
}
|
|
41
|
+
*/
|
|
42
|
+
module.exports = ({channels, filters, nodes, policies}) => {
|
|
43
|
+
const disabled = policies.filter(n => n.is_disabled).map(n => n.public_key);
|
|
44
|
+
|
|
45
|
+
const peers = channels.map(n => n.partner_public_key)
|
|
46
|
+
.filter(n => !disabled.includes(n));
|
|
47
|
+
|
|
48
|
+
const candidates = uniq((nodes || [])
|
|
49
|
+
.filter(n => peers.includes(n)));
|
|
50
|
+
|
|
51
|
+
// Filter out peers that do not fulfill the supplied criteria
|
|
52
|
+
const candidateResults = candidates
|
|
53
|
+
.map(key => {
|
|
54
|
+
if (!filters || !filters.length) {
|
|
55
|
+
return {match: key};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const peerPolicies = policies.filter(n => n.public_key === key);
|
|
59
|
+
const withPeer = channels.filter(n => n.partner_public_key === key);
|
|
60
|
+
|
|
61
|
+
const feeRates = peerPolicies.filter(n => n.fee_rate !== undefined);
|
|
62
|
+
const pendingPayments = withPeer.map(n => n.pending_payments.length);
|
|
63
|
+
|
|
64
|
+
const maxBaseFee = max(...feeRates.map(n => tok(n.base_fee_mtokens)));
|
|
65
|
+
const maxFeeRate = max(...feeRates.map(n => n.fee_rate));
|
|
66
|
+
|
|
67
|
+
const variables = {
|
|
68
|
+
capacity: sumOf(withPeer.map(n => n.capacity)),
|
|
69
|
+
heights: withPeer.map(n => channelHeight(n.id)),
|
|
70
|
+
inbound_liquidity: sumOf(withPeer.map(n => n.remote_balance)),
|
|
71
|
+
outbound_liquidity: sumOf(withPeer.map(n => n.local_balance)),
|
|
72
|
+
pending_payments: sumOf(pendingPayments),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (!!feeRates.length) {
|
|
76
|
+
variables.inbound_base_fee = maxBaseFee;
|
|
77
|
+
variables.inbound_fee_rate = maxFeeRate;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const matching = isMatchingFilters({variables, filters: filters || []});
|
|
81
|
+
|
|
82
|
+
if (!!matching.failure) {
|
|
83
|
+
return matching;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!matching.is_matching) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {match: key};
|
|
91
|
+
})
|
|
92
|
+
.filter(n => !!n);
|
|
93
|
+
|
|
94
|
+
// Exit early when there is no match
|
|
95
|
+
if (!candidateResults.length) {
|
|
96
|
+
return {};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Exit early when there is a failure in a candidate
|
|
100
|
+
if (!!candidateResults.find(n => !!n.failure)) {
|
|
101
|
+
return candidateResults.find(n => !!n.failure);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const {shuffled} = shuffle({array: candidateResults});
|
|
105
|
+
|
|
106
|
+
const [{match}] = shuffled;
|
|
107
|
+
|
|
108
|
+
return {match};
|
|
109
|
+
};
|
package/peers/find_tag_match.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const flatten = arr => [].concat(...arr);
|
|
4
|
-
const {shuffle} = require('./../arrays');
|
|
5
|
-
const {isMatchingFilters} = require('./../display');
|
|
6
|
-
|
|
7
|
-
const {max} = Math;
|
|
8
|
-
const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
|
|
9
|
-
const tok = n => Number(BigInt(n) / BigInt(1e3));
|
|
1
|
+
const findPeerMatch = require('./find_peer_match');
|
|
10
2
|
|
|
11
3
|
/** Find a node for a tag query
|
|
12
4
|
|
|
@@ -40,6 +32,7 @@ const tok = n => Number(BigInt(n) / BigInt(1e3));
|
|
|
40
32
|
formula: <Errored Formula String>
|
|
41
33
|
}
|
|
42
34
|
[match]: <Matching Node Public Key Hex String>
|
|
35
|
+
[is_tag_filtered]: <Tag Matched But All Nodes Failed Filters Bool>
|
|
43
36
|
[matches]: [{
|
|
44
37
|
[alias]: <Tag Alias String>
|
|
45
38
|
id: <Tag Id Hex String>
|
|
@@ -54,14 +47,8 @@ module.exports = ({channels, filters, policies, tags, query}) => {
|
|
|
54
47
|
.map(n => n.partner_public_key)
|
|
55
48
|
.filter(n => !disabled.includes(n));
|
|
56
49
|
|
|
57
|
-
// Find tags that match on id or on alias
|
|
58
|
-
const
|
|
59
|
-
const nodes = (tag.nodes || []).filter(n => peerKeys.includes(n));
|
|
60
|
-
|
|
61
|
-
if (!nodes.length) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
50
|
+
// Find tags that match on id or on alias
|
|
51
|
+
const tagMatches = tags.filter(tag => {
|
|
65
52
|
const alias = tag.alias || String();
|
|
66
53
|
|
|
67
54
|
const isAliasMatch = alias.toLowerCase() === (query || '').toLowerCase();
|
|
@@ -70,9 +57,18 @@ module.exports = ({channels, filters, policies, tags, query}) => {
|
|
|
70
57
|
return isAliasMatch || isIdMatch;
|
|
71
58
|
});
|
|
72
59
|
|
|
60
|
+
// Limit tag matches to tags with relevant peers
|
|
61
|
+
const matches = tagMatches.filter(tag => {
|
|
62
|
+
return (tag.nodes || []).some(n => peerKeys.includes(n));
|
|
63
|
+
});
|
|
64
|
+
|
|
73
65
|
const [tagMatch, ...otherTagMatches] = matches;
|
|
74
66
|
|
|
75
67
|
// Exit early when there are no matches at all
|
|
68
|
+
if (!tagMatch && !!tagMatches.length && !!filters && !!filters.length) {
|
|
69
|
+
return {is_tag_filtered: true};
|
|
70
|
+
}
|
|
71
|
+
|
|
76
72
|
if (!tagMatch) {
|
|
77
73
|
return {};
|
|
78
74
|
}
|
|
@@ -82,68 +78,16 @@ module.exports = ({channels, filters, policies, tags, query}) => {
|
|
|
82
78
|
return {matches};
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!filters || !filters.length) {
|
|
92
|
-
return {match: key};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const peerPolicies = policies.filter(n => n.public_key === key);
|
|
96
|
-
const withPeer = channels.filter(n => n.partner_public_key === key);
|
|
97
|
-
|
|
98
|
-
const feeRates = peerPolicies.filter(n => n.fee_rate !== undefined);
|
|
99
|
-
const pendingPayments = withPeer.map(n => n.pending_payments.length);
|
|
100
|
-
|
|
101
|
-
const maxBaseFee = max(...feeRates.map(n => tok(n.base_fee_mtokens)));
|
|
102
|
-
const maxFeeRate = max(...feeRates.map(n => n.fee_rate));
|
|
103
|
-
|
|
104
|
-
const variables = {
|
|
105
|
-
capacity: sumOf(withPeer.map(n => n.capacity)),
|
|
106
|
-
heights: withPeer.map(n => {
|
|
107
|
-
return decodeChanId({channel: n.id}).block_height;
|
|
108
|
-
}),
|
|
109
|
-
inbound_liquidity: sumOf(withPeer.map(n => n.remote_balance)),
|
|
110
|
-
outbound_liquidity: sumOf(withPeer.map(n => n.local_balance)),
|
|
111
|
-
pending_payments: sumOf(pendingPayments),
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
if (!!feeRates.length) {
|
|
115
|
-
variables.inbound_base_fee = maxBaseFee;
|
|
116
|
-
variables.inbound_fee_rate = maxFeeRate;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const matching = isMatchingFilters({variables, filters: filters || []});
|
|
120
|
-
|
|
121
|
-
if (!!matching.failure) {
|
|
122
|
-
return matching;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (!matching.is_matching) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return {match: key};
|
|
130
|
-
})
|
|
131
|
-
.filter(n => !!n);
|
|
132
|
-
|
|
133
|
-
// Exit early when there is no match
|
|
134
|
-
if (!array.length) {
|
|
135
|
-
return {};
|
|
136
|
-
}
|
|
81
|
+
const {failure, match} = findPeerMatch({
|
|
82
|
+
channels,
|
|
83
|
+
filters,
|
|
84
|
+
policies,
|
|
85
|
+
nodes: tagMatch.nodes.filter(n => peerKeys.includes(n)),
|
|
86
|
+
});
|
|
137
87
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return array.find(n => !!n.failure);
|
|
88
|
+
if (!failure && !match && !!filters && !!filters.length) {
|
|
89
|
+
return {is_tag_filtered: true};
|
|
141
90
|
}
|
|
142
91
|
|
|
143
|
-
|
|
144
|
-
const {shuffled} = shuffle({array});
|
|
145
|
-
|
|
146
|
-
const [{match}] = shuffled;
|
|
147
|
-
|
|
148
|
-
return {match};
|
|
92
|
+
return {failure, match};
|
|
149
93
|
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {findKey} = require('ln-sync');
|
|
3
|
+
const {returnResult} = require('asyncjs-util');
|
|
4
|
+
|
|
5
|
+
const findPeerMatch = require('./../peers/find_peer_match');
|
|
6
|
+
const findTagMatch = require('./../peers/find_tag_match');
|
|
7
|
+
|
|
8
|
+
/** Find a peer for a rebalance
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
active_channels: [{
|
|
12
|
+
capacity: <Channel Token Capacity Number>
|
|
13
|
+
id: <Standard Format Channel Id String>
|
|
14
|
+
local_balance: <Channel Local Balance Tokens Number>
|
|
15
|
+
partner_public_key: <Peer Public Key Hex String>
|
|
16
|
+
pending_payments: [<Pending Payment Object>]
|
|
17
|
+
remote_balance: <Channel Remote Balance Tokens Number>
|
|
18
|
+
}]
|
|
19
|
+
channels: [{
|
|
20
|
+
partner_public_key: <Peer Public Key Hex String>
|
|
21
|
+
}]
|
|
22
|
+
direction: <In or Out Direction String>
|
|
23
|
+
[filters]: [<Peer Filter Formula String>]
|
|
24
|
+
lnd: <Authenticated LND API Object>
|
|
25
|
+
policies: [{
|
|
26
|
+
[base_fee_mtokens]: <Remote Base Fee Charged In Millitokens Number>
|
|
27
|
+
[fee_rate]: <Remote Fees Charged in Millitokens Per Million Number>
|
|
28
|
+
[is_disabled]: <Remote Channel Forwarding Is Disabled Bool>
|
|
29
|
+
public_key: <Remote Public Key Hex String>
|
|
30
|
+
}]
|
|
31
|
+
[query]: <Tag, Public Key, or Alias String>
|
|
32
|
+
tags: [{
|
|
33
|
+
[alias]: <Tag Alias String>
|
|
34
|
+
id: <Tag Id Hex String>
|
|
35
|
+
[nodes]: [<Public Key Hex String>]
|
|
36
|
+
}]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@returns via cbk or Promise
|
|
40
|
+
{
|
|
41
|
+
[public_key]: <Peer Public Key Hex String>
|
|
42
|
+
}
|
|
43
|
+
*/
|
|
44
|
+
module.exports = (args, cbk) => {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
return asyncAuto({
|
|
47
|
+
// Check arguments
|
|
48
|
+
validate: cbk => {
|
|
49
|
+
if (args.direction !== 'in' && args.direction !== 'out') {
|
|
50
|
+
return cbk([400, 'ExpectedInOrOutDirectionToFindRebalancePeer']);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return cbk();
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
// Find a tag, preserving tag precedence over peer aliases
|
|
57
|
+
tag: ['validate', ({}, cbk) => {
|
|
58
|
+
const filters = args.filters || [];
|
|
59
|
+
|
|
60
|
+
if (!args.query && !!filters.length) {
|
|
61
|
+
if (args.direction === 'in') {
|
|
62
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyInboundFilter']);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyOutboundFilter']);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const {failure, is_tag_filtered, match, matches} = findTagMatch({
|
|
69
|
+
filters,
|
|
70
|
+
channels: args.active_channels,
|
|
71
|
+
policies: args.policies,
|
|
72
|
+
query: args.query,
|
|
73
|
+
tags: args.tags,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (!!failure) {
|
|
77
|
+
return cbk([400, 'FailedToParseFilter', failure]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!!matches) {
|
|
81
|
+
if (args.direction === 'in') {
|
|
82
|
+
return cbk([400, 'MultipleTagMatchesFoundForInPeer', {matches}]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return cbk([400, 'MultipleTagMatchesFoundForOutPeer', {matches}]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!!is_tag_filtered && args.direction === 'in') {
|
|
89
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyInboundFilter']);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!!is_tag_filtered) {
|
|
93
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyOutboundFilter']);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!!match) {
|
|
97
|
+
return cbk(null, {public_key: match});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return cbk();
|
|
101
|
+
}],
|
|
102
|
+
|
|
103
|
+
// Resolve a public key or node alias when the query was not a tag
|
|
104
|
+
key: ['tag', ({tag}, cbk) => {
|
|
105
|
+
if (!!tag) {
|
|
106
|
+
return cbk(null, tag);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return findKey({
|
|
110
|
+
lnd: args.lnd,
|
|
111
|
+
channels: args.channels,
|
|
112
|
+
query: args.query,
|
|
113
|
+
},
|
|
114
|
+
cbk);
|
|
115
|
+
}],
|
|
116
|
+
|
|
117
|
+
// Apply filters to the single explicitly resolved peer
|
|
118
|
+
peer: ['key', 'tag', ({key, tag}, cbk) => {
|
|
119
|
+
const filters = args.filters || [];
|
|
120
|
+
|
|
121
|
+
if (!!tag || !filters.length) {
|
|
122
|
+
return cbk(null, key);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const {failure, match} = findPeerMatch({
|
|
126
|
+
filters,
|
|
127
|
+
channels: args.active_channels,
|
|
128
|
+
nodes: [key.public_key.toLowerCase()],
|
|
129
|
+
policies: args.policies,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (!!failure) {
|
|
133
|
+
return cbk([400, 'FailedToParseFilter', failure]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!match && args.direction === 'in') {
|
|
137
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyInboundFilter']);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!match) {
|
|
141
|
+
return cbk([400, 'NoPeerMatchesFoundToSatisfyOutboundFilter']);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return cbk(null, {public_key: match});
|
|
145
|
+
}],
|
|
146
|
+
},
|
|
147
|
+
returnResult({reject, resolve, of: 'peer'}, cbk));
|
|
148
|
+
});
|
|
149
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
|
|
4
|
+
const matchNewLines = /\r?\n/;
|
|
5
|
+
const trim = n => n.trim();
|
|
6
|
+
const uniq = arr => Array.from(new Set(arr));
|
|
7
|
+
|
|
8
|
+
/** Get the list of avoid directives from an avoid list file
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
fs: {
|
|
12
|
+
getFile: <Read File Contents Function> (path, cbk) => {}
|
|
13
|
+
}
|
|
14
|
+
path: <Path To Avoid List File String>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@returns via cbk or Promise
|
|
18
|
+
{
|
|
19
|
+
lines: [<Avoid Directive Line String>]
|
|
20
|
+
}
|
|
21
|
+
*/
|
|
22
|
+
module.exports = ({fs, path}, cbk) => {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
return asyncAuto({
|
|
25
|
+
// Check arguments
|
|
26
|
+
validate: cbk => {
|
|
27
|
+
if (!fs) {
|
|
28
|
+
return cbk([400, 'ExpectedFilesystemMethodsToGetAvoidList']);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!path) {
|
|
32
|
+
return cbk([400, 'ExpectedPathToAvoidListFileToGetAvoidList']);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return cbk();
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Get the lines of the avoid list file
|
|
39
|
+
getList: ['validate', ({}, cbk) => {
|
|
40
|
+
return fs.getFile(path, (err, res) => {
|
|
41
|
+
if (!!err) {
|
|
42
|
+
return cbk([503, 'UnexpectedErrorGettingAvoidListFile', {err}]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const lines = res.toString().split(matchNewLines).map(trim);
|
|
46
|
+
|
|
47
|
+
return cbk(null, {lines: uniq(lines.filter(n => !!n))});
|
|
48
|
+
});
|
|
49
|
+
}],
|
|
50
|
+
},
|
|
51
|
+
returnResult({reject, resolve, of: 'getList'}, cbk));
|
|
52
|
+
});
|
|
53
|
+
};
|