Skip to content

Commit 6f1ba90

Browse files
committed
channels: fetch aliases for channel peers
1 parent e8d1bca commit 6f1ba90

File tree

8 files changed

+96
-9
lines changed

8 files changed

+96
-9
lines changed

app/src/__tests__/components/loop/ChannelRow.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ describe('ChannelRow component', () => {
4949
expect(getByText(channel.uptime.toString())).toBeInTheDocument();
5050
});
5151

52-
it('should display the peer pubkey', () => {
52+
it('should display the peer pubkey or alias', () => {
5353
const { getByText } = render();
54-
expect(getByText(channel.ellipsedPubkey)).toBeInTheDocument();
54+
expect(getByText(channel.aliasLabel)).toBeInTheDocument();
5555
});
5656

5757
it('should display the capacity', () => {

app/src/__tests__/store/channelStore.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { grpc } from '@improbable-eng/grpc-web';
44
import { waitFor } from '@testing-library/react';
55
import Big from 'big.js';
66
import { BalanceMode } from 'util/constants';
7-
import { lndChannelEvent, lndListChannels } from 'util/tests/sampleData';
7+
import {
8+
lndChannel,
9+
lndChannelEvent,
10+
lndGetNodeInfo,
11+
lndListChannels,
12+
} from 'util/tests/sampleData';
813
import { createStore, Store } from 'store';
914
import Channel from 'store/models/channel';
1015
import ChannelStore from 'store/stores/channelStore';
@@ -120,6 +125,16 @@ describe('ChannelStore', () => {
120125
expect(+store.totalOutbound).toBe(outbound);
121126
});
122127

128+
it('should fetch aliases for channels', async () => {
129+
await store.fetchChannels();
130+
const channel = store.channels.get(lndChannel.chanId) as Channel;
131+
expect(channel.alias).toBeUndefined();
132+
// the alias is fetched from the API and should be updated after a few ticks
133+
waitFor(() => {
134+
expect(channel.alias).toBe(lndGetNodeInfo.node.alias);
135+
});
136+
});
137+
123138
describe('onChannelEvent', () => {
124139
const {
125140
OPEN_CHANNEL,

app/src/api/lnd.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ class LndApi extends BaseApi<LndEvents> {
5656
return res.toObject();
5757
}
5858

59+
/**
60+
* call the LND `GetNodeInfo` RPC and return the response
61+
*/
62+
async getNodeInfo(pubkey: string): Promise<LND.NodeInfo.AsObject> {
63+
const req = new LND.NodeInfoRequest();
64+
req.setPubKey(pubkey);
65+
const res = await this._grpc.request(Lightning.GetNodeInfo, req, this._meta);
66+
return res.toObject();
67+
}
68+
5969
/**
6070
* Connect to the LND streaming endpoints
6171
*/

app/src/components/loop/ChannelRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ const ChannelRow: React.FC<Props> = ({ channel, style }) => {
137137
<Column>{channel.uptimePercent}</Column>
138138
<Column>
139139
<Tip overlay={channel.remotePubkey} placement="left">
140-
<span>{channel.ellipsedPubkey}</span>
140+
<span>{channel.aliasLabel}</span>
141141
</Tip>
142142
</Column>
143143
<Column right>

app/src/i18n/locales/en-US.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"cmps.loop.ChannelRowHeader.canReceive": "Can Receive",
2323
"cmps.loop.ChannelRowHeader.canSend": "Can Send",
2424
"cmps.loop.ChannelRowHeader.upTime": "Up Time %",
25-
"cmps.loop.ChannelRowHeader.peer": "Peer Pubkey",
25+
"cmps.loop.ChannelRowHeader.peer": "Peer/Alias",
2626
"cmps.loop.ChannelRowHeader.capacity": "Capacity",
2727
"cmps.loop.LoopActions.channelsSelected": "channels selected",
2828
"cmps.loop.LoopActions.loopInNote": "For multi Loop In, all channels must use the same peer.",

app/src/store/models/channel.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default class Channel {
1313

1414
@observable chanId = '';
1515
@observable remotePubkey = '';
16+
@observable alias: string | undefined;
1617
@observable channelPoint = '';
1718
@observable capacity = Big(0);
1819
@observable localBalance = Big(0);
@@ -27,10 +28,10 @@ export default class Channel {
2728
}
2829

2930
/**
30-
* The remotePubkey shortened to ~20 chars with ellipses inside
31+
* The alias or remotePubkey shortened to ~20 chars with ellipses inside
3132
*/
32-
@computed get ellipsedPubkey() {
33-
return ellipseInside(this.remotePubkey);
33+
@computed get aliasLabel() {
34+
return this.alias || ellipseInside(this.remotePubkey);
3435
}
3536

3637
/**

app/src/store/stores/channelStore.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export default class ChannelStore {
9393
.forEach(id => this.channels.delete(id));
9494

9595
this._store.log.info('updated channelStore.channels', toJS(this.channels));
96+
// fetch the aliases for each of the channels
97+
this.fetchAliases();
9698
});
9799
} catch (error) {
98100
this._store.uiStore.handleError(error, 'Unable to fetch Channels');
@@ -102,6 +104,35 @@ export default class ChannelStore {
102104
/** fetch channels at most once every 2 seconds when using this func */
103105
fetchChannelsThrottled = debounce(this.fetchChannels, 2000);
104106

107+
/**
108+
* queries the LND api to fetch the aliases for all of the peers we have
109+
* channels opened with
110+
*/
111+
@action.bound
112+
async fetchAliases() {
113+
const pubKeys = values(this.channels)
114+
.map(c => c.remotePubkey)
115+
.filter((r, i, a) => a.indexOf(r) === i); // remove duplicates
116+
// call getNodeInfo for each pubkey and wait for all the requests to complete
117+
const nodeInfos = await Promise.all(
118+
pubKeys.map(pk => this._store.api.lnd.getNodeInfo(pk)),
119+
);
120+
121+
// create a map of pubKey to alias
122+
const aliases = nodeInfos.reduce((acc, { node }) => {
123+
if (node) acc[node.pubKey] = node.alias;
124+
return acc;
125+
}, {} as Record<string, string>);
126+
127+
runInAction('fetchAliasesContinuation', () => {
128+
values(this.channels).forEach(c => {
129+
if (aliases[c.remotePubkey]) {
130+
c.alias = aliases[c.remotePubkey];
131+
}
132+
});
133+
});
134+
}
135+
105136
/** update the channel list based on events from the API */
106137
@action.bound
107138
onChannelEvent(event: ChannelEventUpdate.AsObject) {
@@ -136,6 +167,8 @@ export default class ChannelStore {
136167
this.channels.set(channel.chanId, channel);
137168
this._store.log.info('added new open channel', toJS(channel));
138169
this._store.nodeStore.fetchBalancesThrottled();
170+
// fetch the alias for the added channel
171+
this.fetchAliases();
139172
}
140173
}
141174

app/src/util/tests/sampleData.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,33 @@ export const lndGetInfo: LND.GetInfoResponse.AsObject = {
3636
],
3737
};
3838

39+
export const lndGetNodeInfo: Required<LND.NodeInfo.AsObject> = {
40+
channelsList: [],
41+
node: {
42+
addressesList: [
43+
{
44+
addr: '172.28.0.8:9735',
45+
network: 'tcp',
46+
},
47+
],
48+
alias: 'alice',
49+
color: '#cccccc',
50+
featuresMap: [
51+
[0, { name: 'data-loss-protect', isRequired: true, isKnown: true }],
52+
[13, { name: 'static-remote-key', isRequired: false, isKnown: true }],
53+
[15, { name: 'payment-addr', isRequired: false, isKnown: true }],
54+
[17, { name: 'multi-path-payments', isRequired: false, isKnown: true }],
55+
[5, { name: 'upfront-shutdown-script', isRequired: false, isKnown: true }],
56+
[7, { name: 'gossip-queries', isRequired: false, isKnown: true }],
57+
[9, { name: 'tlv-onion', isRequired: false, isKnown: true }],
58+
],
59+
lastUpdate: 1591393224,
60+
pubKey: '037136742c67e24681f36542f7c8916aa6f6fdf665c1dca2a107425503cff94501',
61+
},
62+
numChannels: 3,
63+
totalCapacity: 47000000,
64+
};
65+
3966
export const lndChannelBalance: LND.ChannelBalanceResponse.AsObject = {
4067
balance: 9990950,
4168
pendingOpenBalance: 0,
@@ -95,7 +122,7 @@ export const lndListChannels: LND.ListChannelsResponse.AsObject = {
95122
...c,
96123
chanId: `${i || ''}${c.chanId}`,
97124
channelPoint: `${c.channelPoint.substring(0, c.channelPoint.length - 2)}:${i}`,
98-
remotePubkey: `${i}${c.remotePubkey}`,
125+
remotePubkey: `${i || ''}${c.remotePubkey}`,
99126
localBalance: local,
100127
remoteBalance: cap - local,
101128
capacity: cap,
@@ -186,6 +213,7 @@ export const loopQuote: LOOP.QuoteResponse.AsObject = {
186213
// collection of sample API responses
187214
export const sampleApiResponses: Record<string, any> = {
188215
'lnrpc.Lightning.GetInfo': lndGetInfo,
216+
'lnrpc.Lightning.GetNodeInfo': lndGetNodeInfo,
189217
'lnrpc.Lightning.ChannelBalance': lndChannelBalance,
190218
'lnrpc.Lightning.WalletBalance': lndWalletBalance,
191219
'lnrpc.Lightning.ListChannels': lndListChannels,

0 commit comments

Comments
 (0)