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
- 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 option to auto-mine every X minutes
- switch renovatebot to dependabot and use automatic security fixes
- generate alice/bob/carol names for lnd nodes
- display docker streaming logs in the UI
- 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)
@ -16,7 +20,7 @@ Bigger things
- create a splash page website for lightningpolar.com
- add block explorer (https://github.com/janoside/btc-rpc-explorer)
- 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)
- 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)

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

@ -46,7 +46,7 @@ describe('NetworkDesigner Component', () => {
expect(await findByText('backend')).toBeInTheDocument();
});
it('should render correct # of LND nodes', async () => {
it('should render correct # of lightning nodes', async () => {
const { findByText } = renderComponent();
expect(await findByText('alice')).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 { Status } from 'shared/types';
import * as files from 'utils/files';
import { groupNodes } from 'utils/network';
import {
defaultStateBalances,
defaultStateInfo,
@ -15,7 +14,7 @@ import LightningDetails from './LightningDetails';
jest.mock('utils/files');
describe('LndDetails', () => {
describe('LightningDetails', () => {
const renderComponent = (status?: Status) => {
const network = getNetwork(1, 'test network', status);
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 result = renderWithProviders(cmp, { initialState });
return {
@ -185,7 +184,7 @@ describe('LndDetails', () => {
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);
const { getByText, queryByText, findByText } = renderComponent(Status.Started);
fireEvent.click(await findByText('Info'));

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

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

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

@ -8,7 +8,7 @@ import { format } from 'utils/units';
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 [amount, setAmount] = useState(1000000);
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 { DockerLibrary } from 'types';
import { initChartFromNetwork } from 'utils/chart';
import { groupNodes } from 'utils/network';
import {
getNetwork,
injections,
@ -32,8 +31,8 @@ describe('RemoveNode', () => {
activeId: 1,
},
};
const { lnd } = groupNodes(network);
const node = lnd[status === Status.Started ? 0 : 1];
const { lightning } = network.nodes;
const node = lightning[status === Status.Started ? 0 : 1];
const cmp = <RemoveNode node={node} />;
const result = renderWithProviders(cmp, { initialState });
return {

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

@ -8,37 +8,37 @@ describe('Backend component', () => {
const renderComponent = () => {
const network = getNetwork();
const bitcoind = network.nodes.bitcoin[0];
const lnd = network.nodes.lightning[0];
const result = render(<Backend bitcoinNode={bitcoind} lightningNode={lnd} />);
const lightning = network.nodes.lightning[0];
const result = render(<Backend bitcoinNode={bitcoind} lightningNode={lightning} />);
return {
...result,
bitcoind,
lnd,
lightning,
};
};
describe('LND Details', () => {
describe('Lightning Details', () => {
it('should display Name', () => {
const { getByText, lnd } = renderComponent();
expect(getByText(lnd.name)).toBeInTheDocument();
const { getByText, lightning } = renderComponent();
expect(getByText(lightning.name)).toBeInTheDocument();
});
it('should display Implementation', () => {
const { getByText, getAllByText, lnd } = renderComponent();
const { getByText, getAllByText, lightning } = renderComponent();
expect(getAllByText('Implementation')).toHaveLength(2);
expect(getByText(lnd.implementation)).toBeInTheDocument();
expect(getByText(lightning.implementation)).toBeInTheDocument();
});
it('should display Version', () => {
const { getByText, getAllByText, lnd } = renderComponent();
const { getByText, getAllByText, lightning } = renderComponent();
expect(getAllByText('Version')).toHaveLength(2);
expect(getByText(`v${lnd.version}`)).toBeInTheDocument();
expect(getByText(`v${lightning.version}`)).toBeInTheDocument();
});
it('should display Status', () => {
const { getAllByText, lnd } = renderComponent();
const { getAllByText, lightning } = renderComponent();
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 { Button, Modal } from 'antd';
import { usePrefixedTranslation } from 'hooks';
import { LightningNode, LndNode, Status } from 'shared/types';
import { LightningNode, Status } from 'shared/types';
import { useStoreActions } from 'store';
import { LinkProperties } from 'utils/chart';
import { ellipseInner } from 'utils/strings';
@ -38,7 +38,7 @@ const Channel: React.FC<Props> = ({ link, from, to }) => {
cancelText: l('closeChanCancelBtn'),
onOk: async () => {
try {
await closeChannel({ node: from as LndNode, channelPoint });
await closeChannel({ node: from, channelPoint });
notify({ message: l('closeChanSuccess') });
} catch (error) {
notify({ message: l('closeChanError'), error });

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

@ -1,14 +1,13 @@
import React from 'react';
import { fireEvent, wait } from '@testing-library/dom';
import { ipcChannels } from 'shared';
import { BitcoinNode, LndNode } from 'shared/types';
import { BitcoinNode, LightningNode } from 'shared/types';
import { Network } from 'types';
import { groupNodes } from 'utils/network';
import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import OpenTerminalButton from './OpenTerminalButton';
describe('OpenTerminalButton', () => {
const renderComponent = (nodeSelector: (n: Network) => LndNode | BitcoinNode) => {
const renderComponent = (nodeSelector: (n: Network) => LightningNode | BitcoinNode) => {
const network = getNetwork(1, 'test network');
return renderWithProviders(<OpenTerminalButton node={nodeSelector(network)} />);
};
@ -30,7 +29,7 @@ describe('OpenTerminalButton', () => {
});
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");
expect(help).toBeInTheDocument();
});

3
src/components/terminal/OpenTerminalButton.tsx

@ -21,6 +21,9 @@ const OpenTerminalButton: React.FC<Props> = ({ node }) => {
case 'LND':
cmd = 'lncli';
break;
case 'c-lightning':
cmd = 'lightning-cli';
break;
case 'bitcoind':
cmd = 'bitcoin-cli';
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 ComposeFile from './composeFile';
@ -6,7 +6,7 @@ describe('ComposeFile', () => {
let composeFile = new ComposeFile();
const network = getNetwork();
const btcNode = network.nodes.bitcoin[0];
const lndNode = groupNodes(network).lnd[0];
const lndNode = network.nodes.lightning[0] as LndNode;
beforeEach(() => {
composeFile = new ComposeFile();

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

@ -235,13 +235,6 @@ describe('DockerService', () => {
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 () => {
composeMock.down.mockResolvedValue(mockResult);
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));
}
for (const node of lightning) {
if (node.implementation === 'LND') {
await ensureDir(join(network.path, 'volumes', 'lnd', node.name));
}
const volDir = node.implementation.toLocaleLowerCase().replace('-', '');
await ensureDir(join(network.path, 'volumes', volDir, node.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 { LndNode } from 'shared/types';
import { IpcSender } from 'lib/ipc/ipcService';
import { groupNodes } from 'utils/network';
import { getNetwork } from 'utils/tests';
import lndProxyClient from './lndProxyClient';
describe('LndService', () => {
const node = groupNodes(getNetwork()).lnd[0];
const node = getNetwork().nodes.lightning[0] as LndNode;
let actualIpc: IpcSender;
beforeEach(() => {

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

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

9
src/store/models/designer.ts

@ -13,7 +13,12 @@ import {
} from 'easy-peasy';
import { LndNode, Status } from 'shared/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 { prefixTranslation } from 'utils/translate';
import { RootModel } from './';
@ -104,7 +109,7 @@ const designerModel: DesignerModel = {
const nodesData = getStoreState().lightning.nodes;
const { allCharts } = getState();
// 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({
...allCharts,
[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 bitcoindServiceMock = injections.bitcoindService as jest.Mocked<BitcoindLibrary>;
describe('LND Model', () => {
describe('Lightning Model', () => {
const rootModel = {
network: networkModel,
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
const { rpcUrl } = getStoreState().lightning.nodes[to.name]
.info as LightningNodeInfo;
// open the channel via LND
// open the channel via lightning node
const api = injections.lightningFactory.getService(from);
await api.openChannel(from, rpcUrl, sats);
// 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);
});
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);
const { lightning } = firstNetwork().nodes;
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'));
const { start } = store.getActions().network;
const network = firstNetwork();

1
src/store/models/network.ts

@ -277,6 +277,7 @@ const networkModel: NetworkModel = {
const newNetworks = networks.filter(n => n.id !== networkId);
actions.setNetworks(newNetworks);
getStoreActions().designer.removeChart(networkId);
network.nodes.lightning.forEach(n => getStoreActions().lightning.removeNode(n.name));
await actions.save();
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 { Network } from 'types';
import { defaultStateChannel, defaultStateInfo, getNetwork } from 'utils/tests';
import { initChartFromNetwork, snap, updateChartFromLnd } from './chart';
import { initChartFromNetwork, snap, updateChartFromNodes } from './chart';
describe('Chart Util', () => {
let network: Network;
let chart: IChart;
let lndData: LightningNodeMapping;
let nodesData: LightningNodeMapping;
const addChannel = (node: string, remotePubkey: string, pending?: boolean) => {
const { channels } = lndData[node];
const { channels } = nodesData[node];
if (channels) {
channels.push(
defaultStateChannel({
@ -30,13 +30,13 @@ describe('Chart Util', () => {
beforeEach(() => {
network = getNetwork();
chart = initChartFromNetwork(network);
lndData = {
nodesData = {
[network.nodes.lightning[0].name]: {
info: defaultStateInfo({ pubkey: 'lnd1pubkey' }),
info: defaultStateInfo({ pubkey: 'ln1pubkey' }),
channels: [],
},
[network.nodes.lightning[1].name]: {
info: defaultStateInfo({ pubkey: 'lnd2pubkey' }),
info: defaultStateInfo({ pubkey: 'ln2pubkey' }),
channels: [],
},
};
@ -61,8 +61,8 @@ describe('Chart Util', () => {
describe('updateChartFromNetwork', () => {
it('should create link for an open channel', () => {
addChannel('alice', 'lnd2pubkey');
const result = updateChartFromLnd(chart, lndData);
addChannel('alice', 'ln2pubkey');
const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeDefined();
const link = result.links['xxxxxxxxxx:0'];
expect(link.from.nodeId).toBe('alice');
@ -73,8 +73,8 @@ describe('Chart Util', () => {
});
it('should create link for a pending channel', () => {
addChannel('alice', 'lnd2pubkey', true);
const result = updateChartFromLnd(chart, lndData);
addChannel('alice', 'ln2pubkey', true);
const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeDefined();
const link = result.links['xxxxxxxxxx:0'];
expect(link.from.nodeId).toBe('alice');
@ -85,28 +85,28 @@ describe('Chart Util', () => {
});
it('should remove links for channels that do not exist', () => {
addChannel('alice', 'lnd2pubkey');
const result = updateChartFromLnd(chart, lndData);
addChannel('alice', 'ln2pubkey');
const result = updateChartFromNodes(chart, nodesData);
expect(result.links['xxxxxxxxxx:0']).toBeTruthy();
// remove the channel
const node = lndData['alice'];
const node = nodesData['alice'];
if (node.channels) node.channels = [];
const result2 = updateChartFromLnd(result, lndData);
const result2 = updateChartFromNodes(result, nodesData);
expect(result2.links['xxxxxxxxxx:0']).toBeUndefined();
});
it('should make no changes if channels is undefined', () => {
lndData['alice'].channels = undefined;
lndData['bob'].channels = undefined;
const result = updateChartFromLnd(chart, lndData);
nodesData['alice'].channels = undefined;
nodesData['bob'].channels = undefined;
const result = updateChartFromNodes(chart, nodesData);
expect(result).toEqual(chart);
});
it('should point link right to left', () => {
chart.nodes['alice'].position.x = 200;
chart.nodes['bob'].position.x = 100;
addChannel('alice', 'lnd2pubkey');
const result = updateChartFromLnd(chart, lndData);
addChannel('alice', 'ln2pubkey');
const result = updateChartFromNodes(chart, nodesData);
const link = result.links['xxxxxxxxxx:0'];
expect(link.properties.direction).toEqual('rtl');
});
@ -114,8 +114,8 @@ describe('Chart Util', () => {
it('should update the node sizes', () => {
chart.nodes['alice'].size = { width: 100, height: 20 };
chart.nodes['bob'].size = undefined;
addChannel('alice', 'lnd2pubkey');
const result = updateChartFromLnd(chart, lndData);
addChannel('alice', 'ln2pubkey');
const result = updateChartFromNodes(chart, nodesData);
let size = result.nodes['alice'].size;
expect(size).toBeDefined();
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,
lndData: LightningNodeMapping,
nodesData: LightningNodeMapping,
): IChart => {
// create a mapping of node name to pubkey for lookups
const pubkeys: Record<string, string> = {};
Object.entries(lndData).forEach(([name, data]) => {
Object.entries(nodesData).forEach(([name, data]) => {
if (!data.info || !data.info.pubkey) return;
pubkeys[data.info.pubkey] = name;
});
@ -178,7 +178,7 @@ export const updateChartFromLnd = (
const createdLinkIds: string[] = [];
// update the node and links for each node
Object.entries(lndData).forEach(([fromName, data]) => {
Object.entries(nodesData).forEach(([fromName, data]) => {
const fromNode = nodes[fromName];
if (data.channels) {
@ -208,7 +208,6 @@ export const updateChartFromLnd = (
// remove ports for channels that no longer exist
Object.values(nodes).forEach(node => {
if (!node) return;
Object.keys(node.ports).forEach(portId => {
// don't remove special ports
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
Object.keys(lndData).forEach(name => updateNodeSize(nodes[name]));
Object.keys(nodesData).forEach(name => updateNodeSize(nodes[name]));
return {
...chart,

2
src/utils/network.ts

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

Loading…
Cancel
Save