Files
ObsidianDragon/src/wallet/wallet_capabilities.h
DanS 85a1080b52 feat(lite): Console tab with connection + open/create diagnostics
The lite variant had no visibility into why a wallet failed to open — just a
"disconnected" spinner. Add a lite-only Console tab (full-node keeps its RPC
console) that shows a live diagnostic log.

- LiteDiagnostics: a small thread-safe, bounded ring buffer (header-only). The
  controller writes to it from its background threads: each failover server
  attempt and result, wallet open/create/restore outcomes, sync start, and
  blocked-open reasons. The App logs controller (re)builds with the preferred
  server.
- lite_console_tab: a terminal-styled, read-only view of the log (newest at the
  bottom, error/success lines coloured) with Clear / Copy / Auto-scroll. Reachable
  even when the wallet is locked (it's diagnostics, no secrets). Registered as
  NavPage::LiteConsole, gated lite-only via WalletUiSurface::LiteConsole.

A unit test drives an open-with-failover and asserts the log records the
connection attempt and the successful open. Built clean for full-node, lite, and
Windows cross-compile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 18:46:25 -05:00

184 lines
4.8 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
#ifndef DRAGONX_LITE_BUILD
#define DRAGONX_LITE_BUILD 0
#endif
#ifndef DRAGONX_ENABLE_EMBEDDED_DAEMON
#define DRAGONX_ENABLE_EMBEDDED_DAEMON 1
#endif
#ifndef DRAGONX_ENABLE_LITE_BACKEND
#define DRAGONX_ENABLE_LITE_BACKEND 0
#endif
namespace dragonx {
namespace wallet {
enum class WalletBuildKind {
FullNode,
Lite
};
enum class WalletBackendKind {
FullNodeRpc,
LiteClient
};
enum class WalletUiSurface {
Overview,
Send,
Receive,
History,
Mining,
Market,
Console,
Peers,
Explorer,
Settings,
BootstrapDownload,
SetupWizard,
NodeSettings,
LiteNetwork, // lite-wallet-only server browser (replaces Peers in lite builds)
LiteConsole // lite-wallet-only diagnostics console (full-node uses the RPC Console)
};
struct WalletCapabilities {
WalletBuildKind buildKind = WalletBuildKind::FullNode;
WalletBackendKind backendKind = WalletBackendKind::FullNodeRpc;
bool fullNodeRpcAvailable = true;
bool embeddedDaemonAvailable = true;
bool fullNodePagesAvailable = true;
bool fullNodeLifecycleActionsAvailable = true;
bool soloMiningAvailable = true;
bool poolMiningAvailable = true;
bool liteBackendAvailable = false;
bool lightwalletdNetworkAvailable = false;
bool liteWalletLifecycleAvailable = false;
bool liteWalletSyncAvailable = false;
bool liteWalletSendAvailable = false;
};
constexpr bool isLiteBuild(WalletBuildKind buildKind)
{
return buildKind == WalletBuildKind::Lite;
}
constexpr bool isLiteBuild(const WalletCapabilities& capabilities)
{
return isLiteBuild(capabilities.buildKind);
}
constexpr bool isFullNodeBuild(WalletBuildKind buildKind)
{
return buildKind == WalletBuildKind::FullNode;
}
constexpr WalletCapabilities makeWalletCapabilities(
WalletBuildKind buildKind,
bool embeddedDaemonCompiled,
bool liteBackendLinked)
{
const bool liteBuild = isLiteBuild(buildKind);
const bool fullNodeBuild = !liteBuild;
const bool liteBackendAvailable = liteBuild && liteBackendLinked;
return WalletCapabilities{
buildKind,
liteBuild ? WalletBackendKind::LiteClient : WalletBackendKind::FullNodeRpc,
fullNodeBuild,
fullNodeBuild && embeddedDaemonCompiled,
fullNodeBuild,
fullNodeBuild,
fullNodeBuild,
true,
liteBackendAvailable,
liteBackendAvailable,
liteBackendAvailable,
liteBackendAvailable,
liteBackendAvailable
};
}
constexpr WalletBuildKind currentWalletBuildKind()
{
return DRAGONX_LITE_BUILD ? WalletBuildKind::Lite : WalletBuildKind::FullNode;
}
constexpr WalletCapabilities currentWalletCapabilities()
{
return makeWalletCapabilities(
currentWalletBuildKind(),
DRAGONX_ENABLE_EMBEDDED_DAEMON != 0,
DRAGONX_ENABLE_LITE_BACKEND != 0);
}
constexpr bool supportsEmbeddedDaemon(const WalletCapabilities& capabilities)
{
return capabilities.embeddedDaemonAvailable;
}
constexpr bool supportsFullNodeLifecycleActions(const WalletCapabilities& capabilities)
{
return capabilities.fullNodeLifecycleActionsAvailable;
}
constexpr bool supportsSoloMining(const WalletCapabilities& capabilities)
{
return capabilities.soloMiningAvailable;
}
constexpr bool supportsPoolMining(const WalletCapabilities& capabilities)
{
return capabilities.poolMiningAvailable;
}
constexpr bool supportsLiteBackend(const WalletCapabilities& capabilities)
{
return capabilities.liteBackendAvailable;
}
constexpr bool supportsWalletDataBackend(const WalletCapabilities& capabilities)
{
return capabilities.fullNodeRpcAvailable || capabilities.liteWalletSyncAvailable;
}
constexpr bool isUiSurfaceAvailable(const WalletCapabilities& capabilities,
WalletUiSurface surface)
{
switch (surface) {
case WalletUiSurface::Console:
case WalletUiSurface::Peers:
case WalletUiSurface::Explorer:
return capabilities.fullNodePagesAvailable;
case WalletUiSurface::LiteNetwork:
case WalletUiSurface::LiteConsole:
return !capabilities.fullNodePagesAvailable; // lite builds only
case WalletUiSurface::BootstrapDownload:
case WalletUiSurface::SetupWizard:
case WalletUiSurface::NodeSettings:
return capabilities.fullNodeLifecycleActionsAvailable;
default:
return true;
}
}
constexpr bool uiSurfaceNeedsWalletData(WalletUiSurface surface)
{
switch (surface) {
case WalletUiSurface::Overview:
case WalletUiSurface::Send:
case WalletUiSurface::Receive:
case WalletUiSurface::History:
return true;
default:
return false;
}
}
} // namespace wallet
} // namespace dragonx