Browse Source

feat: make lightning nodes p2p port reachable on LAN

This commit changes lightning nodes to accept p2p connections
via LAN instead of only via the private network (172.x.x.x).
master
Hampus Sjöberg 5 years ago
committed by jamaljsr
parent
commit
20d77ebc70
  1. 15
      src/components/designer/lightning/ConnectTab.tsx
  2. 3
      src/i18n/locales/en-US.json
  3. 23
      src/lib/docker/composeFile.ts
  4. 1
      src/lib/docker/nodeTemplates.spec.ts
  5. 4
      src/lib/docker/nodeTemplates.ts
  6. 2
      src/shared/types.ts
  7. 2
      src/utils/constants.ts
  8. 19
      src/utils/network.spec.ts
  9. 29
      src/utils/network.ts

15
src/components/designer/lightning/ConnectTab.tsx

@ -40,6 +40,7 @@ export interface ConnectionInfo {
readOnly?: string;
cert?: string;
};
p2pUriExternal: string;
}
interface Props {
@ -51,8 +52,9 @@ const ConnectTab: React.FC<Props> = ({ node }) => {
const [authType, setAuthType] = useState<string>('paths');
const { openInBrowser } = useStoreActions(s => s.app);
const nodeState = useStoreState(s => s.lightning.nodes[node.name]);
const pubkey = nodeState && nodeState.info ? nodeState.info.pubkey : '';
const p2pLnUrlInternal = nodeState && nodeState.info ? nodeState.info.rpcUrl : '';
const lnUrl = nodeState && nodeState.info ? nodeState.info.rpcUrl : '';
const info = useMemo((): ConnectionInfo => {
if (node.status === Status.Started) {
if (node.implementation === 'LND') {
@ -67,6 +69,7 @@ const ConnectTab: React.FC<Props> = ({ node }) => {
readOnly: lnd.paths.readonlyMacaroon,
cert: lnd.paths.tlsCert,
},
p2pUriExternal: `${pubkey}@127.0.0.1:${lnd.ports.p2p}`,
};
} else if (node.implementation === 'c-lightning') {
const cln = node as CLightningNode;
@ -76,6 +79,7 @@ const ConnectTab: React.FC<Props> = ({ node }) => {
credentials: {
admin: cln.paths.macaroon,
},
p2pUriExternal: `${pubkey}@127.0.0.1:${cln.ports.p2p}`,
};
}
}
@ -85,7 +89,7 @@ const ConnectTab: React.FC<Props> = ({ node }) => {
restDocsUrl: '',
credentials: {},
} as ConnectionInfo;
}, [node]);
}, [node, pubkey]);
if (node.status !== Status.Started) {
return <>{l('notStarted')}</>;
@ -95,7 +99,12 @@ const ConnectTab: React.FC<Props> = ({ node }) => {
const hosts: DetailValues = [
[l('grpcHost'), grpcUrl, grpcUrl],
[l('restHost'), restUrl, restUrl],
[l('p2pLnUrl'), lnUrl, ellipseInner(lnUrl, 3, 19)],
[l('p2pLnUrlInternal'), info.p2pUriExternal, ellipseInner(p2pLnUrlInternal, 3, 17)],
[
l('p2pLnUrlExternal'),
info.p2pUriExternal,
ellipseInner(info.p2pUriExternal, 3, 17),
],
]
.filter(h => !!h[1]) // exclude empty values
.map(([label, value, text]) => ({

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

@ -180,7 +180,8 @@
"cmps.designer.lightning.ConnectTab.notStarted": "Node needs to be started to view connection info",
"cmps.designer.lightning.ConnectTab.grpcHost": "GRPC Host",
"cmps.designer.lightning.ConnectTab.restHost": "REST Host",
"cmps.designer.lightning.ConnectTab.p2pLnUrl": "P2P LN Url",
"cmps.designer.lightning.ConnectTab.p2pLnUrlInternal": "P2P Internal",
"cmps.designer.lightning.ConnectTab.p2pLnUrlExternal": "P2P External",
"cmps.designer.lightning.ConnectTab.apiDocs": "API Docs",
"cmps.designer.lightning.ConnectTab.filePaths": "File Paths",
"cmps.designer.lightning.ConnectTab.hexStrings": "HEX",

23
src/lib/docker/composeFile.ts

@ -49,22 +49,37 @@ class ComposeFile {
const {
name,
version,
ports: { rest, grpc },
ports: { rest, grpc, p2p },
} = node;
const container = getContainerName(node);
const backendName = getContainerName(backend);
this.content.services[name] = lnd(name, container, version, backendName, rest, grpc);
this.content.services[name] = lnd(
name,
container,
version,
backendName,
rest,
grpc,
p2p,
);
}
addClightning(node: CLightningNode, backend: CommonNode) {
const {
name,
version,
ports: { rest },
ports: { rest, p2p },
} = node;
const container = getContainerName(node);
const backendName = getContainerName(backend);
this.content.services[name] = clightning(name, container, version, backendName, rest);
this.content.services[name] = clightning(
name,
container,
version,
backendName,
rest,
p2p,
);
}
}

1
src/lib/docker/nodeTemplates.spec.ts

@ -17,6 +17,7 @@ describe('nodeTemplates', () => {
'btcnode1',
8080,
10009,
9735,
);
expect(node.image).toContain('lnd');
expect(node.container_name).toEqual('polar-mynode');

4
src/lib/docker/nodeTemplates.ts

@ -62,6 +62,7 @@ export const lnd = (
backendName: string,
restPort: number,
grpcPort: number,
p2pPort: number,
): ComposeService => ({
image: `polarlightning/lnd:${version}`,
container_name: container,
@ -99,6 +100,7 @@ export const lnd = (
ports: [
`${restPort}:8080`, // REST
`${grpcPort}:10009`, // gRPC
`${p2pPort}:9735`, // p2p
],
});
@ -108,6 +110,7 @@ export const clightning = (
version: string,
backendName: string,
restPort: number,
p2pPort: number,
): ComposeService => ({
image: `polarlightning/clightning:${version}`,
container_name: container,
@ -143,5 +146,6 @@ export const clightning = (
],
ports: [
`${restPort}:8080`, // REST
`${p2pPort}:9735`, // p2p
],
});

2
src/shared/types.ts

@ -33,6 +33,7 @@ export interface LndNode extends LightningNode {
ports: {
rest: number;
grpc: number;
p2p: number;
};
}
@ -42,6 +43,7 @@ export interface CLightningNode extends LightningNode {
};
ports: {
rest: number;
p2p: number;
};
}

2
src/utils/constants.ts

@ -51,9 +51,11 @@ export const BasePorts = {
lnd: {
rest: 8081,
grpc: 10001,
p2p: 9735,
},
clightning: {
rest: 8181,
p2p: 9835,
},
};

19
src/utils/network.spec.ts

@ -49,6 +49,8 @@ describe('Network Utils', () => {
const ports = (await getOpenPorts(network)) as OpenPorts;
expect(ports).toBeDefined();
expect(ports[network.nodes.bitcoin[0].name].rpc).toBe(restPort + 1);
expect(ports[network.nodes.bitcoin[0].name].zmqBlock).toBeUndefined();
expect(ports[network.nodes.bitcoin[0].name].zmqTx).toBeUndefined();
});
it('should update the zmq block port for bitcoind', async () => {
@ -60,7 +62,9 @@ describe('Network Utils', () => {
const zmqBlockPort = network.nodes.bitcoin[0].ports.zmqBlock;
const ports = (await getOpenPorts(network)) as OpenPorts;
expect(ports).toBeDefined();
expect(ports[network.nodes.bitcoin[0].name].rest).toBeUndefined();
expect(ports[network.nodes.bitcoin[0].name].zmqBlock).toBe(zmqBlockPort + 1);
expect(ports[network.nodes.bitcoin[0].name].zmqTx).toBeUndefined();
});
it('should update the zmq tx port for bitcoind', async () => {
@ -72,6 +76,8 @@ describe('Network Utils', () => {
const zmqTxPort = network.nodes.bitcoin[0].ports.zmqTx;
const ports = (await getOpenPorts(network)) as OpenPorts;
expect(ports).toBeDefined();
expect(ports[network.nodes.bitcoin[0].name].rest).toBeUndefined();
expect(ports[network.nodes.bitcoin[0].name].zmqBlock).toBeUndefined();
expect(ports[network.nodes.bitcoin[0].name].zmqTx).toBe(zmqTxPort + 1);
});
@ -99,6 +105,19 @@ describe('Network Utils', () => {
expect(ports[network.nodes.lightning[2].name].rest).toBe(8083);
});
it('should update the p2p ports for lightning nodes', async () => {
const portsInUse = [9735, 9836, 9737];
mockDetectPort.mockImplementation(port =>
Promise.resolve(portsInUse.includes(port) ? port + 1 : port),
);
network.nodes.bitcoin = [];
const ports = (await getOpenPorts(network)) as OpenPorts;
expect(ports).toBeDefined();
expect(ports[network.nodes.lightning[0].name].p2p).toBe(9736);
expect(ports[network.nodes.lightning[1].name].p2p).toBe(9837);
expect(ports[network.nodes.lightning[2].name].p2p).toBe(9738);
});
it('should not update ports if none are in use', async () => {
const portsInUse: number[] = [];
mockDetectPort.mockImplementation(port =>

29
src/utils/network.ts

@ -103,6 +103,7 @@ export const createLndNetworkNode = (
ports: {
rest: BasePorts.lnd.rest + id,
grpc: BasePorts.lnd.grpc + id,
p2p: BasePorts.lnd.p2p + id,
},
};
};
@ -139,6 +140,7 @@ export const createCLightningNetworkNode = (
},
ports: {
rest: BasePorts.clightning.rest + id,
p2p: BasePorts.clightning.p2p + id,
},
};
};
@ -277,6 +279,7 @@ export interface OpenPorts {
rest?: number;
zmqBlock?: number;
zmqTx?: number;
p2p?: number;
};
}
@ -345,17 +348,39 @@ export const getOpenPorts = async (network: Network): Promise<OpenPorts | undefi
};
});
}
existingPorts = lnd.map(n => n.ports.p2p);
openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => {
ports[lnd[index].name] = {
...(ports[lnd[index].name] || {}),
p2p: port,
};
});
}
}
clightning = clightning.filter(n => n.status !== Status.Started);
if (clightning.length) {
const existingPorts = clightning.map(n => n.ports.rest);
const openPorts = await getOpenPortRange(existingPorts);
let existingPorts = clightning.map(n => n.ports.rest);
let openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => {
ports[clightning[index].name] = { rest: port };
});
}
existingPorts = clightning.map(n => n.ports.p2p);
openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => {
ports[clightning[index].name] = {
...(ports[clightning[index].name] || {}),
p2p: port,
};
});
}
}
// return undefined if no ports where updated

Loading…
Cancel
Save