nd,ngui: display on-chain balance in bitcoin tab
a previous commit added some lightning tab implementation which including balance details but only for lightning channels. this commit queries lnd for a wallet balance and displays it on the bitcoin tab since "wallet" funds are on-chain and it doesn't feel like it belongs to the lightning tab in the UI. while there, also improved some daemon backend code style, alightning with the lightning implementation structures.pull/27/head v0.4.0
parent
05c89bbd1c
commit
116fb3b59c
|
@ -150,7 +150,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
btcrpc.strip = strip;
|
btcrpc.strip = strip;
|
||||||
btcrpc.addModule("bitcoindrpc", b.createModule(.{ .source_file = .{ .path = "src/nd/bitcoindrpc.zig" } }));
|
btcrpc.addModule("bitcoindrpc", b.createModule(.{ .source_file = .{ .path = "src/bitcoindrpc.zig" } }));
|
||||||
|
|
||||||
const btcrpc_build_step = b.step("btcrpc", "bitcoind RPC client playground");
|
const btcrpc_build_step = b.step("btcrpc", "bitcoind RPC client playground");
|
||||||
btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc, .{}).step);
|
btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc, .{}).step);
|
||||||
|
|
|
@ -5,6 +5,8 @@ const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const Atomic = std.atomic.Atomic;
|
const Atomic = std.atomic.Atomic;
|
||||||
const base64enc = std.base64.standard.Encoder;
|
const base64enc = std.base64.standard.Encoder;
|
||||||
|
|
||||||
|
const types = @import("types.zig");
|
||||||
|
|
||||||
pub const Client = struct {
|
pub const Client = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
cookiepath: []const u8,
|
cookiepath: []const u8,
|
||||||
|
@ -55,7 +57,7 @@ pub const Client = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn Result(comptime m: Method) type {
|
pub fn Result(comptime m: Method) type {
|
||||||
return std.json.Parsed(ResultValue(m));
|
return types.Deinitable(ResultValue(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ResultValue(comptime m: Method) type {
|
pub fn ResultValue(comptime m: Method) type {
|
||||||
|
@ -133,9 +135,12 @@ pub const Client = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseResponse(self: Client, comptime m: Method, b: []const u8) !Result(m) {
|
fn parseResponse(self: Client, comptime m: Method, b: []const u8) !Result(m) {
|
||||||
const jopt = std.json.ParseOptions{ .ignore_unknown_fields = true, .allocate = .alloc_always };
|
var resp = try types.Deinitable(RpcResponse(m)).init(self.allocator);
|
||||||
const resp = try std.json.parseFromSlice(RpcResponse(m), self.allocator, b, jopt);
|
|
||||||
errdefer resp.deinit();
|
errdefer resp.deinit();
|
||||||
|
resp.value = try std.json.parseFromSliceLeaky(RpcResponse(m), self.allocator, b, .{
|
||||||
|
.ignore_unknown_fields = true,
|
||||||
|
.allocate = .alloc_always,
|
||||||
|
});
|
||||||
if (resp.value.@"error") |errfield| {
|
if (resp.value.@"error") |errfield| {
|
||||||
return rpcErrorFromCode(errfield.code) orelse error.UnknownError;
|
return rpcErrorFromCode(errfield.code) orelse error.UnknownError;
|
||||||
}
|
}
|
15
src/comm.zig
15
src/comm.zig
|
@ -27,7 +27,7 @@ pub const Message = union(MessageTag) {
|
||||||
network_report: NetworkReport,
|
network_report: NetworkReport,
|
||||||
get_network_report: GetNetworkReport,
|
get_network_report: GetNetworkReport,
|
||||||
poweroff_progress: PoweroffProgress,
|
poweroff_progress: PoweroffProgress,
|
||||||
bitcoind_report: BitcoindReport,
|
bitcoind_report: BitcoinReport,
|
||||||
lightning_report: LightningReport,
|
lightning_report: LightningReport,
|
||||||
|
|
||||||
pub const WifiConnect = struct {
|
pub const WifiConnect = struct {
|
||||||
|
@ -55,7 +55,7 @@ pub const Message = union(MessageTag) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BitcoindReport = struct {
|
pub const BitcoinReport = struct {
|
||||||
blocks: u64,
|
blocks: u64,
|
||||||
headers: u64,
|
headers: u64,
|
||||||
timestamp: u64, // unix epoch
|
timestamp: u64, // unix epoch
|
||||||
|
@ -81,6 +81,17 @@ pub const Message = union(MessageTag) {
|
||||||
minfee: f32, // BTC/kvB
|
minfee: f32, // BTC/kvB
|
||||||
fullrbf: bool,
|
fullrbf: bool,
|
||||||
},
|
},
|
||||||
|
/// on-chain balance, all values in satoshis.
|
||||||
|
/// may not be available due to disabled wallet, if bitcoin core is used,
|
||||||
|
/// or lnd turned off/nonfunctional.
|
||||||
|
balance: ?struct {
|
||||||
|
source: enum { lnd, bitcoincore },
|
||||||
|
total: i64,
|
||||||
|
confirmed: i64,
|
||||||
|
unconfirmed: i64,
|
||||||
|
locked: i64, // output leases
|
||||||
|
reserved: i64, // for fee bumps
|
||||||
|
} = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const LightningReport = struct {
|
pub const LightningReport = struct {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
|
||||||
|
/// safe for concurrent use as long as Client.allocator is.
|
||||||
pub const Client = struct {
|
pub const Client = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
hostname: []const u8 = "localhost",
|
hostname: []const u8 = "localhost",
|
||||||
|
@ -307,6 +308,7 @@ pub const PendingChannel = struct {
|
||||||
// local_chan_reserve_sat, remote_chan_reserve_sat, initiator, chan_status_flags, memo
|
// local_chan_reserve_sat, remote_chan_reserve_sat, initiator, chan_status_flags, memo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// on-chain balance, in satoshis.
|
||||||
pub const WalletBalance = struct {
|
pub const WalletBalance = struct {
|
||||||
total_balance: i64,
|
total_balance: i64,
|
||||||
confirmed_balance: i64,
|
confirmed_balance: i64,
|
||||||
|
|
|
@ -15,13 +15,13 @@ const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const time = std.time;
|
const time = std.time;
|
||||||
|
|
||||||
|
const bitcoindrpc = @import("../bitcoindrpc.zig");
|
||||||
const comm = @import("../comm.zig");
|
const comm = @import("../comm.zig");
|
||||||
|
const lndhttp = @import("../lndhttp.zig");
|
||||||
const network = @import("network.zig");
|
const network = @import("network.zig");
|
||||||
const screen = @import("../ui/screen.zig");
|
const screen = @import("../ui/screen.zig");
|
||||||
const types = @import("../types.zig");
|
|
||||||
const SysService = @import("SysService.zig");
|
const SysService = @import("SysService.zig");
|
||||||
const bitcoindrpc = @import("bitcoindrpc.zig");
|
const types = @import("../types.zig");
|
||||||
const lndhttp = @import("../lndhttp.zig");
|
|
||||||
|
|
||||||
const logger = std.log.scoped(.daemon);
|
const logger = std.log.scoped(.daemon);
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ want_wifi_scan: bool, // initiate wifi scan at the next loop cycle
|
||||||
network_report_ready: bool, // indicates whether the network status is ready to be sent
|
network_report_ready: bool, // indicates whether the network status is ready to be sent
|
||||||
wifi_scan_in_progress: bool = false,
|
wifi_scan_in_progress: bool = false,
|
||||||
wpa_save_config_on_connected: bool = false,
|
wpa_save_config_on_connected: bool = false,
|
||||||
// bitcoin flags
|
// bitcoin fields
|
||||||
want_bitcoind_report: bool,
|
want_bitcoind_report: bool,
|
||||||
bitcoin_timer: time.Timer,
|
bitcoin_timer: time.Timer,
|
||||||
bitcoin_report_interval: u64 = 1 * time.ns_per_min,
|
bitcoin_report_interval: u64 = 1 * time.ns_per_min,
|
||||||
// lightning flags
|
// lightning fields
|
||||||
want_lnd_report: bool,
|
want_lnd_report: bool,
|
||||||
lnd_timer: time.Timer,
|
lnd_timer: time.Timer,
|
||||||
lnd_report_interval: u64 = 1 * time.ns_per_min,
|
lnd_report_interval: u64 = 1 * time.ns_per_min,
|
||||||
|
@ -530,7 +530,19 @@ fn sendBitcoindReport(self: *Daemon) !void {
|
||||||
const mempool = try client.call(.getmempoolinfo, {});
|
const mempool = try client.call(.getmempoolinfo, {});
|
||||||
defer mempool.deinit();
|
defer mempool.deinit();
|
||||||
|
|
||||||
const btcrep: comm.Message.BitcoindReport = .{
|
const balance: ?lndhttp.WalletBalance = blk: {
|
||||||
|
var lndc = lndhttp.Client.init(.{
|
||||||
|
.allocator = self.allocator,
|
||||||
|
.tlscert_path = "/home/lnd/.lnd/tls.cert",
|
||||||
|
.macaroon_ro_path = "/ssd/lnd/data/chain/bitcoin/mainnet/readonly.macaroon",
|
||||||
|
}) catch break :blk null;
|
||||||
|
defer lndc.deinit();
|
||||||
|
const res = lndc.call(.walletbalance, {}) catch break :blk null;
|
||||||
|
defer res.deinit();
|
||||||
|
break :blk res.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const btcrep: comm.Message.BitcoinReport = .{
|
||||||
.blocks = bcinfo.value.blocks,
|
.blocks = bcinfo.value.blocks,
|
||||||
.headers = bcinfo.value.headers,
|
.headers = bcinfo.value.headers,
|
||||||
.timestamp = bcinfo.value.time,
|
.timestamp = bcinfo.value.time,
|
||||||
|
@ -554,6 +566,14 @@ fn sendBitcoindReport(self: *Daemon) !void {
|
||||||
.minfee = mempool.value.mempoolminfee,
|
.minfee = mempool.value.mempoolminfee,
|
||||||
.fullrbf = mempool.value.fullrbf,
|
.fullrbf = mempool.value.fullrbf,
|
||||||
},
|
},
|
||||||
|
.balance = if (balance) |bal| .{
|
||||||
|
.source = .lnd,
|
||||||
|
.total = bal.total_balance,
|
||||||
|
.confirmed = bal.confirmed_balance,
|
||||||
|
.unconfirmed = bal.unconfirmed_balance,
|
||||||
|
.locked = bal.locked_balance,
|
||||||
|
.reserved = bal.reserved_balance_anchor_chan,
|
||||||
|
} else null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try comm.write(self.allocator, self.uiwriter, .{ .bitcoind_report = btcrep });
|
try comm.write(self.allocator, self.uiwriter, .{ .bitcoind_report = btcrep });
|
||||||
|
|
|
@ -140,7 +140,7 @@ fn commWriteThread(gpa: std.mem.Allocator, w: anytype) !void {
|
||||||
block_count += 1;
|
block_count += 1;
|
||||||
const now = time.timestamp();
|
const now = time.timestamp();
|
||||||
|
|
||||||
const btcrep: comm.Message.BitcoindReport = .{
|
const btcrep: comm.Message.BitcoinReport = .{
|
||||||
.blocks = block_count,
|
.blocks = block_count,
|
||||||
.headers = block_count,
|
.headers = block_count,
|
||||||
.timestamp = @intCast(now),
|
.timestamp = @intCast(now),
|
||||||
|
@ -162,6 +162,14 @@ fn commWriteThread(gpa: std.mem.Allocator, w: anytype) !void {
|
||||||
.minfee = 0.00004155,
|
.minfee = 0.00004155,
|
||||||
.fullrbf = false,
|
.fullrbf = false,
|
||||||
},
|
},
|
||||||
|
.balance = .{
|
||||||
|
.source = .lnd,
|
||||||
|
.total = 800000,
|
||||||
|
.confirmed = 350000,
|
||||||
|
.unconfirmed = 350000,
|
||||||
|
.locked = 0,
|
||||||
|
.reserved = 100000,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
comm.write(gpa, w, .{ .bitcoind_report = btcrep }) catch |err| logger.err("comm.write: {any}", .{err});
|
comm.write(gpa, w, .{ .bitcoind_report = btcrep }) catch |err| logger.err("comm.write: {any}", .{err});
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,17 @@ var tab: struct {
|
||||||
currblock: lvgl.Label,
|
currblock: lvgl.Label,
|
||||||
timestamp: lvgl.Label,
|
timestamp: lvgl.Label,
|
||||||
blockhash: lvgl.Label,
|
blockhash: lvgl.Label,
|
||||||
// usage section
|
|
||||||
diskusage: lvgl.Label,
|
diskusage: lvgl.Label,
|
||||||
conn_in: lvgl.Label,
|
conn_in: lvgl.Label,
|
||||||
conn_out: lvgl.Label,
|
conn_out: lvgl.Label,
|
||||||
|
balance: struct {
|
||||||
|
avail_bar: lvgl.Bar,
|
||||||
|
avail_pct: lvgl.Label,
|
||||||
|
total: lvgl.Label,
|
||||||
|
unconf: lvgl.Label,
|
||||||
|
locked: lvgl.Label,
|
||||||
|
reserved: lvgl.Label,
|
||||||
|
},
|
||||||
// mempool section
|
// mempool section
|
||||||
mempool: struct {
|
mempool: struct {
|
||||||
txcount: lvgl.Label,
|
txcount: lvgl.Label,
|
||||||
|
@ -41,16 +48,49 @@ pub fn initTabPanel(cont: lvgl.Container) !void {
|
||||||
const card = try lvgl.Card.new(parent, "BLOCKCHAIN");
|
const card = try lvgl.Card.new(parent, "BLOCKCHAIN");
|
||||||
const row = try lvgl.FlexLayout.new(card, .row, .{});
|
const row = try lvgl.FlexLayout.new(card, .row, .{});
|
||||||
row.setWidth(lvgl.sizePercent(100));
|
row.setWidth(lvgl.sizePercent(100));
|
||||||
|
row.setHeightToContent();
|
||||||
row.clearFlag(.scrollable);
|
row.clearFlag(.scrollable);
|
||||||
|
// left column
|
||||||
const left = try lvgl.FlexLayout.new(row, .column, .{});
|
const left = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
left.setWidth(lvgl.sizePercent(50));
|
left.setWidth(lvgl.sizePercent(50));
|
||||||
|
left.setHeightToContent();
|
||||||
left.setPad(10, .row, .{});
|
left.setPad(10, .row, .{});
|
||||||
tab.currblock = try lvgl.Label.new(left, "HEIGHT\n", .{ .recolor = true });
|
tab.currblock = try lvgl.Label.new(left, "HEIGHT\n", .{ .recolor = true });
|
||||||
tab.timestamp = try lvgl.Label.new(left, "TIMESTAMP\n", .{ .recolor = true });
|
tab.timestamp = try lvgl.Label.new(left, "TIMESTAMP\n", .{ .recolor = true });
|
||||||
tab.blockhash = try lvgl.Label.new(row, "BLOCK HASH\n", .{ .recolor = true });
|
tab.blockhash = try lvgl.Label.new(left, "BLOCK HASH\n", .{ .recolor = true });
|
||||||
tab.blockhash.flexGrow(1);
|
// right column
|
||||||
|
const right = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
|
right.setWidth(lvgl.sizePercent(50));
|
||||||
|
right.setHeightToContent();
|
||||||
|
right.setPad(10, .row, .{});
|
||||||
|
tab.diskusage = try lvgl.Label.new(right, "DISK USAGE\n", .{ .recolor = true });
|
||||||
|
tab.conn_in = try lvgl.Label.new(right, "CONNECTIONS IN\n", .{ .recolor = true });
|
||||||
|
tab.conn_out = try lvgl.Label.new(right, "CONNECTIONS OUT\n", .{ .recolor = true });
|
||||||
|
}
|
||||||
|
// balance section
|
||||||
|
{
|
||||||
|
const card = try lvgl.Card.new(parent, "ON-CHAIN BALANCE");
|
||||||
|
const row = try lvgl.FlexLayout.new(card, .row, .{});
|
||||||
|
row.setWidth(lvgl.sizePercent(100));
|
||||||
|
row.setHeightToContent();
|
||||||
|
row.clearFlag(.scrollable);
|
||||||
|
// left column
|
||||||
|
const left = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
|
left.setWidth(lvgl.sizePercent(50));
|
||||||
|
left.setPad(8, .top, .{});
|
||||||
|
left.setPad(10, .row, .{});
|
||||||
|
tab.balance.avail_bar = try lvgl.Bar.new(left);
|
||||||
|
tab.balance.avail_pct = try lvgl.Label.new(left, "AVAILABLE\n", .{ .recolor = true });
|
||||||
|
tab.balance.total = try lvgl.Label.new(left, "TOTAL\n", .{ .recolor = true });
|
||||||
|
// right column
|
||||||
|
const right = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
|
right.setWidth(lvgl.sizePercent(50));
|
||||||
|
right.setHeightToContent();
|
||||||
|
right.setPad(10, .row, .{});
|
||||||
|
tab.balance.locked = try lvgl.Label.new(right, "LOCKED\n", .{ .recolor = true });
|
||||||
|
tab.balance.reserved = try lvgl.Label.new(right, "RESERVED\n", .{ .recolor = true });
|
||||||
|
tab.balance.unconf = try lvgl.Label.new(right, "UNCONFIRMED\n", .{ .recolor = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// mempool section
|
// mempool section
|
||||||
{
|
{
|
||||||
const card = try lvgl.Card.new(parent, "MEMPOOL");
|
const card = try lvgl.Card.new(parent, "MEMPOOL");
|
||||||
|
@ -69,34 +109,43 @@ pub fn initTabPanel(cont: lvgl.Container) !void {
|
||||||
tab.mempool.txcount = try lvgl.Label.new(right, "TRANSACTIONS COUNT\n", .{ .recolor = true });
|
tab.mempool.txcount = try lvgl.Label.new(right, "TRANSACTIONS COUNT\n", .{ .recolor = true });
|
||||||
tab.mempool.totalfee = try lvgl.Label.new(right, "TOTAL FEES\n", .{ .recolor = true });
|
tab.mempool.totalfee = try lvgl.Label.new(right, "TOTAL FEES\n", .{ .recolor = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// usage section
|
|
||||||
{
|
|
||||||
const card = try lvgl.Card.new(parent, "USAGE");
|
|
||||||
const row = try lvgl.FlexLayout.new(card, .row, .{});
|
|
||||||
row.setWidth(lvgl.sizePercent(100));
|
|
||||||
row.clearFlag(.scrollable);
|
|
||||||
const left = try lvgl.FlexLayout.new(row, .column, .{});
|
|
||||||
left.setWidth(lvgl.sizePercent(50));
|
|
||||||
left.setPad(10, .row, .{});
|
|
||||||
tab.diskusage = try lvgl.Label.new(left, "DISK USAGE\n", .{ .recolor = true });
|
|
||||||
const right = try lvgl.FlexLayout.new(row, .column, .{});
|
|
||||||
right.setWidth(lvgl.sizePercent(50));
|
|
||||||
right.setPad(10, .row, .{});
|
|
||||||
tab.conn_in = try lvgl.Label.new(right, "CONNECTIONS IN\n", .{ .recolor = true });
|
|
||||||
tab.conn_out = try lvgl.Label.new(right, "CONNECTIONS OUT\n", .{ .recolor = true });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// updates the tab with new data from the report.
|
/// updates the tab with new data from the report.
|
||||||
/// the tab must be inited first with initTabPanel.
|
/// the tab must be inited first with initTabPanel.
|
||||||
pub fn updateTabPanel(rep: comm.Message.BitcoindReport) !void {
|
pub fn updateTabPanel(rep: comm.Message.BitcoinReport) !void {
|
||||||
var buf: [512]u8 = undefined;
|
var buf: [512]u8 = undefined;
|
||||||
|
|
||||||
// blockchain section
|
// blockchain section
|
||||||
try tab.currblock.setTextFmt(&buf, cmark ++ "HEIGHT#\n{d}", .{rep.blocks});
|
try tab.currblock.setTextFmt(&buf, cmark ++ "HEIGHT#\n{d}", .{rep.blocks});
|
||||||
try tab.timestamp.setTextFmt(&buf, cmark ++ "TIMESTAMP#\n{}", .{xfmt.unix(rep.timestamp)});
|
try tab.timestamp.setTextFmt(&buf, cmark ++ "TIMESTAMP#\n{}", .{xfmt.unix(rep.timestamp)});
|
||||||
try tab.blockhash.setTextFmt(&buf, cmark ++ "BLOCK HASH#\n{s}\n{s}", .{ rep.hash[0..32], rep.hash[32..] });
|
try tab.blockhash.setTextFmt(&buf, cmark ++ "BLOCK HASH#\n{s}\n{s}", .{ rep.hash[0..32], rep.hash[32..] });
|
||||||
|
try tab.diskusage.setTextFmt(&buf, cmark ++ "DISK USAGE#\n{:.1}", .{fmt.fmtIntSizeBin(rep.diskusage)});
|
||||||
|
try tab.conn_in.setTextFmt(&buf, cmark ++ "CONNECTIONS IN#\n{d}", .{rep.conn_in});
|
||||||
|
try tab.conn_out.setTextFmt(&buf, cmark ++ "CONNECTIONS OUT#\n{d}", .{rep.conn_out});
|
||||||
|
|
||||||
|
// balance section
|
||||||
|
if (rep.balance) |bal| {
|
||||||
|
const confpct: f32 = pct: {
|
||||||
|
if (bal.confirmed > bal.total) {
|
||||||
|
break :pct 100;
|
||||||
|
}
|
||||||
|
if (bal.total == 0) {
|
||||||
|
break :pct 0;
|
||||||
|
}
|
||||||
|
const v = @as(f64, @floatFromInt(bal.confirmed)) / @as(f64, @floatFromInt(bal.total));
|
||||||
|
break :pct @floatCast(v * 100);
|
||||||
|
};
|
||||||
|
tab.balance.avail_bar.setValue(@as(i32, @intFromFloat(@round(confpct))));
|
||||||
|
try tab.balance.avail_pct.setTextFmt(&buf, cmark ++ "AVAILABLE#\n{} sat ({d:.1}%)", .{
|
||||||
|
xfmt.imetric(bal.confirmed),
|
||||||
|
confpct,
|
||||||
|
});
|
||||||
|
try tab.balance.total.setTextFmt(&buf, cmark ++ "TOTAL#\n{} sat", .{xfmt.imetric(bal.total)});
|
||||||
|
try tab.balance.unconf.setTextFmt(&buf, cmark ++ "UNCONFIRMED#\n{} sat", .{xfmt.imetric(bal.unconfirmed)});
|
||||||
|
try tab.balance.locked.setTextFmt(&buf, cmark ++ "LOCKED#\n{} sat", .{xfmt.imetric(bal.locked)});
|
||||||
|
try tab.balance.reserved.setTextFmt(&buf, cmark ++ "RESERVED#\n{} sat", .{xfmt.imetric(bal.reserved)});
|
||||||
|
}
|
||||||
|
|
||||||
// mempool section
|
// mempool section
|
||||||
const mempool_pct: f32 = pct: {
|
const mempool_pct: f32 = pct: {
|
||||||
|
@ -117,9 +166,4 @@ pub fn updateTabPanel(rep: comm.Message.BitcoindReport) !void {
|
||||||
});
|
});
|
||||||
try tab.mempool.txcount.setTextFmt(&buf, cmark ++ "TRANSACTIONS COUNT#\n{d}", .{rep.mempool.txcount});
|
try tab.mempool.txcount.setTextFmt(&buf, cmark ++ "TRANSACTIONS COUNT#\n{d}", .{rep.mempool.txcount});
|
||||||
try tab.mempool.totalfee.setTextFmt(&buf, cmark ++ "TOTAL FEES#\n{d:10} BTC", .{rep.mempool.totalfee});
|
try tab.mempool.totalfee.setTextFmt(&buf, cmark ++ "TOTAL FEES#\n{d:10} BTC", .{rep.mempool.totalfee});
|
||||||
|
|
||||||
// usage section
|
|
||||||
try tab.diskusage.setTextFmt(&buf, cmark ++ "DISK USAGE#\n{:.1}", .{fmt.fmtIntSizeBin(rep.diskusage)});
|
|
||||||
try tab.conn_in.setTextFmt(&buf, cmark ++ "CONNECTIONS IN#\n{d}", .{rep.conn_in});
|
|
||||||
try tab.conn_out.setTextFmt(&buf, cmark ++ "CONNECTIONS OUT#\n{d}", .{rep.conn_out});
|
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue