mirror of
https://github.com/alexbosworth/balanceofsatoshis.git
synced 2026-08-13 12:33:37 +02:00
159 lines
4.8 KiB
JavaScript
159 lines
4.8 KiB
JavaScript
const asyncAuto = require('async/auto');
|
|
const {enforceForwardRequestRules} = require('ln-sync');
|
|
const {returnResult} = require('asyncjs-util');
|
|
|
|
const disableAllForwards = 0;
|
|
const hoursAsSeconds = hours => hours * 60 * 60;
|
|
const {isArray} = Array;
|
|
const isEdge = n => !!n && /^[0-9A-F]{66}\/[0-9A-F]{66}$/i.test(n);
|
|
const splitEdge = n => n.split('/');
|
|
|
|
/** Limit forwarding requests
|
|
|
|
{
|
|
lnd: (await lndForNode(logger, options.node)).lnd,
|
|
logger: <Winston Logger Object>
|
|
[is_disabling_all_forwards]: <All Forwards Are Disabled Bool>
|
|
[max_hours_since_last_block]: <Maximum Hours Since Last Block Number>
|
|
[max_new_pending_per_hour]: <Maximum Outstanding New HTLCs Per Hour Number>
|
|
[min_channel_confirmations]: <Minimum Required Channel Confs Number>
|
|
only_allow: [<In Public Key / Out Public Key String>]
|
|
only_disallow: [<In Public Key / Out Public Key String>]
|
|
stop_channels: [<Channel Id to Stop Traffic On String>]
|
|
}
|
|
|
|
@returns via cbk or Promise
|
|
*/
|
|
module.exports = (args, cbk) => {
|
|
return new Promise((resolve, reject) => {
|
|
return asyncAuto({
|
|
// Check arguments
|
|
validate: cbk => {
|
|
if (!isArray(args.only_allow)) {
|
|
return cbk([400, 'ExpectedOnlyAllowArrayToLimitForwarding']);
|
|
}
|
|
|
|
if (!isArray(args.only_disallow)) {
|
|
return cbk([400, 'ExpectedOnlyDisallowArrayToLimitForwarding']);
|
|
}
|
|
|
|
if (!!args.only_allow.length && !!args.only_disallow.length) {
|
|
return cbk([400, 'ExpectedEitherAllowOrDisallowPublicKeyPairs']);
|
|
}
|
|
|
|
if (!!args.only_allow.filter(n => !isEdge(n)).length) {
|
|
return cbk([400, 'ExpectedOnlyAllowAsPublicKeyPairs']);
|
|
}
|
|
|
|
if (!!args.only_disallow.filter(n => !isEdge(n)).length) {
|
|
return cbk([400, 'ExpectedOnlyDisallowAsPublicKeyPairs']);
|
|
}
|
|
|
|
if (!args.logger) {
|
|
return cbk([400, 'ExpectedWinstonLoggerToLimitForwarding']);
|
|
}
|
|
|
|
if (!args.lnd) {
|
|
return cbk([400, 'ExpectedAuthenticatedLndToLimitForwarding']);
|
|
}
|
|
|
|
if (!isArray(args.stop_channels)) {
|
|
return cbk([400, 'ExpectedStopChannelsArrayToLimitForwarding']);
|
|
}
|
|
|
|
return cbk();
|
|
},
|
|
|
|
// Max pending per hour
|
|
maxPendingPerHour: ['validate', ({}, cbk) => {
|
|
if (!!args.is_disabling_all_forwards) {
|
|
return cbk(null, disableAllForwards);
|
|
}
|
|
|
|
if (!!args.max_new_pending_per_hour) {
|
|
return cbk(null, args.max_new_pending_per_hour);
|
|
}
|
|
|
|
return cbk();
|
|
}],
|
|
|
|
// Max seconds allowed since the last block
|
|
maxSecondsSinceLastBlock: ['validate', ({}, cbk) => {
|
|
if (!args.max_hours_since_last_block) {
|
|
return cbk();
|
|
}
|
|
|
|
return cbk(null, hoursAsSeconds(args.max_hours_since_last_block));
|
|
}],
|
|
|
|
// Only allow pairs
|
|
onlyAllow: ['validate', ({}, cbk) => {
|
|
if (!args.only_allow.length) {
|
|
return cbk();
|
|
}
|
|
|
|
const allow = args.only_allow.map(splitEdge).map(([inKey, outKey]) => {
|
|
return {inbound_peer: inKey, outbound_peer: outKey};
|
|
});
|
|
|
|
return cbk(null, allow);
|
|
}],
|
|
|
|
// Only disallow pairs
|
|
onlyDisallow: ['validate', ({}, cbk) => {
|
|
// Exit early when there is no deny list
|
|
if (!args.only_disallow.length) {
|
|
return cbk();
|
|
}
|
|
|
|
const edges = args.only_disallow.map(splitEdge);
|
|
|
|
const disallow = edges.map(([inKey, outKey]) => {
|
|
return {inbound_peer: inKey, outbound_peer: outKey};
|
|
});
|
|
|
|
return cbk(null, disallow);
|
|
}],
|
|
|
|
// Limit forward requests
|
|
limit: [
|
|
'maxPendingPerHour',
|
|
'maxSecondsSinceLastBlock',
|
|
'onlyAllow',
|
|
'onlyDisallow',
|
|
({
|
|
maxPendingPerHour,
|
|
maxSecondsSinceLastBlock,
|
|
onlyAllow,
|
|
onlyDisallow,
|
|
},
|
|
cbk) =>
|
|
{
|
|
args.logger.info({limiting_forwards: true});
|
|
|
|
const sub = enforceForwardRequestRules({
|
|
lnd: args.lnd,
|
|
max_new_pending_per_hour: maxPendingPerHour,
|
|
max_seconds_since_last_block: maxSecondsSinceLastBlock,
|
|
min_activation_age: args.min_channel_confirmations || undefined,
|
|
only_allow: onlyAllow,
|
|
only_disallow: onlyDisallow,
|
|
stop_channels: args.stop_channels.length ? args.stop_channels : null,
|
|
});
|
|
|
|
sub.on('error', err => {
|
|
return cbk([503, 'UnexpectedErrorLimitingForwarding', {err}]);
|
|
});
|
|
|
|
sub.on('rejected', async rejected => {
|
|
const forward = `${rejected.in_channel} → ${rejected.out_channel}`;
|
|
|
|
const rejection = `${rejected.reject_reason} ${forward}`;
|
|
|
|
return args.logger.info({rejection});
|
|
});
|
|
}],
|
|
},
|
|
returnResult({reject, resolve}, cbk));
|
|
});
|
|
};
|