daemon version check, idle mining control, bootstrap mirror, import key paste, and cleanup

- Add startup binary version checking for dragonxd/xmrig
- Display daemon version in UI
- Add idle mining thread count adjustment
- Add bootstrap mirror option (bootstrap2.dragonx.is) in setup wizard
- Add paste button to import private key dialog with address validation
- Add z-address generation UI feedback (loading indicator)
- Add option to delete blockchain data while preserving wallet.dat
- Add font scale slider hotkey tooltip (Ctrl+Plus/Ctrl+Minus)
- Fix Windows RPC auth: trim \r from config values, add .cookie fallback
- Fix connection status message during block index loading
- Improve application shutdown to prevent lingering background process
This commit is contained in:
2026-03-17 14:57:12 -05:00
parent 1b97476a54
commit 40dd6d45b2
27 changed files with 897 additions and 2050 deletions

View File

@@ -144,6 +144,37 @@ int extractBundledThemes(const std::string& destDir)
return count;
}
int updateBundledThemes(const std::string& dir)
{
namespace fs = std::filesystem;
int count = 0;
const auto* themes = getEmbeddedThemes();
if (!themes || !themes->data) return 0;
if (!fs::exists(dir)) return 0;
for (const auto* t = themes; t->data != nullptr; ++t) {
fs::path dest = fs::path(dir) / t->filename;
if (!fs::exists(dest)) {
// New theme not yet on disk — extract it
} else {
std::error_code ec;
auto diskSize = fs::file_size(dest, ec);
if (!ec && diskSize == static_cast<std::uintmax_t>(t->size))
continue; // up to date
}
std::ofstream f(dest, std::ios::binary);
if (f.is_open()) {
f.write(reinterpret_cast<const char*>(t->data), t->size);
f.close();
DEBUG_LOGF("[INFO] EmbeddedResources: Updated stale theme: %s (%zu bytes)\n",
t->filename, t->size);
count++;
}
}
return count;
}
std::string getParamsDirectory()
{
#ifdef _WIN32
@@ -169,6 +200,9 @@ std::string getParamsDirectory()
#endif
}
// Forward declaration — defined below extractResource()
static bool resourceNeedsUpdate(const EmbeddedResource* res, const std::string& destPath);
bool needsParamsExtraction()
{
if (!hasEmbeddedResources()) {
@@ -177,21 +211,46 @@ bool needsParamsExtraction()
// Check daemon directory (dragonx/) — the only extraction target
std::string daemonDir = getDaemonDirectory();
std::string spendPath = daemonDir +
#ifdef _WIN32
"\\sapling-spend.params";
const char pathSep = '\\';
#else
"/sapling-spend.params";
#endif
std::string outputPath = daemonDir +
#ifdef _WIN32
"\\sapling-output.params";
#else
"/sapling-output.params";
const char pathSep = '/';
#endif
std::string spendPath = daemonDir + pathSep + RESOURCE_SAPLING_SPEND;
std::string outputPath = daemonDir + pathSep + RESOURCE_SAPLING_OUTPUT;
// Check if both params exist in daemon directory
return !std::filesystem::exists(spendPath) || !std::filesystem::exists(outputPath);
// Check if params are missing or stale (size mismatch → updated in newer build)
const auto* spendRes = getEmbeddedResource(RESOURCE_SAPLING_SPEND);
const auto* outputRes = getEmbeddedResource(RESOURCE_SAPLING_OUTPUT);
if (spendRes && resourceNeedsUpdate(spendRes, spendPath)) return true;
if (outputRes && resourceNeedsUpdate(outputRes, outputPath)) return true;
// Also check if daemon binaries need updating
#ifdef HAS_EMBEDDED_DAEMON
const auto* daemonRes = getEmbeddedResource(RESOURCE_DRAGONXD);
std::string daemonPath = daemonDir + pathSep + RESOURCE_DRAGONXD;
if (daemonRes && resourceNeedsUpdate(daemonRes, daemonPath)) return true;
#endif
#ifdef HAS_EMBEDDED_XMRIG
const auto* xmrigRes = getEmbeddedResource(RESOURCE_XMRIG);
std::string xmrigPath = daemonDir + pathSep + RESOURCE_XMRIG;
if (xmrigRes && resourceNeedsUpdate(xmrigRes, xmrigPath)) return true;
#endif
return false;
}
// Check if an on-disk file is missing or differs in size from the embedded resource.
// A size mismatch means the binary was updated in a newer wallet build.
static bool resourceNeedsUpdate(const EmbeddedResource* res, const std::string& destPath)
{
if (!res || !res->data || res->size == 0) return false;
if (!std::filesystem::exists(destPath)) return true;
std::error_code ec;
auto diskSize = std::filesystem::file_size(destPath, ec);
if (ec) return true; // can't stat → re-extract
return diskSize != static_cast<std::uintmax_t>(res->size);
}
static bool extractResource(const EmbeddedResource* res, const std::string& destPath)
@@ -251,7 +310,7 @@ bool extractEmbeddedResources()
const EmbeddedResource* spendRes = getEmbeddedResource(RESOURCE_SAPLING_SPEND);
if (spendRes) {
std::string dest = daemonDir + pathSep + RESOURCE_SAPLING_SPEND;
if (!std::filesystem::exists(dest)) {
if (resourceNeedsUpdate(spendRes, dest)) {
DEBUG_LOGF("[INFO] Extracting sapling-spend.params (%zu MB)...\n", spendRes->size / (1024*1024));
if (!extractResource(spendRes, dest)) {
success = false;
@@ -262,7 +321,7 @@ bool extractEmbeddedResources()
const EmbeddedResource* outputRes = getEmbeddedResource(RESOURCE_SAPLING_OUTPUT);
if (outputRes) {
std::string dest = daemonDir + pathSep + RESOURCE_SAPLING_OUTPUT;
if (!std::filesystem::exists(dest)) {
if (resourceNeedsUpdate(outputRes, dest)) {
DEBUG_LOGF("[INFO] Extracting sapling-output.params (%zu MB)...\n", outputRes->size / (1024*1024));
if (!extractResource(outputRes, dest)) {
success = false;
@@ -274,7 +333,7 @@ bool extractEmbeddedResources()
const EmbeddedResource* asmapRes = getEmbeddedResource(RESOURCE_ASMAP);
if (asmapRes) {
std::string dest = daemonDir + pathSep + RESOURCE_ASMAP;
if (!std::filesystem::exists(dest)) {
if (resourceNeedsUpdate(asmapRes, dest)) {
DEBUG_LOGF("[INFO] Extracting asmap.dat...\n");
if (!extractResource(asmapRes, dest)) {
success = false;
@@ -291,33 +350,48 @@ bool extractEmbeddedResources()
const EmbeddedResource* daemonRes = getEmbeddedResource(RESOURCE_DRAGONXD);
if (daemonRes) {
std::string dest = daemonDir + pathSep + RESOURCE_DRAGONXD;
if (!std::filesystem::exists(dest)) {
DEBUG_LOGF("[INFO] Extracting dragonxd.exe (%zu MB)...\n", daemonRes->size / (1024*1024));
if (resourceNeedsUpdate(daemonRes, dest)) {
if (std::filesystem::exists(dest))
DEBUG_LOGF("[INFO] Updating stale dragonxd (size mismatch)...\n");
DEBUG_LOGF("[INFO] Extracting dragonxd (%zu MB)...\n", daemonRes->size / (1024*1024));
if (!extractResource(daemonRes, dest)) {
success = false;
}
#ifndef _WIN32
else { chmod(dest.c_str(), 0755); }
#endif
}
}
const EmbeddedResource* cliRes = getEmbeddedResource(RESOURCE_DRAGONX_CLI);
if (cliRes) {
std::string dest = daemonDir + pathSep + RESOURCE_DRAGONX_CLI;
if (!std::filesystem::exists(dest)) {
DEBUG_LOGF("[INFO] Extracting dragonx-cli.exe (%zu MB)...\n", cliRes->size / (1024*1024));
if (resourceNeedsUpdate(cliRes, dest)) {
if (std::filesystem::exists(dest))
DEBUG_LOGF("[INFO] Updating stale dragonx-cli (size mismatch)...\n");
DEBUG_LOGF("[INFO] Extracting dragonx-cli (%zu MB)...\n", cliRes->size / (1024*1024));
if (!extractResource(cliRes, dest)) {
success = false;
}
#ifndef _WIN32
else { chmod(dest.c_str(), 0755); }
#endif
}
}
const EmbeddedResource* txRes = getEmbeddedResource(RESOURCE_DRAGONX_TX);
if (txRes) {
std::string dest = daemonDir + pathSep + RESOURCE_DRAGONX_TX;
if (!std::filesystem::exists(dest)) {
DEBUG_LOGF("[INFO] Extracting dragonx-tx.exe (%zu MB)...\n", txRes->size / (1024*1024));
if (resourceNeedsUpdate(txRes, dest)) {
if (std::filesystem::exists(dest))
DEBUG_LOGF("[INFO] Updating stale dragonx-tx (size mismatch)...\n");
DEBUG_LOGF("[INFO] Extracting dragonx-tx (%zu MB)...\n", txRes->size / (1024*1024));
if (!extractResource(txRes, dest)) {
success = false;
}
#ifndef _WIN32
else { chmod(dest.c_str(), 0755); }
#endif
}
}
#endif
@@ -326,11 +400,16 @@ bool extractEmbeddedResources()
const EmbeddedResource* xmrigRes = getEmbeddedResource(RESOURCE_XMRIG);
if (xmrigRes) {
std::string dest = daemonDir + pathSep + RESOURCE_XMRIG;
if (!std::filesystem::exists(dest)) {
DEBUG_LOGF("[INFO] Extracting xmrig.exe (%zu MB)...\n", xmrigRes->size / (1024*1024));
if (resourceNeedsUpdate(xmrigRes, dest)) {
if (std::filesystem::exists(dest))
DEBUG_LOGF("[INFO] Updating stale xmrig (size mismatch)...\n");
DEBUG_LOGF("[INFO] Extracting xmrig (%zu MB)...\n", xmrigRes->size / (1024*1024));
if (!extractResource(xmrigRes, dest)) {
success = false;
}
#ifndef _WIN32
else { chmod(dest.c_str(), 0755); }
#endif
}
}
#endif
@@ -360,7 +439,8 @@ bool needsDaemonExtraction()
#else
std::string daemonPath = daemonDir + "/dragonxd";
#endif
return !std::filesystem::exists(daemonPath);
const auto* res = getEmbeddedResource(RESOURCE_DRAGONXD);
return resourceNeedsUpdate(res, daemonPath);
#else
return false;
#endif
@@ -426,7 +506,8 @@ bool needsXmrigExtraction()
#else
std::string xmrigPath = daemonDir + "/xmrig";
#endif
return !std::filesystem::exists(xmrigPath);
const auto* res = getEmbeddedResource(RESOURCE_XMRIG);
return resourceNeedsUpdate(res, xmrigPath);
#else
return false;
#endif

View File

@@ -55,6 +55,11 @@ const EmbeddedTheme* getEmbeddedThemes();
// Returns number of themes extracted
int extractBundledThemes(const std::string& destDir);
// Update stale bundled theme files in the given directory.
// Compares on-disk file size to embedded size; overwrites on mismatch.
// Returns number of themes updated.
int updateBundledThemes(const std::string& dir);
// Check if daemon needs to be extracted
bool needsDaemonExtraction();