From 3ef05b338e2dbf391067dfb1eeb53f1bf02156ef Mon Sep 17 00:00:00 2001 From: AP Date: Wed, 11 Dec 2019 22:42:23 +0100 Subject: [PATCH] feat: forward channel route query --- .../query/report/ForwardChannels.ts | 15 -- src/schemas/query/report/ForwardChannels.ts | 135 +++++++++++++++--- src/schemas/query/report/Helpers.ts | 30 ++++ 3 files changed, 149 insertions(+), 31 deletions(-) delete mode 100644 src/schemaTypes/query/report/ForwardChannels.ts diff --git a/src/schemaTypes/query/report/ForwardChannels.ts b/src/schemaTypes/query/report/ForwardChannels.ts deleted file mode 100644 index 7abdaac8..00000000 --- a/src/schemaTypes/query/report/ForwardChannels.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { GraphQLObjectType, GraphQLString } from "graphql"; - -export const ForwardChannelsType = new GraphQLObjectType({ - name: "forwardChannelType", - fields: () => { - return { - incoming: { - type: GraphQLString - }, - outgoing: { - type: GraphQLString - } - }; - } -}); diff --git a/src/schemas/query/report/ForwardChannels.ts b/src/schemas/query/report/ForwardChannels.ts index 0e9f53cc..23f9a9d3 100644 --- a/src/schemas/query/report/ForwardChannels.ts +++ b/src/schemas/query/report/ForwardChannels.ts @@ -1,20 +1,34 @@ import { GraphQLString, GraphQLNonNull } from 'graphql'; -import { getForwards as getLnForwards } from 'ln-service'; +import { + getForwards as getLnForwards, + getNode, + getChannel, + getWalletInfo, +} from 'ln-service'; import { logger } from '../../../helpers/logger'; import { requestLimiter } from '../../../helpers/rateLimiter'; import { subHours, subDays } from 'date-fns'; -import { countArray } from './Helpers'; +import { countArray, countRoutes } from './Helpers'; import { ForwardCompleteProps } from './ForwardReport.interface'; -import { ForwardChannelsType } from '../../../schemaTypes/query/report/ForwardChannels'; import { sortBy } from 'underscore'; import { getAuthLnd, getErrorMsg } from '../../../helpers/helpers'; +interface NodeProps { + alias: string; + color: string; +} + +interface ChannelsProps { + policies: { public_key: string }[]; +} + export const getForwardChannelsReport = { - type: ForwardChannelsType, + type: GraphQLString, args: { auth: { type: new GraphQLNonNull(GraphQLString) }, time: { type: GraphQLString }, order: { type: GraphQLString }, + type: { type: GraphQLString }, }, resolve: async (root: any, params: any, context: any) => { await requestLimiter(context.ip, 'forwardChannels'); @@ -32,6 +46,66 @@ export const getForwardChannelsReport = { startDate = subHours(endDate, 24); } + const getNodeAlias = async (id: string, publicKey: string) => { + const channelInfo: ChannelsProps = await getChannel({ + lnd, + id, + }); + + const partnerPublicKey = + channelInfo.policies[0].public_key !== publicKey + ? channelInfo.policies[0].public_key + : channelInfo.policies[1].public_key; + + const nodeInfo: NodeProps = await getNode({ + lnd, + is_omitting_channels: true, + public_key: partnerPublicKey, + }); + + return { + alias: nodeInfo.alias, + color: nodeInfo.color, + }; + }; + + const getRouteAlias = (array: any[], publicKey: string) => + Promise.all( + array.map(async channel => { + const nodeAliasIn = await getNodeAlias( + channel.in, + publicKey, + ); + const nodeAliasOut = await getNodeAlias( + channel.out, + publicKey, + ); + + return { + aliasIn: nodeAliasIn.alias, + colorIn: nodeAliasIn.color, + aliasOut: nodeAliasOut.alias, + colorOut: nodeAliasOut.color, + ...channel, + }; + }), + ); + + const getAlias = (array: any[], publicKey: string) => + Promise.all( + array.map(async channel => { + const nodeAlias = await getNodeAlias( + channel.name, + publicKey, + ); + return { + alias: nodeAlias.alias, + color: nodeAlias.color, + ...channel, + }; + }), + ); + try { const forwardsList: ForwardCompleteProps = await getLnForwards({ lnd: lnd, @@ -40,20 +114,49 @@ export const getForwardChannelsReport = { limit: 10000, }); - const incomingCount = countArray(forwardsList.forwards, true); - const outgoingCount = countArray(forwardsList.forwards, false); + const walletInfo: { public_key: string } = await getWalletInfo({ + lnd, + }); - const sortedInCount = sortBy(incomingCount, params.order) - .reverse() - .slice(0, 5); - const sortedOutCount = sortBy(outgoingCount, params.order) - .reverse() - .slice(0, 5); + if (params.type === 'route') { + const mapped = forwardsList.forwards.map(forward => { + return { + route: `${forward.incoming_channel} - ${forward.outgoing_channel}`, + ...forward, + }; + }); + const grouped = countRoutes(mapped); - return { - incoming: JSON.stringify(sortedInCount), - outgoing: JSON.stringify(sortedOutCount), - }; + const routeAlias = await getRouteAlias( + grouped, + walletInfo.public_key, + ); + + const sortedRoute = sortBy(routeAlias, params.order) + .reverse() + .slice(0, 10); + return JSON.stringify(sortedRoute); + } else if (params.type === 'incoming') { + const incomingCount = countArray(forwardsList.forwards, true); + const incomingAlias = await getAlias( + incomingCount, + walletInfo.public_key, + ); + const sortedInCount = sortBy(incomingAlias, params.order) + .reverse() + .slice(0, 10); + return JSON.stringify(sortedInCount); + } else { + const outgoingCount = countArray(forwardsList.forwards, false); + const outgoingAlias = await getAlias( + outgoingCount, + walletInfo.public_key, + ); + const sortedOutCount = sortBy(outgoingAlias, params.order) + .reverse() + .slice(0, 10); + return JSON.stringify(sortedOutCount); + } } catch (error) { logger.error('Error getting forward channel report: %o', error); throw new Error(getErrorMsg(error)); diff --git a/src/schemas/query/report/Helpers.ts b/src/schemas/query/report/Helpers.ts index 942dce21..722ce0e5 100644 --- a/src/schemas/query/report/Helpers.ts +++ b/src/schemas/query/report/Helpers.ts @@ -74,3 +74,33 @@ export const countArray = (list: ForwardProps[], type: boolean) => { return channelInfo; }; + +export const countRoutes = (list: ForwardProps[]) => { + const grouped = groupBy(list, 'route'); + + const channelInfo = []; + for (const key in grouped) { + if (grouped.hasOwnProperty(key)) { + const element = grouped[key]; + + const fee = element + .map(forward => forward.fee) + .reduce((p, c) => p + c); + + const tokens = element + .map(forward => forward.tokens) + .reduce((p, c) => p + c); + + channelInfo.push({ + route: key, + in: element[0].incoming_channel, + out: element[0].outgoing_channel, + amount: element.length, + fee: fee, + tokens: tokens, + }); + } + } + + return channelInfo; +};