Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/src/api/btc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ export async function get_balance(tag: string) {
return await btcCmd("GetBalance", tag);
}

export async function get_transaction_status(tag: string, txid: string) {
return await btcCmd("GetTransactionStatus", tag, { txid });
}
1 change: 1 addition & 0 deletions app/src/api/cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type Cmd =
| "ListUsers"
| "AddUser"
| "GetInfo"
| "GetTransactionStatus"
| "GetContainerLogs"
| "TestMine"
| "ListChannels"
Expand Down
1 change: 1 addition & 0 deletions app/src/api/lnd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface LndChannel {
close_address?: string;
push_amount_sat?: number;
thaw_height?: number;
confirmation?: number;
}

export interface LndPeer {
Expand Down
33 changes: 27 additions & 6 deletions app/src/helpers/bitcoin.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
export async function getTransactionStatus(txid) {
import * as BTC from "../api/btc";

type BitcoinNetwork = "bitcoin" | "regtest";

function mempoolApiBase(network: BitcoinNetwork) {
return network === "bitcoin"
? "https://mempool.space/api"
: "https://mempool.space/testnet/api";
}

export async function getTransactionStatus(
txid: string,
network: BitcoinNetwork,
btcTag: string
) {
if (network === "regtest") {
return await BTC.get_transaction_status(btcTag, txid);
}

const res = await fetch(
`https://mempool.space/testnet/api/tx/${txid}/status`
`${mempoolApiBase(network)}/tx/${txid}/status`
);
const status = await res.json();
return status;
}

export async function getBlockTip() {
const res = await fetch(
`https://mempool.space/testnet/api/blocks/tip/height`
);
export async function getBlockTip(network: BitcoinNetwork, btcTag: string) {
if (network === "regtest") {
const info = await BTC.get_info(btcTag);
return info.blocks;
}

const res = await fetch(`${mempoolApiBase(network)}/blocks/tip/height`);
const status = await res.json();
return status;
}
49 changes: 39 additions & 10 deletions app/src/lnd/ChannelRows.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import ReceiveLine from "../components/ReceiveLine.svelte";
import DotWrap from "../components/DotWrap.svelte";
import Dot from "../components/Dot.svelte";
import { channels, lightningPeers, peers } from "../store";
import { channels, lightningPeers, peers, stack } from "../store";
import { formatSatsNumbers } from "../helpers";
import { getTransactionStatus, getBlockTip } from "../helpers/bitcoin";
import Exit from "carbon-icons-svelte/lib/Exit.svelte";
Expand All @@ -27,7 +27,24 @@
export let type = "";
export let onclose = (id: string, dest: string) => {};

let channel_arr = $channels[tag];
let channel_arr = $channels[tag] || [];

$: channel_arr = $channels[tag] || [];
$: btcTag = getBitcoinTag();

function getBitcoinTag() {
const nodes = $stack.nodes || [];
const lightningNode = nodes.find((node) => node.name === tag);
const linkedBitcoin = lightningNode?.links?.find((link) =>
nodes.some((node) => node.name === link && node.type === "Btc")
);
return (
linkedBitcoin ||
nodes.find((node) => node.type === "Btc" && node.place === "Internal")
?.name ||
"bitcoind"
);
}

$: peersObj = convertLightningPeersToObject($lightningPeers);

Expand Down Expand Up @@ -106,12 +123,18 @@
return 0;
}
let tx_id = channel_point_arr[0];
const transaction_status = await getTransactionStatus(tx_id);
const transaction_status = await getTransactionStatus(
tx_id,
$stack.network,
btcTag
);
if (!transaction_status.confirmed) {
return 0;
}
const currentBlockHeight = await getBlockTip();
return currentBlockHeight - transaction_status.block_height + 1;
const currentBlockHeight = await getBlockTip($stack.network, btcTag);
return transaction_status.block_height != null
? currentBlockHeight - transaction_status.block_height + 1
: transaction_status.confirmations || 0;
} catch (e) {
console.warn(e);
return 0;
Expand All @@ -120,17 +143,23 @@

async function getChannelsConfirmation() {
let new_channel = [];
let notActiveExist = false;
let updated = false;

for (const chan of channel_arr) {
if (!chan.active) {
notActiveExist = true;
const confirmation = await getConfirmation(chan);
new_channel.push({ ...chan, confirmation });
updated = updated || chan.confirmation !== confirmation;
} else {
new_channel.push(chan);
}
}
// if (notActiveExist) {
// channel_arr = [...new_channel];
// }

if (updated) {
channels.update((chans) => {
return { ...chans, [tag]: new_channel };
});
}
}

function openReconnectPeerModal(e, pubkey) {
Expand Down
20 changes: 19 additions & 1 deletion app/src/lnd/Channels.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,33 @@
}
}

function keepChannelConfirmations(newChannels: LND.LndChannel[]) {
const confirmationsByPoint = new Map(
($channels[tag] || []).map((channel) => [
channel.channel_point,
channel.confirmation,
])
);

return newChannels.map((channel) => {
const confirmation = confirmationsByPoint.get(channel.channel_point);
if (!channel.active && confirmation != null) {
return { ...channel, confirmation };
}
return channel;
});
}

async function getChannels() {
let newChannels = [];
let newChannels: LND.LndChannel[] = [];
if (type === "Cln") {
const peersData = await CLN.list_peer_channels(tag);
newChannels = await parseClnListPeerChannelsRes(peersData);
} else {
const channelsData = await getLndPendingAndActiveChannels(tag);
newChannels = channelsData;
}
newChannels = keepChannelConfirmations(newChannels);
if (JSON.stringify(newChannels) !== JSON.stringify($channels[tag])) {
channels.update((chans) => {
return { ...chans, [tag]: newChannels };
Expand Down
6 changes: 6 additions & 0 deletions src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,18 @@ pub struct GetInvoice {
pub payment_hash: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GetTransactionStatus {
pub txid: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "cmd", content = "content")]
pub enum BitcoindCmd {
GetInfo,
TestMine(TestMine),
GetBalance,
GetTransactionStatus(GetTransactionStatus),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down
30 changes: 29 additions & 1 deletion src/conn/bitcoin/bitcoinrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ extern crate bitcoincore_rpc;

use crate::images::btc::BtcImage;
use anyhow::Result;
use bitcoincore_rpc::bitcoin::{Address, BlockHash};
use bitcoincore_rpc::bitcoin::{Address, BlockHash, Txid};
use bitcoincore_rpc::{Auth, Client, RpcApi};
use bitcoincore_rpc_json::{AddressType, GetBlockchainInfoResult};
use serde::Serialize;
use std::str::FromStr;

pub struct BitcoinRPC(Client);

#[derive(Serialize)]
pub struct TransactionStatus {
pub confirmed: bool,
pub block_height: Option<u32>,
pub confirmations: u32,
}

impl BitcoinRPC {
pub fn new(btc: &BtcImage, url: &str, port: &str) -> Result<Self> {
let btc_url: String = format!("{}:{}", url, port);
Expand All @@ -32,6 +40,26 @@ impl BitcoinRPC {
Ok(self.0.get_blockchain_info()?)
}

pub fn get_transaction_status(&self, txid: String) -> Result<TransactionStatus> {
let txid = Txid::from_str(&txid)?;
let transaction = self.0.get_raw_transaction_info(&txid, None)?;
let confirmations = transaction.confirmations.unwrap_or(0);
let block_height = transaction
.blockhash
.map(|block_hash| {
self.0
.get_block_header_info(&block_hash)
.map(|b| b.height as u32)
})
.transpose()?;

Ok(TransactionStatus {
confirmed: confirmations > 0,
block_height,
confirmations,
})
}

pub fn create_or_load_wallet(&self) -> Result<()> {
let wallet = "wallet";
// try to create, otherwise load
Expand Down
4 changes: 4 additions & 0 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,10 @@ pub async fn handle(
let res = client.get_wallet_balance()?;
Some(serde_json::to_string(&res)?)
}
BitcoindCmd::GetTransactionStatus(ts) => {
let res = client.get_transaction_status(ts.txid)?;
Some(serde_json::to_string(&res)?)
}
}
}
Cmd::Lnd(c) => {
Expand Down