diff --git a/build.sh b/build.sh index 1c8ee99..2c31b3c 100755 --- a/build.sh +++ b/build.sh @@ -271,6 +271,9 @@ build_release_linux() { [[ -f bin/asmap.dat ]] && cp bin/asmap.dat "$dist_dir/" [[ -f bin/sapling-spend.params ]] && cp bin/sapling-spend.params "$dist_dir/" [[ -f bin/sapling-output.params ]] && cp bin/sapling-output.params "$dist_dir/" + # Bundle xmrig for mining support + local XMRIG_LINUX="$SCRIPT_DIR/prebuilt-binaries/xmrig-hac/xmrig" + [[ -f "$XMRIG_LINUX" ]] && { cp "$XMRIG_LINUX" "$dist_dir/"; chmod +x "$dist_dir/xmrig"; info "Bundled xmrig"; } || warn "xmrig not found — mining unavailable in zip" cp -r bin/res "$dist_dir/" 2>/dev/null || true # ── Zip ────────────────────────────────────────────────────────────────── @@ -294,9 +297,14 @@ build_release_linux() { [[ -f bin/dragonxd ]] && cp bin/dragonxd "$APPDIR/usr/bin/" [[ -f bin/dragonx-cli ]] && cp bin/dragonx-cli "$APPDIR/usr/bin/" - [[ -f bin/asmap.dat ]] && cp bin/asmap.dat "$APPDIR/usr/share/ObsidianDragon/" - [[ -f bin/sapling-spend.params ]] && cp bin/sapling-spend.params "$APPDIR/usr/share/ObsidianDragon/" - [[ -f bin/sapling-output.params ]] && cp bin/sapling-output.params "$APPDIR/usr/share/ObsidianDragon/" + # Daemon data files must be alongside the daemon binary (usr/bin/) + # because dragonxd searches relative to its own directory. + [[ -f bin/asmap.dat ]] && cp bin/asmap.dat "$APPDIR/usr/bin/" + [[ -f bin/sapling-spend.params ]] && cp bin/sapling-spend.params "$APPDIR/usr/bin/" + [[ -f bin/sapling-output.params ]] && cp bin/sapling-output.params "$APPDIR/usr/bin/" + # Bundle xmrig for mining support + local XMRIG_LINUX_AI="$SCRIPT_DIR/prebuilt-binaries/xmrig-hac/xmrig" + [[ -f "$XMRIG_LINUX_AI" ]] && { cp "$XMRIG_LINUX_AI" "$APPDIR/usr/bin/"; chmod +x "$APPDIR/usr/bin/xmrig"; } # Desktop entry cat > "$APPDIR/usr/share/applications/ObsidianDragon.desktop" <<'DESK' @@ -602,6 +610,13 @@ HDR [[ -f "$DD/$f" ]] && cp "$DD/$f" "$dist_dir/" done + # Bundle Sapling params + asmap for the zip distribution + # (The single-file exe has these embedded via INCBIN, but the zip + # needs them on disk so the daemon can find them in its work dir.) + for f in sapling-spend.params sapling-output.params asmap.dat; do + [[ -f "$DD/$f" ]] && cp "$DD/$f" "$dist_dir/" + done + cp -r bin/res "$dist_dir/" 2>/dev/null || true # ── Single-file exe (all resources embedded) ──────────────────────────── diff --git a/setup.sh b/setup.sh index 6c55dd4..580f686 100755 --- a/setup.sh +++ b/setup.sh @@ -627,8 +627,13 @@ XMRIG_SRC="$PROJECT_DIR/external/xmrig-hac" XMRIG_PREBUILT="$PROJECT_DIR/prebuilt-binaries/xmrig-hac" # Clean previous prebuilt xmrig binaries so we always rebuild +# Only clean the binary for the platform(s) we are actually building, +# otherwise a plain ./setup.sh deletes xmrig.exe without rebuilding it. if ! $CHECK_ONLY; then - rm -f "$XMRIG_PREBUILT/xmrig" "$XMRIG_PREBUILT/xmrig.exe" 2>/dev/null || true + rm -f "$XMRIG_PREBUILT/xmrig" 2>/dev/null || true + if $SETUP_WIN; then + rm -f "$XMRIG_PREBUILT/xmrig.exe" 2>/dev/null || true + fi fi # Helper: clone xmrig-hac if not present diff --git a/src/app.cpp b/src/app.cpp index d8003a6..cbd6e4f 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1855,10 +1855,34 @@ bool App::startEmbeddedDaemon() } DEBUG_LOGF("Sapling params extracted successfully\n"); } else { - daemon_status_ = "Sapling parameters not found. They should be in: " + rpc::Connection::getSaplingParamsDir(); - DEBUG_LOGF("Sapling params not found and no embedded resources available!\n"); - DEBUG_LOGF("Expected location: %s\n", rpc::Connection::getSaplingParamsDir().c_str()); - return false; + // Fallback: check for params bundled alongside the executable + // (zip distributions bundle sapling-*.params next to the binary) + namespace fs = std::filesystem; + std::string exe_dir = util::Platform::getExecutableDirectory(); + std::string daemon_dir = resources::getDaemonDirectory(); + const char* paramFiles[] = { "sapling-spend.params", "sapling-output.params", "asmap.dat" }; + bool copied = false; + if (!exe_dir.empty()) { + std::error_code ec; + fs::create_directories(daemon_dir, ec); + for (const char* name : paramFiles) { + fs::path src = fs::path(exe_dir) / name; + fs::path dst = fs::path(daemon_dir) / name; + if (fs::exists(src) && !fs::exists(dst)) { + DEBUG_LOGF("Copying bundled %s from exe dir to %s\n", name, daemon_dir.c_str()); + fs::copy_file(src, dst, ec); + if (!ec) copied = true; + } + } + } + if (copied && rpc::Connection::verifySaplingParams()) { + DEBUG_LOGF("Sapling params copied from exe directory successfully\n"); + } else { + daemon_status_ = "Sapling parameters not found. They should be in: " + rpc::Connection::getSaplingParamsDir(); + DEBUG_LOGF("Sapling params not found and no embedded resources available!\n"); + DEBUG_LOGF("Expected location: %s\n", rpc::Connection::getSaplingParamsDir().c_str()); + return false; + } } } diff --git a/src/daemon/xmrig_manager.cpp b/src/daemon/xmrig_manager.cpp index abb6179..444def2 100644 --- a/src/daemon/xmrig_manager.cpp +++ b/src/daemon/xmrig_manager.cpp @@ -466,6 +466,18 @@ bool XmrigManager::startProcess(const std::string& xmrigPath, const std::string& dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); + // Detach from controlling terminal's stdin to prevent SIGTTIN/SIGTTOU + // when running in a new process group (setpgid below). + int devnull = open("/dev/null", O_RDONLY); + if (devnull >= 0) { + dup2(devnull, STDIN_FILENO); + close(devnull); + } + + // Ignore job-control signals that a background process group may receive + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + // New process group so we can kill the whole group setpgid(0, 0); diff --git a/src/resources/embedded_resources.cpp b/src/resources/embedded_resources.cpp index b27b056..8487dfa 100644 --- a/src/resources/embedded_resources.cpp +++ b/src/resources/embedded_resources.cpp @@ -509,6 +509,18 @@ std::string getXmrigPath() return xmrigName; } + // Check alongside the wallet executable (zip / AppImage distributions) + { + std::string exeDir = util::Platform::getExecutableDirectory(); + if (!exeDir.empty()) { + std::string exeDirPath = exeDir + "/" + xmrigName; + if (std::filesystem::exists(exeDirPath)) { + DEBUG_LOGF("[INFO] getXmrigPath: found alongside wallet at %s\n", exeDirPath.c_str()); + return exeDirPath; + } + } + } + // Check development paths #ifdef _WIN32 // Not applicable for cross-compiled Windows builds diff --git a/src/ui/windows/mining_tab.cpp b/src/ui/windows/mining_tab.cpp index a4ce8f4..aa97689 100644 --- a/src/ui/windows/mining_tab.cpp +++ b/src/ui/windows/mining_tab.cpp @@ -153,10 +153,15 @@ void RenderMiningTab(App* app) s_pool_mode = app->settings()->getPoolMode(); strncpy(s_pool_url, app->settings()->getPoolUrl().c_str(), sizeof(s_pool_url) - 1); strncpy(s_pool_worker, app->settings()->getPoolWorker().c_str(), sizeof(s_pool_worker) - 1); - - // If pool worker is empty or placeholder, default to user's first address + s_pool_state_loaded = true; + } + + // Default pool worker to user's first shielded address once addresses are available + { + static bool s_pool_worker_defaulted = false; std::string workerStr(s_pool_worker); - if (workerStr.empty() || workerStr == "x") { + if (!s_pool_worker_defaulted && !state.addresses.empty() && + (workerStr.empty() || workerStr == "x")) { std::string defaultAddr; for (const auto& addr : state.addresses) { if (addr.type == "shielded" && !addr.address.empty()) { @@ -175,9 +180,10 @@ void RenderMiningTab(App* app) if (!defaultAddr.empty()) { strncpy(s_pool_worker, defaultAddr.c_str(), sizeof(s_pool_worker) - 1); s_pool_worker[sizeof(s_pool_worker) - 1] = '\0'; + s_pool_settings_dirty = true; } + s_pool_worker_defaulted = true; } - s_pool_state_loaded = true; } // Persist pool settings when dirty and no field is active