fix: Windows identity, async address creation, mining UI, and chart artifacts

Windows identity:
- Add VERSIONINFO resource (.rc) with ObsidianDragon file description
- Embed application manifest for DPI awareness and shell identity
- Patch libwinpthread/libpthread to remove competing VERSIONINFO
- Set AppUserModelID and HWND property store to override Task Manager cache
- Link patched pthread libs to eliminate "POSIX WinThreads" description

Address creation (+New button):
- Move z_getnewaddress/getnewaddress off UI thread to async worker
- Inject new address into state immediately for instant UI selection
- Trigger background refresh for balance updates

Mining tab:
- Add pool mining dropdown with saved URLs/workers and bookmarks
- Add solo mining log panel from daemon output with chart/log toggle
- Fix toggle button cursor (render after InputTextMultiline)
- Auto-restart miner on pool config change
- Migrate default pool URL to include stratum port

Transactions:
- Sort pending (0-conf) transactions to top of history
- Fall back to timereceived when timestamp is missing

Shutdown:
- Replace blocking sleep_for calls with 100ms polling loops
- Check shutting_down_ flag throughout daemon restart/bootstrap flows
- Reduce daemon stop timeout from 30s to 10s

Other:
- Fix market chart fill artifact (single concave polygon vs per-segment quads)
- Add bootstrap checksum verification state display
- Rename daemon client identifier to ObsidianDragon
This commit is contained in:
2026-03-05 22:43:27 -06:00
parent e2265b0bdf
commit b3a0ce29ed
20 changed files with 842 additions and 116 deletions

View File

@@ -382,6 +382,11 @@ void App::update()
state_.pool_mining.xmrig_running = false;
}
// Populate solo mining log lines from daemon output
if (embedded_daemon_ && embedded_daemon_->isRunning()) {
state_.mining.log_lines = embedded_daemon_->getRecentLines(50);
}
// Check daemon output for rescan progress
if (embedded_daemon_ && embedded_daemon_->isRunning()) {
std::string newOutput = embedded_daemon_->getOutputSince(daemon_output_offset_);
@@ -1935,12 +1940,13 @@ void App::stopEmbeddedDaemon()
if (stop_sent) {
DEBUG_LOGF("Waiting for daemon to begin shutdown...\n");
shutdown_status_ = "Waiting for daemon to begin shutdown...";
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
// Wait for process to exit; SIGTERM/TerminateProcess as last resort
// Wait for process to exit; SIGTERM/TerminateProcess as last resort.
// 10 seconds is generous — if the daemon hasn't exited by then it's stuck.
shutdown_status_ = "Waiting for dragonxd process to exit...";
embedded_daemon_->stop(30000);
embedded_daemon_->stop(10000);
}
bool App::isEmbeddedDaemonRunning() const
@@ -1972,10 +1978,13 @@ void App::rescanBlockchain()
std::thread([this]() {
DEBUG_LOGF("[App] Stopping daemon for rescan...\n");
stopEmbeddedDaemon();
if (shutting_down_) return;
// Wait for daemon to fully stop
DEBUG_LOGF("[App] Waiting for daemon to fully stop...\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
for (int i = 0; i < 30 && !shutting_down_; ++i)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (shutting_down_) return;
// Reset output offset so we parse fresh output for rescan progress
daemon_output_offset_ = 0;
@@ -2663,8 +2672,10 @@ void App::restartDaemon()
if (embedded_daemon_ && isEmbeddedDaemonRunning()) {
stopEmbeddedDaemon();
}
if (shutting_down_) { daemon_restarting_ = false; return; }
// Brief pause to let the port free up
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (int i = 0; i < 5 && !shutting_down_; ++i)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
startEmbeddedDaemon();
daemon_restarting_ = false;
DEBUG_LOGF("[App] Daemon restart complete — waiting for RPC...\n");