Browse Source

refactor(lightning): update may var names from lnd to lightning

master
jamaljsr 5 years ago
parent
commit
d77fef6c58
  1. 10
      TODO.md
  2. 2
      src/components/designer/NetworkDesigner.spec.tsx
  3. 7
      src/components/designer/lightning/LightningDetails.spec.tsx
  4. 3
      src/components/designer/lightning/actions/Deposit.spec.tsx
  5. 4
      src/components/designer/lightning/actions/Deposit.tsx
  6. 5
      src/components/designer/lightning/actions/RemoveNode.spec.tsx
  7. 24
      src/components/designer/link/Backend.spec.tsx
  8. 4
      src/components/designer/link/Channel.tsx
  9. 7
      src/components/terminal/OpenTerminalButton.spec.tsx
  10. 3
      src/components/terminal/OpenTerminalButton.tsx
  11. 4
      src/lib/docker/composeFile.spec.ts
  12. 7
      src/lib/docker/dockerService.spec.ts
  13. 5
      src/lib/docker/dockerService.ts
  14. 4
      src/lib/lightning/lnd/lndProxyClient.spec.ts
  15. 3
      src/lib/lightning/lnd/lndService.spec.ts
  16. 9
      src/store/models/designer.ts
  17. 2
      src/store/models/lightning.spec.ts
  18. 2
      src/store/models/lightning.ts
  19. 4
      src/store/models/network.spec.ts
  20. 1
      src/store/models/network.ts
  21. 42
      src/utils/chart.spec.ts
  22. 11
      src/utils/chart.ts
  23. 2
      src/utils/network.ts

10
TODO.md

@ -2,11 +2,15 @@
Small Stuff Small Stuff
- dont allow open channel if both nodes aren't Started - add draggable c-lightning node to sidebar
- in designer.ts change addLndNode to addLightningNode
- in network.ts rename addLndNode to addNode
- in network.ts update removeNode for c-lightning
- rename lnd in locale files
- implement real-time channel updates from LND via GRPC streams - implement real-time channel updates from LND via GRPC streams
- implement option to auto-mine every X minutes - implement option to auto-mine every X minutes
- switch renovatebot to dependabot and use automatic security fixes - switch renovatebot to dependabot and use automatic security fixes
- generate alice/bob/carol names for lnd nodes
- display docker streaming logs in the UI - display docker streaming logs in the UI
- mock or install docker on build servers for e2e tests - mock or install docker on build servers for e2e tests
- consistent scrollbars for all OS's (https://github.com/xobotyi/react-scrollbars-custom) (https://github.com/souhe/reactScrollbar) - consistent scrollbars for all OS's (https://github.com/xobotyi/react-scrollbars-custom) (https://github.com/souhe/reactScrollbar)
@ -16,7 +20,7 @@ Bigger things
- create a splash page website for lightningpolar.com - create a splash page website for lightningpolar.com
- add block explorer (https://github.com/janoside/btc-rpc-explorer) - add block explorer (https://github.com/janoside/btc-rpc-explorer)
- add grpc API explorer (https://github.com/grpc-ecosystem/awesome-grpc#gui) - add grpc API explorer (https://github.com/grpc-ecosystem/awesome-grpc#gui)
- add support for c-lightning, eclair, btcd - add support for eclair, btcd
- live theme changer (https://medium.com/@mzohaib.qc/ant-design-dynamic-runtime-theme-1f9a1a030ba0) - live theme changer (https://medium.com/@mzohaib.qc/ant-design-dynamic-runtime-theme-1f9a1a030ba0)
- dark theme UI (https://material.io/design/color/dark-theme.html) - dark theme UI (https://material.io/design/color/dark-theme.html)
- POC testing-library for testcafe (https://testing-library.com/docs/testcafe-testing-library/intro) - POC testing-library for testcafe (https://testing-library.com/docs/testcafe-testing-library/intro)

2
src/components/designer/NetworkDesigner.spec.tsx

@ -46,7 +46,7 @@ describe('NetworkDesigner Component', () => {
expect(await findByText('backend')).toBeInTheDocument(); expect(await findByText('backend')).toBeInTheDocument();
}); });
it('should render correct # of LND nodes', async () => { it('should render correct # of lightning nodes', async () => {
const { findByText } = renderComponent(); const { findByText } = renderComponent();
expect(await findByText('alice')).toBeInTheDocument(); expect(await findByText('alice')).toBeInTheDocument();
expect(await findByText('bob')).toBeInTheDocument(); expect(await findByText('bob')).toBeInTheDocument();

7
src/components/designer/lightning/LightningDetails.spec.tsx

@ -3,7 +3,6 @@ import { shell } from 'electron';
import { fireEvent, wait, waitForElement } from '@testing-library/dom'; import { fireEvent, wait, waitForElement } from '@testing-library/dom';
import { Status } from 'shared/types'; import { Status } from 'shared/types';
import * as files from 'utils/files'; import * as files from 'utils/files';
import { groupNodes } from 'utils/network';
import { import {
defaultStateBalances, defaultStateBalances,
defaultStateInfo, defaultStateInfo,
@ -15,7 +14,7 @@ import LightningDetails from './LightningDetails';
jest.mock('utils/files'); jest.mock('utils/files');
describe('LndDetails', () => { describe('LightningDetails', () => {
const renderComponent = (status?: Status) => { const renderComponent = (status?: Status) => {
const network = getNetwork(1, 'test network', status); const network = getNetwork(1, 'test network', status);
if (status === Status.Error) { if (status === Status.Error) {
@ -31,7 +30,7 @@ describe('LndDetails', () => {
}, },
}, },
}; };
const node = groupNodes(network).lnd[0]; const node = network.nodes.lightning[0];
const cmp = <LightningDetails node={node} />; const cmp = <LightningDetails node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {
@ -185,7 +184,7 @@ describe('LndDetails', () => {
expect(queryByText('Unconfirmed Balance')).not.toBeInTheDocument(); expect(queryByText('Unconfirmed Balance')).not.toBeInTheDocument();
}); });
it('should not display LND info if its undefined', async () => { it('should not display node info if its undefined', async () => {
lightningServiceMock.getInfo.mockResolvedValue(null as any); lightningServiceMock.getInfo.mockResolvedValue(null as any);
const { getByText, queryByText, findByText } = renderComponent(Status.Started); const { getByText, queryByText, findByText } = renderComponent(Status.Started);
fireEvent.click(await findByText('Info')); fireEvent.click(await findByText('Info'));

3
src/components/designer/lightning/actions/Deposit.spec.tsx

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import { fireEvent, waitForElement } from '@testing-library/dom'; import { fireEvent, waitForElement } from '@testing-library/dom';
import { BitcoindLibrary } from 'types'; import { BitcoindLibrary } from 'types';
import { groupNodes } from 'utils/network';
import { import {
defaultStateInfo, defaultStateInfo,
getNetwork, getNetwork,
@ -21,7 +20,7 @@ describe('Deposit', () => {
networks: [network], networks: [network],
}, },
}; };
const node = groupNodes(network).lnd[0]; const node = network.nodes.lightning[0];
const cmp = <Deposit node={node} />; const cmp = <Deposit node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {

4
src/components/designer/lightning/actions/Deposit.tsx

@ -8,7 +8,7 @@ import { format } from 'utils/units';
const InputGroup = Input.Group; const InputGroup = Input.Group;
const LndDeposit: React.FC<{ node: LightningNode }> = ({ node }) => { const Deposit: React.FC<{ node: LightningNode }> = ({ node }) => {
const { l } = usePrefixedTranslation('cmps.designer.lnd.actions.Deposit'); const { l } = usePrefixedTranslation('cmps.designer.lnd.actions.Deposit');
const [amount, setAmount] = useState(1000000); const [amount, setAmount] = useState(1000000);
const { notify } = useStoreActions(s => s.app); const { notify } = useStoreActions(s => s.app);
@ -49,4 +49,4 @@ const LndDeposit: React.FC<{ node: LightningNode }> = ({ node }) => {
); );
}; };
export default LndDeposit; export default Deposit;

5
src/components/designer/lightning/actions/RemoveNode.spec.tsx

@ -3,7 +3,6 @@ import { fireEvent, waitForElement } from '@testing-library/dom';
import { Status } from 'shared/types'; import { Status } from 'shared/types';
import { DockerLibrary } from 'types'; import { DockerLibrary } from 'types';
import { initChartFromNetwork } from 'utils/chart'; import { initChartFromNetwork } from 'utils/chart';
import { groupNodes } from 'utils/network';
import { import {
getNetwork, getNetwork,
injections, injections,
@ -32,8 +31,8 @@ describe('RemoveNode', () => {
activeId: 1, activeId: 1,
}, },
}; };
const { lnd } = groupNodes(network); const { lightning } = network.nodes;
const node = lnd[status === Status.Started ? 0 : 1]; const node = lightning[status === Status.Started ? 0 : 1];
const cmp = <RemoveNode node={node} />; const cmp = <RemoveNode node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {

24
src/components/designer/link/Backend.spec.tsx

@ -8,37 +8,37 @@ describe('Backend component', () => {
const renderComponent = () => { const renderComponent = () => {
const network = getNetwork(); const network = getNetwork();
const bitcoind = network.nodes.bitcoin[0]; const bitcoind = network.nodes.bitcoin[0];
const lnd = network.nodes.lightning[0]; const lightning = network.nodes.lightning[0];
const result = render(<Backend bitcoinNode={bitcoind} lightningNode={lnd} />); const result = render(<Backend bitcoinNode={bitcoind} lightningNode={lightning} />);
return { return {
...result, ...result,
bitcoind, bitcoind,
lnd, lightning,
}; };
}; };
describe('LND Details', () => { describe('Lightning Details', () => {
it('should display Name', () => { it('should display Name', () => {
const { getByText, lnd } = renderComponent(); const { getByText, lightning } = renderComponent();
expect(getByText(lnd.name)).toBeInTheDocument(); expect(getByText(lightning.name)).toBeInTheDocument();
}); });
it('should display Implementation', () => { it('should display Implementation', () => {
const { getByText, getAllByText, lnd } = renderComponent(); const { getByText, getAllByText, lightning } = renderComponent();
expect(getAllByText('Implementation')).toHaveLength(2); expect(getAllByText('Implementation')).toHaveLength(2);
expect(getByText(lnd.implementation)).toBeInTheDocument(); expect(getByText(lightning.implementation)).toBeInTheDocument();
}); });
it('should display Version', () => { it('should display Version', () => {
const { getByText, getAllByText, lnd } = renderComponent(); const { getByText, getAllByText, lightning } = renderComponent();
expect(getAllByText('Version')).toHaveLength(2); expect(getAllByText('Version')).toHaveLength(2);
expect(getByText(`v${lnd.version}`)).toBeInTheDocument(); expect(getByText(`v${lightning.version}`)).toBeInTheDocument();
}); });
it('should display Status', () => { it('should display Status', () => {
const { getAllByText, lnd } = renderComponent(); const { getAllByText, lightning } = renderComponent();
expect(getAllByText('Status')).toHaveLength(2); expect(getAllByText('Status')).toHaveLength(2);
expect(getAllByText(Status[lnd.status])).toHaveLength(2); expect(getAllByText(Status[lightning.status])).toHaveLength(2);
}); });
}); });

4
src/components/designer/link/Channel.tsx

@ -2,7 +2,7 @@ import React from 'react';
import { ILink } from '@mrblenny/react-flow-chart'; import { ILink } from '@mrblenny/react-flow-chart';
import { Button, Modal } from 'antd'; import { Button, Modal } from 'antd';
import { usePrefixedTranslation } from 'hooks'; import { usePrefixedTranslation } from 'hooks';
import { LightningNode, LndNode, Status } from 'shared/types'; import { LightningNode, Status } from 'shared/types';
import { useStoreActions } from 'store'; import { useStoreActions } from 'store';
import { LinkProperties } from 'utils/chart'; import { LinkProperties } from 'utils/chart';
import { ellipseInner } from 'utils/strings'; import { ellipseInner } from 'utils/strings';
@ -38,7 +38,7 @@ const Channel: React.FC<Props> = ({ link, from, to }) => {
cancelText: l('closeChanCancelBtn'), cancelText: l('closeChanCancelBtn'),
onOk: async () => { onOk: async () => {
try { try {
await closeChannel({ node: from as LndNode, channelPoint }); await closeChannel({ node: from, channelPoint });
notify({ message: l('closeChanSuccess') }); notify({ message: l('closeChanSuccess') });
} catch (error) { } catch (error) {
notify({ message: l('closeChanError'), error }); notify({ message: l('closeChanError'), error });

7
src/components/terminal/OpenTerminalButton.spec.tsx

@ -1,14 +1,13 @@
import React from 'react'; import React from 'react';
import { fireEvent, wait } from '@testing-library/dom'; import { fireEvent, wait } from '@testing-library/dom';
import { ipcChannels } from 'shared'; import { ipcChannels } from 'shared';
import { BitcoinNode, LndNode } from 'shared/types'; import { BitcoinNode, LightningNode } from 'shared/types';
import { Network } from 'types'; import { Network } from 'types';
import { groupNodes } from 'utils/network';
import { getNetwork, injections, renderWithProviders } from 'utils/tests'; import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import OpenTerminalButton from './OpenTerminalButton'; import OpenTerminalButton from './OpenTerminalButton';
describe('OpenTerminalButton', () => { describe('OpenTerminalButton', () => {
const renderComponent = (nodeSelector: (n: Network) => LndNode | BitcoinNode) => { const renderComponent = (nodeSelector: (n: Network) => LightningNode | BitcoinNode) => {
const network = getNetwork(1, 'test network'); const network = getNetwork(1, 'test network');
return renderWithProviders(<OpenTerminalButton node={nodeSelector(network)} />); return renderWithProviders(<OpenTerminalButton node={nodeSelector(network)} />);
}; };
@ -30,7 +29,7 @@ describe('OpenTerminalButton', () => {
}); });
it('should render lnd help text', () => { it('should render lnd help text', () => {
const { getByText } = renderComponent(n => groupNodes(n).lnd[0]); const { getByText } = renderComponent(n => n.nodes.lightning[0]);
const help = getByText("Run 'lncli' commands directly on the node"); const help = getByText("Run 'lncli' commands directly on the node");
expect(help).toBeInTheDocument(); expect(help).toBeInTheDocument();
}); });

3
src/components/terminal/OpenTerminalButton.tsx

@ -21,6 +21,9 @@ const OpenTerminalButton: React.FC<Props> = ({ node }) => {
case 'LND': case 'LND':
cmd = 'lncli'; cmd = 'lncli';
break; break;
case 'c-lightning':
cmd = 'lightning-cli';
break;
case 'bitcoind': case 'bitcoind':
cmd = 'bitcoin-cli'; cmd = 'bitcoin-cli';
break; break;

4
src/lib/docker/composeFile.spec.ts

@ -1,4 +1,4 @@
import { groupNodes } from 'utils/network'; import { LndNode } from 'shared/types';
import { getNetwork } from 'utils/tests'; import { getNetwork } from 'utils/tests';
import ComposeFile from './composeFile'; import ComposeFile from './composeFile';
@ -6,7 +6,7 @@ describe('ComposeFile', () => {
let composeFile = new ComposeFile(); let composeFile = new ComposeFile();
const network = getNetwork(); const network = getNetwork();
const btcNode = network.nodes.bitcoin[0]; const btcNode = network.nodes.bitcoin[0];
const lndNode = groupNodes(network).lnd[0]; const lndNode = network.nodes.lightning[0] as LndNode;
beforeEach(() => { beforeEach(() => {
composeFile = new ComposeFile(); composeFile = new ComposeFile();

7
src/lib/docker/dockerService.spec.ts

@ -235,13 +235,6 @@ describe('DockerService', () => {
expect(fs.ensureDir).toBeCalledTimes(3); expect(fs.ensureDir).toBeCalledTimes(3);
}); });
it('should not create volume dirs for unknown implementations', async () => {
network.nodes.lightning[0].implementation = 'c-lightning';
composeMock.upAll.mockResolvedValue(mockResult);
await dockerService.start(network);
expect(fs.ensureDir).toBeCalledTimes(2);
});
it('should call compose.down when a network is stopped', async () => { it('should call compose.down when a network is stopped', async () => {
composeMock.down.mockResolvedValue(mockResult); composeMock.down.mockResolvedValue(mockResult);
await dockerService.stop(network); await dockerService.stop(network);

5
src/lib/docker/dockerService.ts

@ -109,9 +109,8 @@ class DockerService implements DockerLibrary {
await ensureDir(join(network.path, 'volumes', 'bitcoind', node.name)); await ensureDir(join(network.path, 'volumes', 'bitcoind', node.name));
} }
for (const node of lightning) { for (const node of lightning) {
if (node.implementation === 'LND') { const volDir = node.implementation.toLocaleLowerCase().replace('-', '');
await ensureDir(join(network.path, 'volumes', 'lnd', node.name)); await ensureDir(join(network.path, 'volumes', volDir, node.name));
}
} }
info(`Starting docker containers for ${network.name}`); info(`Starting docker containers for ${network.name}`);

4
src/lib/lightning/lnd/lndProxyClient.spec.ts

@ -1,11 +1,11 @@
import { ipcChannels } from 'shared'; import { ipcChannels } from 'shared';
import { LndNode } from 'shared/types';
import { IpcSender } from 'lib/ipc/ipcService'; import { IpcSender } from 'lib/ipc/ipcService';
import { groupNodes } from 'utils/network';
import { getNetwork } from 'utils/tests'; import { getNetwork } from 'utils/tests';
import lndProxyClient from './lndProxyClient'; import lndProxyClient from './lndProxyClient';
describe('LndService', () => { describe('LndService', () => {
const node = groupNodes(getNetwork()).lnd[0]; const node = getNetwork().nodes.lightning[0] as LndNode;
let actualIpc: IpcSender; let actualIpc: IpcSender;
beforeEach(() => { beforeEach(() => {

3
src/lib/lightning/lnd/lndService.spec.ts

@ -7,7 +7,6 @@ import {
defaultPendingOpenChannel, defaultPendingOpenChannel,
defaultWalletBalance, defaultWalletBalance,
} from 'shared'; } from 'shared';
import { groupNodes } from 'utils/network';
import { defaultStateBalances, defaultStateInfo, getNetwork } from 'utils/tests'; import { defaultStateBalances, defaultStateInfo, getNetwork } from 'utils/tests';
import lndProxyClient from './lndProxyClient'; import lndProxyClient from './lndProxyClient';
import lndService from './lndService'; import lndService from './lndService';
@ -15,7 +14,7 @@ import lndService from './lndService';
jest.mock('./lndProxyClient'); jest.mock('./lndProxyClient');
describe('LndService', () => { describe('LndService', () => {
const node = groupNodes(getNetwork()).lnd[0]; const node = getNetwork().nodes.lightning[0];
it('should get node info', async () => { it('should get node info', async () => {
const apiResponse = defaultInfo({ identityPubkey: 'asdf' }); const apiResponse = defaultInfo({ identityPubkey: 'asdf' });

9
src/store/models/designer.ts

@ -13,7 +13,12 @@ import {
} from 'easy-peasy'; } from 'easy-peasy';
import { LndNode, Status } from 'shared/types'; import { LndNode, Status } from 'shared/types';
import { Network, StoreInjections } from 'types'; import { Network, StoreInjections } from 'types';
import { createLightningChartNode, rotate, snap, updateChartFromLnd } from 'utils/chart'; import {
createLightningChartNode,
rotate,
snap,
updateChartFromNodes,
} from 'utils/chart';
import { LOADING_NODE_ID } from 'utils/constants'; import { LOADING_NODE_ID } from 'utils/constants';
import { prefixTranslation } from 'utils/translate'; import { prefixTranslation } from 'utils/translate';
import { RootModel } from './'; import { RootModel } from './';
@ -104,7 +109,7 @@ const designerModel: DesignerModel = {
const nodesData = getStoreState().lightning.nodes; const nodesData = getStoreState().lightning.nodes;
const { allCharts } = getState(); const { allCharts } = getState();
// sync the chart with data from all of the nodes // sync the chart with data from all of the nodes
const chart = updateChartFromLnd(allCharts[network.id], nodesData); const chart = updateChartFromNodes(allCharts[network.id], nodesData);
actions.setAllCharts({ actions.setAllCharts({
...allCharts, ...allCharts,
[network.id]: chart, [network.id]: chart,

2
src/store/models/lightning.spec.ts

@ -20,7 +20,7 @@ jest.mock('utils/async');
const asyncUtilMock = asyncUtil as jest.Mocked<typeof asyncUtil>; const asyncUtilMock = asyncUtil as jest.Mocked<typeof asyncUtil>;
const bitcoindServiceMock = injections.bitcoindService as jest.Mocked<BitcoindLibrary>; const bitcoindServiceMock = injections.bitcoindService as jest.Mocked<BitcoindLibrary>;
describe('LND Model', () => { describe('Lightning Model', () => {
const rootModel = { const rootModel = {
network: networkModel, network: networkModel,
lightning: lightningModel, lightning: lightningModel,

2
src/store/models/lightning.ts

@ -129,7 +129,7 @@ const lightningModel: LightningModel = {
// cast because it should never be undefined after calling getInfo above // cast because it should never be undefined after calling getInfo above
const { rpcUrl } = getStoreState().lightning.nodes[to.name] const { rpcUrl } = getStoreState().lightning.nodes[to.name]
.info as LightningNodeInfo; .info as LightningNodeInfo;
// open the channel via LND // open the channel via lightning node
const api = injections.lightningFactory.getService(from); const api = injections.lightningFactory.getService(from);
await api.openChannel(from, rpcUrl, sats); await api.openChannel(from, rpcUrl, sats);
// mine some blocks to confirm the txn // mine some blocks to confirm the txn

4
src/store/models/network.spec.ts

@ -97,7 +97,7 @@ describe('Network model', () => {
expect(injections.dockerService.saveComposeFile).toBeCalledTimes(1); expect(injections.dockerService.saveComposeFile).toBeCalledTimes(1);
}); });
it('should add a network with the correct LND nodes', async () => { it('should add a network with the correct lightning nodes', async () => {
await store.getActions().network.addNetwork(addNetworkArgs); await store.getActions().network.addNetwork(addNetworkArgs);
const { lightning } = firstNetwork().nodes; const { lightning } = firstNetwork().nodes;
expect(lightning.length).toBe(2); expect(lightning.length).toBe(2);
@ -240,7 +240,7 @@ describe('Network model', () => {
); );
}); });
it('should set LND node status to error if the node startup fails', async () => { it('should set lightning node status to error if the node startup fails', async () => {
lightningServiceMock.waitUntilOnline.mockRejectedValue(new Error('test-error')); lightningServiceMock.waitUntilOnline.mockRejectedValue(new Error('test-error'));
const { start } = store.getActions().network; const { start } = store.getActions().network;
const network = firstNetwork(); const network = firstNetwork();

1
src/store/models/network.ts

@ -277,6 +277,7 @@ const networkModel: NetworkModel = {
const newNetworks = networks.filter(n => n.id !== networkId); const newNetworks = networks.filter(n => n.id !== networkId);
actions.setNetworks(newNetworks); actions.setNetworks(newNetworks);
getStoreActions().designer.removeChart(networkId); getStoreActions().designer.removeChart(networkId);
network.nodes.lightning.forEach(n => getStoreActions().lightning.removeNode(n.name));
await actions.save(); await actions.save();
await getStoreActions().app.clearAppCache(); await getStoreActions().app.clearAppCache();
}), }),

42
src/utils/chart.spec.ts

@ -2,15 +2,15 @@ import { IChart, IConfig } from '@mrblenny/react-flow-chart';
import { LightningNodeMapping } from 'store/models/lightning'; import { LightningNodeMapping } from 'store/models/lightning';
import { Network } from 'types'; import { Network } from 'types';
import { defaultStateChannel, defaultStateInfo, getNetwork } from 'utils/tests'; import { defaultStateChannel, defaultStateInfo, getNetwork } from 'utils/tests';
import { initChartFromNetwork, snap, updateChartFromLnd } from './chart'; import { initChartFromNetwork, snap, updateChartFromNodes } from './chart';
describe('Chart Util', () => { describe('Chart Util', () => {
let network: Network; let network: Network;
let chart: IChart; let chart: IChart;
let lndData: LightningNodeMapping; let nodesData: LightningNodeMapping;
const addChannel = (node: string, remotePubkey: string, pending?: boolean) => { const addChannel = (node: string, remotePubkey: string, pending?: boolean) => {
const { channels } = lndData[node]; const { channels } = nodesData[node];
if (channels) { if (channels) {
channels.push( channels.push(
defaultStateChannel({ defaultStateChannel({
@ -30,13 +30,13 @@ describe('Chart Util', () => {
beforeEach(() => { beforeEach(() => {
network = getNetwork(); network = getNetwork();
chart = initChartFromNetwork(network); chart = initChartFromNetwork(network);
lndData = { nodesData = {
[network.nodes.lightning[0].name]: { [network.nodes.lightning[0].name]: {
info: defaultStateInfo({ pubkey: 'lnd1pubkey' }), info: defaultStateInfo({ pubkey: 'ln1pubkey' }),
channels: [], channels: [],
}, },
[network.nodes.lightning[1].name]: { [network.nodes.lightning[1].name]: {
info: defaultStateInfo({ pubkey: 'lnd2pubkey' }), info: defaultStateInfo({ pubkey: 'ln2pubkey' }),
channels: [], channels: [],
}, },
}; };
@ -61,8 +61,8 @@ describe('Chart Util', () => {
describe('updateChartFromNetwork', () => { describe('updateChartFromNetwork', () => {
it('should create link for an open channel', () => { it('should create link for an open channel', () => {
addChannel('alice', 'lnd2pubkey'); addChannel('alice', 'ln2pubkey');
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeDefined(); expect(result.links['xxxxxxxxxx:0']).toBeDefined();
const link = result.links['xxxxxxxxxx:0']; const link = result.links['xxxxxxxxxx:0'];
expect(link.from.nodeId).toBe('alice'); expect(link.from.nodeId).toBe('alice');
@ -73,8 +73,8 @@ describe('Chart Util', () => {
}); });
it('should create link for a pending channel', () => { it('should create link for a pending channel', () => {
addChannel('alice', 'lnd2pubkey', true); addChannel('alice', 'ln2pubkey', true);
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeDefined(); expect(result.links['xxxxxxxxxx:0']).toBeDefined();
const link = result.links['xxxxxxxxxx:0']; const link = result.links['xxxxxxxxxx:0'];
expect(link.from.nodeId).toBe('alice'); expect(link.from.nodeId).toBe('alice');
@ -85,28 +85,28 @@ describe('Chart Util', () => {
}); });
it('should remove links for channels that do not exist', () => { it('should remove links for channels that do not exist', () => {
addChannel('alice', 'lnd2pubkey'); addChannel('alice', 'ln2pubkey');
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeTruthy(); expect(result.links['xxxxxxxxxx:0']).toBeTruthy();
// remove the channel // remove the channel
const node = lndData['alice']; const node = nodesData['alice'];
if (node.channels) node.channels = []; if (node.channels) node.channels = [];
const result2 = updateChartFromLnd(result, lndData); const result2 = updateChartFromNodes(result, nodesData);
expect(result2.links['xxxxxxxxxx:0']).toBeUndefined(); expect(result2.links['xxxxxxxxxx:0']).toBeUndefined();
}); });
it('should make no changes if channels is undefined', () => { it('should make no changes if channels is undefined', () => {
lndData['alice'].channels = undefined; nodesData['alice'].channels = undefined;
lndData['bob'].channels = undefined; nodesData['bob'].channels = undefined;
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
expect(result).toEqual(chart); expect(result).toEqual(chart);
}); });
it('should point link right to left', () => { it('should point link right to left', () => {
chart.nodes['alice'].position.x = 200; chart.nodes['alice'].position.x = 200;
chart.nodes['bob'].position.x = 100; chart.nodes['bob'].position.x = 100;
addChannel('alice', 'lnd2pubkey'); addChannel('alice', 'ln2pubkey');
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
const link = result.links['xxxxxxxxxx:0']; const link = result.links['xxxxxxxxxx:0'];
expect(link.properties.direction).toEqual('rtl'); expect(link.properties.direction).toEqual('rtl');
}); });
@ -114,8 +114,8 @@ describe('Chart Util', () => {
it('should update the node sizes', () => { it('should update the node sizes', () => {
chart.nodes['alice'].size = { width: 100, height: 20 }; chart.nodes['alice'].size = { width: 100, height: 20 };
chart.nodes['bob'].size = undefined; chart.nodes['bob'].size = undefined;
addChannel('alice', 'lnd2pubkey'); addChannel('alice', 'ln2pubkey');
const result = updateChartFromLnd(chart, lndData); const result = updateChartFromNodes(chart, nodesData);
let size = result.nodes['alice'].size; let size = result.nodes['alice'].size;
expect(size).toBeDefined(); expect(size).toBeDefined();
if (size) expect(size.height).toBe(60); if (size) expect(size.height).toBe(60);

11
src/utils/chart.ts

@ -162,13 +162,13 @@ const updateLinksAndPorts = (
}; };
}; };
export const updateChartFromLnd = ( export const updateChartFromNodes = (
chart: IChart, chart: IChart,
lndData: LightningNodeMapping, nodesData: LightningNodeMapping,
): IChart => { ): IChart => {
// create a mapping of node name to pubkey for lookups // create a mapping of node name to pubkey for lookups
const pubkeys: Record<string, string> = {}; const pubkeys: Record<string, string> = {};
Object.entries(lndData).forEach(([name, data]) => { Object.entries(nodesData).forEach(([name, data]) => {
if (!data.info || !data.info.pubkey) return; if (!data.info || !data.info.pubkey) return;
pubkeys[data.info.pubkey] = name; pubkeys[data.info.pubkey] = name;
}); });
@ -178,7 +178,7 @@ export const updateChartFromLnd = (
const createdLinkIds: string[] = []; const createdLinkIds: string[] = [];
// update the node and links for each node // update the node and links for each node
Object.entries(lndData).forEach(([fromName, data]) => { Object.entries(nodesData).forEach(([fromName, data]) => {
const fromNode = nodes[fromName]; const fromNode = nodes[fromName];
if (data.channels) { if (data.channels) {
@ -208,7 +208,6 @@ export const updateChartFromLnd = (
// remove ports for channels that no longer exist // remove ports for channels that no longer exist
Object.values(nodes).forEach(node => { Object.values(nodes).forEach(node => {
if (!node) return;
Object.keys(node.ports).forEach(portId => { Object.keys(node.ports).forEach(portId => {
// don't remove special ports // don't remove special ports
if (['empty-left', 'empty-right', 'backend'].includes(portId)) return; if (['empty-left', 'empty-right', 'backend'].includes(portId)) return;
@ -220,7 +219,7 @@ export const updateChartFromLnd = (
}); });
// resize chart nodes if necessary to fit new ports // resize chart nodes if necessary to fit new ports
Object.keys(lndData).forEach(name => updateNodeSize(nodes[name])); Object.keys(nodesData).forEach(name => updateNodeSize(nodes[name]));
return { return {
...chart, ...chart,

2
src/utils/network.ts

@ -18,7 +18,7 @@ import { range } from './numbers';
export const getContainerName = (node: CommonNode) => export const getContainerName = (node: CommonNode) =>
`polar-n${node.networkId}-${node.name}`; `polar-n${node.networkId}-${node.name}`;
export const groupNodes = (network: Network) => { const groupNodes = (network: Network) => {
const { bitcoin, lightning } = network.nodes; const { bitcoin, lightning } = network.nodes;
return { return {
bitcoind: bitcoin.filter(n => n.implementation === 'bitcoind') as BitcoinNode[], bitcoind: bitcoin.filter(n => n.implementation === 'bitcoind') as BitcoinNode[],

Loading…
Cancel
Save