Browse Source

feat(clightning): implement c-lightning getChannels

master
jamaljsr 5 years ago
parent
commit
181b62e459
  1. 4
      src/components/terminal/DockerTerminal.tsx
  2. 58
      src/lib/clightning/clightningService.ts
  3. 40
      src/lib/clightning/types.ts
  4. 8
      src/lib/lightning/types.ts

4
src/components/terminal/DockerTerminal.tsx

@ -66,6 +66,10 @@ const nodeConfig: Record<string, { user: string; alias: string }> = {
user: 'lnd',
alias: 'alias lncli="lncli --network regtest"',
},
'c-lightning': {
user: 'clightning',
alias: '',
},
bitcoind: {
user: 'bitcoin',
alias: 'alias bitcoin-cli="bitcoin-cli -regtest"',

58
src/lib/clightning/clightningService.ts

@ -13,6 +13,18 @@ import { read } from 'utils/files';
import { snakeKeysToCamel } from 'utils/objects';
import * as CLN from './types';
const ChannelStateToStatus: Record<CLN.ChannelState, LightningNodeChannel['status']> = {
CHANNELD_AWAITING_LOCKIN: 'Opening',
CHANNELD_NORMAL: 'Open',
CHANNELD_SHUTTING_DOWN: 'Closing',
CLOSINGD_SIGEXCHANGE: 'Closing',
CLOSINGD_COMPLETE: 'Waiting to Close',
AWAITING_UNILATERAL: 'Force Closing',
FUNDING_SPEND_SEEN: 'Waiting to Close',
ONCHAIN: 'Closed',
CLOSED: 'Closed',
};
class CLightningService implements LightningService {
async getInfo(node: LightningNode): Promise<LightningNodeInfo> {
const info = await this.request<CLN.GetInfoResponse>(node, 'getinfo');
@ -20,7 +32,7 @@ class CLightningService implements LightningService {
pubkey: info.id,
alias: info.alias,
rpcUrl: '',
syncedToChain: !info.warningBitcoindSync,
syncedToChain: !info.warningBitcoindSync && !info.warningLightningdSync,
numActiveChannels: info.numActiveChannels,
numPendingChannels: info.numPendingChannels,
numInactiveChannels: info.numInactiveChannels,
@ -37,12 +49,30 @@ class CLightningService implements LightningService {
}
async getNewAddress(node: LightningNode): Promise<LightningNodeAddress> {
const address = await this.request<string>(node, 'getNewAddress');
return { address };
const address = await this.request<LightningNodeAddress>(node, 'newaddr');
return address;
}
async getChannels(node: LightningNode): Promise<LightningNodeChannel[]> {
throw new Error(`getChannels is not implemented for ${node.implementation} nodes`);
const channels = await this.request<CLN.GetChannelsResponse[]>(
node,
'channel/listChannels',
);
return channels
.filter(c => ChannelStateToStatus[c.state] !== 'Closed')
.map(c => {
const status = ChannelStateToStatus[c.state];
return {
pending: status !== 'Open',
uniqueId: c.fundingTxid.slice(-12),
channelPoint: c.fundingTxid,
pubkey: c.id,
capacity: this.toSats(c.msatoshiTotal),
localBalance: this.toSats(c.msatoshiToUs),
remoteBalance: this.toSats(c.msatoshiTotal - c.msatoshiToUs),
status,
};
});
}
async openChannel(
@ -52,11 +82,25 @@ class CLightningService implements LightningService {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
amount: string,
): Promise<LightningNodeChannelPoint> {
/* Sample output
{
"tx": "020000000001018375970adb157e76bdf1214d7b874dd7870fc29fc7797be37965ffd2dc534d4f0100000000ffffffff0290d0030000000000220020af14c0deff170638da0652d69766cbe38cfc1e9653f5297723ea717379ed6fc116710b000000000016001406586c3ae5327631466f3db75f949416c2c03e8502483045022100f6066c5a93363b0888aaf6abf02e77ffcb590f2bf2d6a7d9ee6dc6984332a3760220310ef982ccc6f8d04905863dba9e850f5e77af4c935ee624d9bda385da134b83012103016ad498f69789e2fb373fdedaa06c1a3acde26c4e810509357677e91d91aaf100000000",
"txid": "2b15604898e54dd0157d01a08b8f4cd1862b621506e80eb078b92c7259033bcd",
"channel_id": "cd3b0359722cb978b00ee80615622b86d14c8f8ba0017d15d04de5984860152b"
}
*/
throw new Error(`openChannel is not implemented for ${from.implementation} nodes`);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async closeChannel(node: LightningNode, channelPoint: string): Promise<any> {
/* - sample response
{
"tx": "0200000001c1c2feecdd65ad005f97879c31a78fa2570ba7c2182358ee1016730e3e38cb920000000000ffffffff013949020000000000160014548e6cc35fa2e56dd33b7c072c88eb9da155a7f600000000",
"txid": "bdcd0bde6f4bfbb7bd9f69387583c3273cecbe897c237c8a7893e67c215be671",
"type": "mutual"
}
*/
throw new Error(`closeChannel is not implemented for ${node.implementation} nodes`);
}
@ -91,10 +135,14 @@ class CLightningService implements LightningService {
},
});
const json = await response.json();
debug(` - resp: ${JSON.stringify(json)}`);
debug(` - resp: ${JSON.stringify(json, null, 2)}`);
return snakeKeysToCamel(json) as T;
}
private toSats(msats: number): string {
return (msats / 1000).toString();
}
private cast(node: LightningNode): CLightningNode {
if (node.implementation !== 'c-lightning')
throw new Error(

40
src/lib/clightning/types.ts

@ -18,6 +18,7 @@ export interface GetInfoResponse {
msatoshiFeesCollected: number;
feesCollectedMsat: string;
warningBitcoindSync: string;
warningLightningdSync: string;
}
export interface GetBalanceResponse {
@ -25,3 +26,42 @@ export interface GetBalanceResponse {
confBalance: number;
unconfBalance: number;
}
/**
* Source: https://github.com/ElementsProject/lightning/blob/master/lightningd/channel_state.h
*/
export enum ChannelState {
/* In channeld, still waiting for lockin. */
CHANNELD_AWAITING_LOCKIN = 'CHANNELD_AWAITING_LOCKIN',
/* Normal operating state. */
CHANNELD_NORMAL = 'CHANNELD_NORMAL',
/* We are closing. pending HTLC resolution. */
CHANNELD_SHUTTING_DOWN = 'CHANNELD_SHUTTING_DOWN',
/* Exchanging signatures on closing tx. */
CLOSINGD_SIGEXCHANGE = 'CLOSINGD_SIGEXCHANGE',
/* Waiting for onchain event. */
CLOSINGD_COMPLETE = 'CLOSINGD_COMPLETE',
/* Waiting for unilateral close to hit blockchain. */
AWAITING_UNILATERAL = 'AWAITING_UNILATERAL',
/* We've seen the funding spent. we're waiting for onchaind. */
FUNDING_SPEND_SEEN = 'FUNDING_SPEND_SEEN',
/* On chain */
ONCHAIN = 'ONCHAIN',
/* Final state after we have fully settled on-chain */
CLOSED = 'CLOSED',
}
export interface GetChannelsResponse {
alias: string;
channelId: string;
connected: boolean;
fundingTxid: string;
id: string;
msatoshiToUs: number;
msatoshiTotal: number;
ourChannelReserveSatoshis: number;
private: boolean;
shortChannelId: string;
spendableMsatoshi: number;
state: ChannelState;
theirChannelReserveSatoshis: number;
}

8
src/lib/lightning/types.ts

@ -26,7 +26,13 @@ export interface LightningNodeChannel {
capacity: string;
localBalance: string;
remoteBalance: string;
status: 'Open' | 'Opening' | 'Closing' | 'Force Closing' | 'Waiting to Close';
status:
| 'Open'
| 'Opening'
| 'Closing'
| 'Force Closing'
| 'Waiting to Close'
| 'Closed';
}
export interface LightningNodeChannelPoint {

Loading…
Cancel
Save