diff --git a/.drone.yml b/.drone.yml index b4aed15..9fee86d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,11 +14,9 @@ steps: commands: - git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/ - git config --global url."http://gitea:3000/".insteadOf https://github.com/ - - git submodule update --init --depth 50 contrib/tor - - git submodule update --init --depth 50 contrib/torsocks - git submodule update --init --depth 120 monero - git submodule update --init --depth 120 --recursive monero - - make -j8 release-static + - TOR="/usr/local/tor/bin/tor" XMRIG="/xmrig/xmrig" make -j6 release-static environment: OPENSSL_ROOT_DIR: /usr/local/openssl/ CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off @@ -44,7 +42,7 @@ volumes: path: /var/drone/ccache_linux_release/ - name: files_linux_release host: - path: /mnt/storage1/feather_files/files/linux-release/ + path: /build/feather_files/files/linux-release/ --- @@ -75,7 +73,7 @@ steps: volumes: - name: files_linux_appimage host: - path: /mnt/storage1/feather_files/files/linux-release-appimage/ + path: /build/feather_files/files/linux-release-appimage/ --- @@ -94,11 +92,9 @@ steps: commands: - git config --global url."http://gitea:3000/tor/".insteadOf https://git.torproject.org/ - git config --global url."http://gitea:3000/".insteadOf https://github.com/ - - git submodule update --init --depth 50 contrib/tor - - git submodule update --init --depth 50 contrib/torsocks - git submodule update --init --depth 120 monero - git submodule update --init --depth 120 --recursive monero - - PATH=/mxe/usr/bin/:$PATH make -j8 windows-mxe-release + - PATH="/mxe/usr/bin/:$PATH" TOR="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" XMRIG="/xmrig/xmrig.exe" make -j6 windows-mxe-release environment: CMAKEFLAGS_EXTRA: -DFETCH_DEPS=Off - name: deploy @@ -122,7 +118,7 @@ volumes: path: /var/drone/ccache_win_release/ - name: files_win_release host: - path: /mnt/storage1/feather_files/files/windows-mxe-release/ + path: /build/feather_files/files/windows-mxe-release/ --- @@ -157,9 +153,9 @@ steps: volumes: - name: files_mac_release host: - path: /mnt/storage1/feather_files/files/mac-release/ + path: /build/feather_files/files/mac-release/ --- kind: signature -hmac: 91e773a27d27f29ea62f5df500664b733df641b7c31202c8e5558174fd046fba +hmac: 527d334190a8a824b3b781a05ae4c7d87f4fa2bc37ebc53a96db91f925fa4a52 ... diff --git a/BUILDING.md b/BUILDING.md index 35efd02..912190c 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -35,7 +35,7 @@ Note: You only need to build the base image once. #### 3. Build ```bash -docker run --rm -it -v /tmp/ccache:/root/.ccache -v /root/feather:/feather -w /feather feather:win /bin/bash -c 'PATH=/mxe/usr/bin/:$PATH make windows-mxe-release -j8' +docker run --rm -it -v /tmp/ccache:/root/.ccache -v /root/feather:/feather -w /feather feather:win /bin/bash -c 'PATH="/mxe/usr/bin/:$PATH" TOR="/mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe" XMRIG="/xmrig/xmrig.exe" make windows-mxe-release -j8' ``` Replace `PATH_TO_FEATHER` with the absolute path to Feather locally. @@ -68,7 +68,7 @@ Note: You only need to build the base image once. #### 3. Build ```bash -docker run --env OPENSSL_ROOT_DIR=/usr/local/openssl/ --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:linux sh -c 'make release-static -j8' +docker run --env OPENSSL_ROOT_DIR=/usr/local/openssl/ --rm -it -v /tmp/ccache:/root/.ccache -v PATH_TO_FEATHER:/feather -w /feather feather:linux sh -c 'TOR="/usr/local/tor/bin/tor" XMRIG="/xmrig/xmrig" make release-static -j8' ``` Replace `PATH_TO_FEATHER` with the absolute path to Feather locally. @@ -98,4 +98,4 @@ Build Feather. CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release ``` -The resulting Mac OS application can be found `build/bin/feather.app`. +The resulting Mac OS application can be found `build/bin/feather.app` and will **not** have Tor embedded. \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3afe305..c9851a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,9 @@ set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}") option(FETCH_DEPS "Download dependencies if they are not found" ON) option(XMRTO "Include Xmr.To module" ON) -option(XMRig "Include XMRig module" ON) -option(BUILD_TOR "Build Tor" OFF) +option(XMRIG "Path to XMRig binary to embed inside Feather" OFF) +option(TOR "Path to Tor binary to embed inside Feather" OFF) +option(TOR_VERSION "Optional git hash or tag of embedded Tor version" "tor-0.4.3.5") option(STATIC "Link libraries statically, requires static Qt") option(USE_DEVICE_TREZOR "Trezor support compilation" OFF) option(DONATE_BEG "Prompt donation window every once in a while" ON) @@ -175,47 +176,48 @@ if(UNIX AND NOT APPLE) endif() endif() -# Tor/torsocks -set(TOR_TAG "tor-0.4.3.5") -set(TOR_DIR "${CMAKE_SOURCE_DIR}/contrib/tor") - -if(BUILD_TOR AND APPLE) - execute_process(COMMAND bash -c "touch ${CMAKE_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib") -ENDIF() - -if(UNIX AND NOT APPLE) - set(TOR_LIB "libtorsocks.so") -elseif(APPLE) - set(TOR_LIB "libtorsocks.dylib") +if("$ENV{DRONE}" STREQUAL "true") + message(STATUS "We are inside a static compile with Drone CI") endif() -if("$ENV{DRONE}" STREQUAL "true" AND APPLE) - message(STATUS "We are inside a static compile with Drone CI") - # @TODO: taken from Tor Browser official release for now - execute_process(COMMAND bash -c "cp ~/tor/libevent-2.1.7.dylib ${CMAKE_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib") - execute_process(COMMAND bash -c "cp ~/tor/tor ${CMAKE_SOURCE_DIR}/src/tor/tor") -elseif("$ENV{DRONE}" STREQUAL "true" AND BUILD_TOR) - message(STATUS "We are inside a static compile with Drone CI") - if(MINGW) - execute_process(COMMAND bash -c "cp /mxe/usr/x86_64-w64-mingw32.static/bin/tor.exe ${CMAKE_SOURCE_DIR}/src/tor/tor.exe") - elseif(UNIX AND NOT APPLE) - execute_process(COMMAND bash -c "cp /usr/local/tor/bin/tor ${CMAKE_SOURCE_DIR}/src/tor/tor") - execute_process(COMMAND bash -c "cp /usr/local/torsocks/lib/torsocks/* ${CMAKE_SOURCE_DIR}/src/tor/") +# To build Feather with embedded (and static) Tor, pass CMake -DTOR=/path/to/tor +if(TOR) + if(APPLE) + execute_process(COMMAND bash -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/src/tor/libevent-2.1.7.dylib") endif() + + # on the buildbot Tor is baked into the image + # - linux: See `Dockerfile` + # - windows: https://github.com/mxe/mxe/blob/1024dc7d2db5eb7d5d3c64a2c12b5f592572f1ce/plugins/apps/tor.mk + # - macos: taken from Tor Browser official release + set(TOR_COPY_CMD "cp ${TOR} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/tor") + message(STATUS "${TOR_COPY_CMD}") + execute_process(COMMAND bash -c "${TOR_COPY_CMD}" RESULT_VARIABLE ret) + if(ret EQUAL "1") + message(FATAL_ERROR "Tor copy failure: ${TOR_COPY_CMD}") + endif() + + message(STATUS "Embedding Tor binary at ${TOR}") else() - if(BUILD_TOR) - if(UNIX OR APPLE) - execute_process(COMMAND bash -c "ls -al src/tor/${TOR_LIB} 2>/dev/null" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE TOR_FOUND OUTPUT_STRIP_TRAILING_WHITESPACE) - if(TOR_FOUND) - message(STATUS "${TOR_LIB} found, skipping Tor build") - else() - message(STATUS "${TOR_LIB} not found, building Tor") - execute_process(COMMAND bash -c "bash build_tor.sh ${TOR_TAG} ${CMAKE_SOURCE_DIR} 'ON'" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/contrib) - endif() - endif() - else() - message(STATUS "Skipping Tor build because -DBUILD_TOR=OFF") + message(STATUS "Skipping Tor inclusion because -DTOR=Off") +endif() + +# To build Feather with embedded (and static) XMRig, pass CMake -DXMRIG=/path/to/xmrig +if(XMRIG) + # on the buildbot XMRig is baked into the image + # - linux: See `Dockerfile` + # - windows: See `Dockerfile_windows` + # - macos: manually downloaded an official release + set(XMRIG_COPY_CMD "cp ${XMRIG} ${CMAKE_CURRENT_SOURCE_DIR}/src/assets/exec/xmrig") + message(STATUS "${XMRIG_COPY_CMD}") + execute_process(COMMAND bash -c "${XMRIG_COPY_CMD}" RESULT_VARIABLE ret) + if(ret EQUAL "1") + message(FATAL_ERROR "XMRig copy failure: ${XMRIG_COPY_CMD}") endif() + + message(STATUS "Embedding XMRig binary at ${XMRIG}") +else() + message(STATUS "Skipping XMRig inclusion because -DXMRIG=Off") endif() if(MINGW) diff --git a/Dockerfile b/Dockerfile index 74e39a9..c499c6f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -305,3 +305,9 @@ RUN git clone https://git.wownero.com/feather/monero-seed.git && \ cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ make -Cbuild -j$THREADS && \ make -Cbuild install + +RUN apt install -y curl && \ + curl -LO "https://github.com/xmrig/xmrig/releases/download/v6.3.5/xmrig-6.3.5-linux-static-x64.tar.gz" && \ + echo "24d4f07cf5850f00ab513b228f95769a5a5ed68d35808d98f9959b58d97985a0 xmrig-6.3.5-linux-static-x64.tar.gz" > hashsum.txt && \ + sha256sum -c hashsum.txt && \ + tar xvf xmrig-6.3.5-linux-static-x64.tar.gz --one-top-level=/xmrig --strip 1 diff --git a/Dockerfile_windows b/Dockerfile_windows index 759d88c..3cbf4b9 100644 --- a/Dockerfile_windows +++ b/Dockerfile_windows @@ -72,3 +72,10 @@ RUN git clone https://git.wownero.com/feather/monero-seed.git && \ cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ make -Cbuild -j$THREADS && \ make -Cbuild install + +RUN apt install -y curl && \ + curl -LO "https://github.com/xmrig/xmrig/releases/download/v6.3.5/xmrig-6.3.5-gcc-win64.zip" && \ + echo "e45915ada7e6e30f6ab40abf33831056449d5914307d7706bb0ad439b6d64c12 xmrig-6.3.5-gcc-win64.zip" > hashsum.txt && \ + sha256sum -c hashsum.txt && \ + unzip -q xmrig-6.3.5-gcc-win64.zip -d /xmrig && \ + mv /xmrig/xmrig-6.3.5/* /xmrig/ diff --git a/HACKING.md b/HACKING.md index f644a4c..8285c63 100644 --- a/HACKING.md +++ b/HACKING.md @@ -42,7 +42,8 @@ via the `CMAKE_PREFIX_PATH` definition. For me this is: There are some Monero/Feather related options/definitions that you may pass: - `-DXMRTO=OFF` - disable Xmr.To feature -- `-DBUILD_TOR=OFF` - disable embedded Tor +- `-DTOR=/path/to/tor` - Embed a Tor executable inside Feather +- `-DXMRIG=/path/to/xmrig` - Embed a XMRig executable inside Feather - `-DDONATE_BEG=OFF` - disable the dreaded donate requests And: diff --git a/Makefile b/Makefile index 88d2800..53684c4 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ CMAKEFLAGS = \ -DBUILD_64=On \ -DBUILD_TESTS=Off \ -DXMRTO=ON \ + -DXMRIG=Off \ + -DTOR=Off \ -DCMAKE_CXX_STANDARD=11 \ -DCMAKE_VERBOSE_MAKEFILE=On \ -DINSTALL_VENDORED_LIBUNBOUND=Off \ @@ -40,29 +42,33 @@ CMAKEFLAGS = \ $(CMAKEFLAGS_EXTRA) release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64" -release-static: CMAKEFLAGS += -DBUILD_TOR=On +release-static: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) +release-static: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF) release-static: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release release-static: cmake -Bbuild $(CMAKEFLAGS) $(MAKE) -Cbuild windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64" -windows-mxe-release: CMAKEFLAGS += -DBUILD_TOR=On +windows-mxe-release: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) +windows-mxe-release: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF) windows-mxe-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release windows-mxe-release: cmake -Bbuild $(CMAKEFLAGS) $(MAKE) -Cbuild windows-mxe-debug: CMAKEFLAGS += -DBUILD_TAG="win-x64" -windows-mxe-debug: CMAKEFLAGS += -DBUILD_TOR=Off +windows-mxe-debug: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) +windows-mxe-debug: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF) windows-mxe-debug: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Debug windows-mxe-debug: cmake -Bbuild $(CMAKEFLAGS) $(MAKE) -Cbuild mac-release: CMAKEFLAGS += -DSTATIC=Off +mac-release: CMAKEFLAGS += -DTOR=$(or ${TOR},OFF) +mac-release: CMAKEFLAGS += -DXMRIG=$(or ${XMRIG},OFF) mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64" -mac-release: CMAKEFLAGS += -DBUILD_TOR=Off mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release mac-release: cmake -Bbuild $(CMAKEFLAGS) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14688dc..da2f614 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,14 +42,16 @@ file(GLOB SOURCE_FILES "dialog/*.cpp" ) -if((APPLE AND BUILD_TOR) OR (APPLE AND "$ENV{DRONE}" STREQUAL "true")) - set(ASSETS_OS "assets_macos_tor.qrc") -elseif(UNIX AND NOT APPLE AND BUILD_TOR) - set(ASSETS_OS "assets_linux_tor.qrc") -elseif(MINGW AND BUILD_TOR) - set(ASSETS_OS "assets_windows_tor.qrc") -else() - message(STATUS "Building without embedded Tor") +if(TOR) + if(APPLE) + set(ASSETS_TOR "assets_tor_macos.qrc") + else() + set(ASSETS_TOR "assets_tor.qrc") + endif() +endif() + +if(XMRIG) + set(ASSETS_XMRIG "assets_mining.qrc") endif() set(EXECUTABLE_FLAG) @@ -74,7 +76,8 @@ endif() add_executable(feather ${EXECUTABLE_FLAG} main.cpp ${SOURCE_FILES} ${RESOURCES} - ${ASSETS_OS} + ${ASSETS_TOR} + ${ASSETS_XMRIG} ) # mac os bundle @@ -122,16 +125,16 @@ if(DONATE_BEG) target_compile_definitions(feather PRIVATE DONATE_BEG=1) endif() -if(BUILD_TOR) - target_compile_definitions(feather PRIVATE BUILD_TOR=1) -endif() - if(XMRTO) target_compile_definitions(feather PRIVATE XMRTO=1) endif() -if(XMRig) - target_compile_definitions(feather PRIVATE MINING=1) +if(TOR) + target_compile_definitions(feather PRIVATE HAS_TOR=1) +endif() + +if(XMRIG) + target_compile_definitions(feather PRIVATE HAS_XMRIG=1) endif() if(HAVE_SYS_PRCTL_H) diff --git a/src/appcontext.cpp b/src/appcontext.cpp index e1a8202..e2826a3 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -147,10 +147,17 @@ AppContext::AppContext(QCommandLineParser *cmdargs) { AppContext::prices = new Prices(); // xmr.to -#if defined(XMRTO) +#ifdef XMRTO this->XMRTo = new XmrTo(this); #endif + // XMRig +#ifdef HAS_XMRIG + this->XMRig = new XmRig(this->configDirectory, this); + if(!this->isTails) + this->XMRig->prepare(); +#endif + this->walletManager = WalletManager::instance(); QString logPath = QString("%1/daemon.log").arg(configDirectory); Monero::Utils::onStartup(); @@ -393,7 +400,7 @@ void AppContext::onWSMessage(const QJsonObject &msg) { else if(cmd == "nodes") { this->onWSNodes(msg.value("data").toArray()); } -#if defined(MINING) +#if defined(HAS_XMRIG) else if(cmd == "xmrig") { this->XMRigDownloads(msg.value("data").toObject()); } @@ -511,31 +518,17 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) { } void AppContext::createConfigDirectory(const QString &dir) { - if(!Utils::dirExists(dir)) { - qDebug() << QString("Creating directory: %1").arg(dir); - if(!QDir().mkpath(dir)) - throw std::runtime_error("Could not create directory " + dir.toStdString()); - } - QString config_dir_tor = QString("%1%2").arg(dir).arg("tor"); - if(!Utils::dirExists(config_dir_tor)) { - qDebug() << QString("Creating directory: %1").arg(config_dir_tor); - if (!QDir().mkpath(config_dir_tor)) - throw std::runtime_error("Could not create directory " + config_dir_tor.toStdString()); - } - QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data"); - if(!Utils::dirExists(config_dir_tordata)) { - qDebug() << QString("Creating directory: %1").arg(config_dir_tordata); - if (!QDir().mkpath(config_dir_tordata)) - throw std::runtime_error("Could not create directory " + config_dir_tordata.toStdString()); - } + QString config_dir_xmrig = QString("%1%2").arg(dir).arg("xmrig"); - QString config_dir_torsocks = QString("%1%2").arg(dir).arg("torsocks"); - if(!Utils::dirExists(config_dir_torsocks)) { - qDebug() << QString("Creating directory: %1").arg(config_dir_torsocks); - if (!QDir().mkpath(config_dir_torsocks)) - throw std::runtime_error("Could not create directory " + config_dir_torsocks.toStdString()); + QStringList createDirs({dir, config_dir_tor, config_dir_tordata, config_dir_xmrig}); + for(const auto &d: createDirs) { + if(!Utils::dirExists(d)) { + qDebug() << QString("Creating directory: %1").arg(d); + if (!QDir().mkpath(d)) + throw std::runtime_error("Could not create directory " + d.toStdString()); + } } } diff --git a/src/appcontext.h b/src/appcontext.h index 8f9bdda..dd9057c 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -14,6 +14,7 @@ #include "utils/networking.h" #include "utils/tor.h" #include "utils/xmrto.h" +#include "utils/xmrig.h" #include "utils/wsclient.h" #include "utils/txfiathistory.h" #include "widgets/RedditPost.h" @@ -78,6 +79,7 @@ public: Tor *tor; WSClient *ws; XmrTo *XMRTo; + XmRig *XMRig; Nodes *nodes; static Prices *prices; static WalletKeysFilesModel *wallets; diff --git a/src/tor/.gitkeep b/src/assets/exec/.gitkeep similarity index 100% rename from src/tor/.gitkeep rename to src/assets/exec/.gitkeep diff --git a/src/assets_macos_tor.qrc b/src/assets_macos_tor.qrc deleted file mode 100644 index 5acecc2..0000000 --- a/src/assets_macos_tor.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - tor/tor - tor/libevent-2.1.7.dylib - - diff --git a/src/assets_windows_tor.qrc b/src/assets_mining.qrc similarity index 68% rename from src/assets_windows_tor.qrc rename to src/assets_mining.qrc index 70e0369..bbe426e 100644 --- a/src/assets_windows_tor.qrc +++ b/src/assets_mining.qrc @@ -1,5 +1,5 @@ - tor/tor.exe + assets/exec/xmrig diff --git a/src/assets_linux_tor.qrc b/src/assets_tor.qrc similarity index 69% rename from src/assets_linux_tor.qrc rename to src/assets_tor.qrc index 4539da6..7f0c2cf 100644 --- a/src/assets_linux_tor.qrc +++ b/src/assets_tor.qrc @@ -1,5 +1,5 @@ - tor/tor + assets/exec/tor diff --git a/src/assets_tor_macos.qrc b/src/assets_tor_macos.qrc new file mode 100644 index 0000000..909796c --- /dev/null +++ b/src/assets_tor_macos.qrc @@ -0,0 +1,6 @@ + + + assets/exec/tor + assets/exec/libevent-2.1.7.dylib + + diff --git a/src/main.cpp b/src/main.cpp index a7cbf6f..5482d44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,12 +22,14 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(assets); -#if defined(Q_OS_MAC) && defined(BUILD_TOR) - Q_INIT_RESOURCE(assets_macos_tor); -#elif defined(Q_OS_LINUX) && defined(BUILD_TOR) - Q_INIT_RESOURCE(assets_linux_tor); -#elif defined(Q_OS_WIN) && defined(BUILD_TOR) - Q_INIT_RESOURCE(assets_windows_tor); +#if defined(Q_OS_MAC) && defined(HAS_TOR) + Q_INIT_RESOURCE(assets_tor_macos); +#elif defined(HAS_TOR) + Q_INIT_RESOURCE(assets_tor); +#endif + +#if defined(HAS_XMRIG) + Q_INIT_RESOURCE(assets_mining); #endif QStringList argv_; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 34ca687..e4d247a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -167,13 +167,20 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage); // XMRig +#ifdef HAS_XMRIG m_xmrig = new XMRigWidget(m_ctx, this); ui->xmrRigLayout->addWidget(m_xmrig); + connect(m_ctx->XMRig, &XmRig::output, m_xmrig, &XMRigWidget::onProcessOutput); + connect(m_ctx->XMRig, &XmRig::error, m_xmrig, &XMRigWidget::onProcessError); + connect(m_ctx->XMRig, &XmRig::hashrate, m_xmrig, &XMRigWidget::onHashrate); + + connect(m_ctx, &AppContext::walletClosed, m_xmrig, &XMRigWidget::onWalletClosed); connect(m_ctx, &AppContext::walletOpened, m_xmrig, &XMRigWidget::onWalletOpened); connect(m_ctx, &AppContext::XMRigDownloads, m_xmrig, &XMRigWidget::onDownloads); - connect(m_ctx, &AppContext::walletClosed, m_xmrig, &XMRigWidget::onWalletClosed); + connect(m_xmrig, &XMRigWidget::miningStarted, [=]{ m_ctx->setWindowTitle(true); }); connect(m_xmrig, &XMRigWidget::miningEnded, [=]{ m_ctx->setWindowTitle(false); }); +#endif // CCS/Reddit widget m_ccsWidget = new CCSWidget(this); @@ -388,7 +395,7 @@ void MainWindow::initMenu() { ui->actionShow_xmr_to->setVisible(false); #endif -#if defined(MINING) +#if defined(HAS_XMRIG) connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); m_tabShowHideMapper["XMRig"] = new ToggleTab(ui->tabXmrRig, "XMRig", "XMRig", ui->actionShow_XMRig, Config::showTabXMRig); m_tabShowHideSignalMapper->setMapping(ui->actionShow_XMRig, "XMRig"); diff --git a/src/utils/tor.cpp b/src/utils/tor.cpp index 3e763ed..5eb0411 100644 --- a/src/utils/tor.cpp +++ b/src/utils/tor.cpp @@ -43,9 +43,15 @@ Tor::Tor(AppContext *ctx, QObject *parent) return; } +#ifndef HAS_TOR + qCritical() << "Feather built without embedded Tor. Assuming --use-local-tor"; + this->localTor = true; + return; +#endif + bool unpacked = this->unpackBins(); if (!unpacked) { - qCritical() << "Feather built without embedded Tor. Assuming --use-local-tor"; + qCritical() << "Error unpacking embedded Tor. Assuming --use-local-tor"; this->localTor = true; return; } @@ -175,11 +181,9 @@ void Tor::handleProcessError(QProcess::ProcessError error) { bool Tor::unpackBins() { QString torFile; - // @TODO: refactor for Mac OS - should compile Tor statically. -#if defined(Q_OS_MAC) && defined(DRONE) - // Tor on Mac requires libevent.dylib, borrowed the executable from - // the official Tor Browser release for now. - QString libEvent = ":/tor/libevent-2.1.7.dylib"; + // On MacOS write libevent to disk +#if defined(Q_OS_MAC) + QString libEvent = ":/assets/exec/libevent-2.1.7.dylib"; if (Utils::fileExists(libEvent)) { QFile e(libEvent); QFileInfo eventInfo(e); @@ -190,18 +194,15 @@ bool Tor::unpackBins() { } #endif -#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) - torFile = ":/tor/tor"; -#elif defined(Q_OS_WIN) - torFile = ":/tor/tor.exe"; -#endif - + torFile = ":/assets/exec/tor"; if (!Utils::fileExists(torFile)) return false; + + // write to disk QFile f(torFile); QFileInfo fileInfo(f); this->torPath = QDir(this->torDir).filePath(fileInfo.fileName()); - qDebug() << this->torPath; + qDebug() << "Writing Tor executable to " << this->torPath; f.copy(torPath); f.close(); @@ -209,7 +210,6 @@ bool Tor::unpackBins() { QFile torBin(this->torPath); torBin.setPermissions(QFile::ExeGroup | QFile::ExeOther | QFile::ExeOther | QFile::ExeUser); #endif - return true; } diff --git a/src/utils/xmrig.cpp b/src/utils/xmrig.cpp index df2c0f9..dc03ea5 100644 --- a/src/utils/xmrig.cpp +++ b/src/utils/xmrig.cpp @@ -13,28 +13,37 @@ #include "appcontext.h" -XMRig::XMRig(QObject *parent) : QObject(parent) -{ - qDebug() << "Using embedded tor instance"; - m_process.setProcessChannelMode(QProcess::MergedChannels); - - connect(&m_process, &QProcess::readyReadStandardOutput, this, &XMRig::handleProcessOutput); - connect(&m_process, &QProcess::errorOccurred, this, &XMRig::handleProcessError); - connect(&m_process, &QProcess::stateChanged, this, &XMRig::stateChanged); +XmRig::XmRig(const QString &configDir, QObject *parent) : QObject(parent) { + this->rigDir = QDir(configDir).filePath("xmrig"); } -void XMRig::stop() { +void XmRig::prepare() { + // unpack and set process signals + + if(!this->unpackBins()) { + qCritical() << "failed to write XMRig to config directory"; + return; + } + + m_process.setProcessChannelMode(QProcess::MergedChannels); + connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput); + connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError); + connect(&m_process, &QProcess::stateChanged, this, &XmRig::stateChanged); +} + +void XmRig::stop() { if(m_process.state() == QProcess::Running) m_process.kill(); } -void XMRig::terminate() { +void XmRig::terminate() { if(m_process.state() == QProcess::Running) m_process.terminate(); } -void XMRig::start(unsigned int threads, - const QString &pool_name, +void XmRig::start(const QString &path, + unsigned int threads, + const QString &address, const QString &username, const QString &password, bool tor, bool tls) { @@ -44,22 +53,22 @@ void XMRig::start(unsigned int threads, return; } - auto path = config()->get(Config::xmrigPath).toString(); if(path.isEmpty()) { - emit error("Please set path to XMRig binary before starting."); + emit error("XmRig->Start path parameter missing."); return; } if(!Utils::fileExists(path)) { - emit error("Path to XMRig binary invalid; file does not exist."); + emit error(QString("Path to XMRig binary invalid; file does not exist: %1").arg(path)); return; } QStringList arguments; - arguments << "-o" << pool_name; + arguments << "-o" << address; arguments << "-a" << "rx/0"; arguments << "-u" << username; - arguments << "-p" << password; + if(!password.isEmpty()) + arguments << "-p" << password; arguments << "--no-color"; arguments << "-t" << QString::number(threads); if(tor) @@ -72,14 +81,14 @@ void XMRig::start(unsigned int threads, m_process.start(path, arguments); } -void XMRig::stateChanged(QProcess::ProcessState state) { +void XmRig::stateChanged(QProcess::ProcessState state) { if(state == QProcess::ProcessState::Running) emit output("XMRig started"); else if (state == QProcess::ProcessState::NotRunning) emit output("XMRig stopped"); } -void XMRig::handleProcessOutput() { +void XmRig::handleProcessOutput() { QByteArray _output = m_process.readAllStandardOutput(); if(_output.contains("miner") && _output.contains("speed")) { // detect hashrate @@ -93,7 +102,7 @@ void XMRig::handleProcessOutput() { emit output(_output); } -void XMRig::handleProcessError(QProcess::ProcessError err) { +void XmRig::handleProcessError(QProcess::ProcessError err) { if (err == QProcess::ProcessError::Crashed) emit error("XMRig crashed or killed"); else if (err == QProcess::ProcessError::FailedToStart) { @@ -102,3 +111,24 @@ void XMRig::handleProcessError(QProcess::ProcessError err) { } } +bool XmRig::unpackBins() { + QString rigFile; + + rigFile = ":/assets/exec/xmrig"; + if (!Utils::fileExists(rigFile)) + return false; + + // write to disk + QFile f(rigFile); + QFileInfo fileInfo(f); + this->rigPath = QDir(this->rigDir).filePath(fileInfo.fileName()); + qDebug() << "Writing XMRig executable to " << this->rigPath; + f.copy(rigPath); + f.close(); + +#if defined(Q_OS_UNIX) + QFile torBin(this->rigPath); + torBin.setPermissions(QFile::ExeGroup | QFile::ExeOther | QFile::ExeOther | QFile::ExeUser); +#endif + return true; +} diff --git a/src/utils/xmrig.h b/src/utils/xmrig.h index 42817f5..46e5b20 100644 --- a/src/utils/xmrig.h +++ b/src/utils/xmrig.h @@ -15,16 +15,21 @@ #include "utils/childproc.h" -class XMRig : public QObject +class XmRig : public QObject { Q_OBJECT public: - explicit XMRig(QObject *parent = nullptr); + explicit XmRig(const QString &configDir, QObject *parent = nullptr); + void prepare(); - void start(unsigned int threads, const QString &pool_name, const QString &username, const QString &password, bool tor = false, bool tls = true); + void start(const QString &path, unsigned int threads, const QString &address, const QString &username, const QString &password, bool tor = false, bool tls = true); void stop(); void terminate(); + bool unpackBins(); + + QString rigDir; + QString rigPath; signals: void error(const QString &msg); diff --git a/src/widgets/xmrigwidget.cpp b/src/widgets/xmrigwidget.cpp index f87fb03..4d541cf 100644 --- a/src/widgets/xmrigwidget.cpp +++ b/src/widgets/xmrigwidget.cpp @@ -33,12 +33,6 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) : connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &XMRigWidget::showContextMenu); connect(ui->tableView, &QTableView::doubleClicked, this, &XMRigWidget::linkClicked); - // XMRig core - m_rig = new XMRig(this); - connect(m_rig, &XMRig::output, this, &XMRigWidget::onProcessOutput); - connect(m_rig, &XMRig::error, this, &XMRigWidget::onProcessError); - connect(m_rig, &XMRig::hashrate, this, &XMRigWidget::onHashrate); - // threads ui->threadSlider->setMinimum(1); int threads = QThread::idealThreadCount(); @@ -60,19 +54,29 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) : ui->relayTor->setChecked(false); ui->check_tls->setChecked(true); ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse); + ui->label_status->hide(); + ui->pathFrame->hide(); + ui->soloFrame->hide(); + ui->poolFrame->hide(); // XMRig binary auto path = config()->get(Config::xmrigPath).toString(); - ui->lineEdit_path->setText(path); - ui->label_status->hide(); - if(path.isEmpty()) - ui->tabWidget->setCurrentIndex(1); + if(!path.isEmpty()) { + ui->pathFrame->show(); + ui->check_custompath->setChecked(true); + ui->lineEdit_path->setText(path); + } // pools + ui->poolFrame->show(); ui->combo_pools->insertItems(0, m_pools); auto preferredPool = config()->get(Config::xmrigPool).toString(); if (m_pools.contains(preferredPool)) ui->combo_pools->setCurrentIndex(m_pools.indexOf(preferredPool)); + else { + preferredPool = m_pools.at(0); + config()->set(Config::xmrigPool, preferredPool); + } connect(ui->combo_pools, QOverload::of(&QComboBox::currentIndexChanged), this, &XMRigWidget::onPoolChanged); // info @@ -81,18 +85,26 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) : ui->console->appendPlainText("Invalid path to XMRig binary detected. Please reconfigure on the Settings tab."); else ui->console->appendPlainText(QString("XMRig path set to %1").arg(path)); - ui->console->appendPlainText("Ready to mine."); + if(m_ctx->isTails) { + ui->console->appendPlainText("Mining not available on Tails."); + ui->btn_start->setEnabled(false); + } + else + ui->console->appendPlainText("Ready to mine."); // username/password connect(ui->lineEdit_password, &QLineEdit::editingFinished, [=]() { m_ctx->currentWallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text()); m_ctx->currentWallet->store(); }); - connect(ui->lineEdit_address, &QLineEdit::editingFinished, [=]() { m_ctx->currentWallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text()); m_ctx->currentWallet->store(); }); + + // checkbox connects + connect(ui->check_custompath, &QCheckBox::stateChanged, this, &XMRigWidget::onCustomPathChecked); + connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked); } void XMRigWidget::onWalletClosed() { @@ -140,30 +152,40 @@ void XMRigWidget::onClearClicked() { } void XMRigWidget::onStartClicked() { - auto pool_name = config()->get(Config::xmrigPool).toString(); + QString xmrigPath; + bool solo = ui->check_solo->isChecked(); + bool customBinary = ui->check_custompath->isChecked(); - // fix error in config - if(!m_pools.contains(pool_name)) { - pool_name = m_pools.at(0); - config()->set(Config::xmrigPool, pool_name); - } + if(customBinary) + xmrigPath = config()->get(Config::xmrigPath).toString(); + else + xmrigPath = m_ctx->XMRig->rigPath; + // username is receiving address usually auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username"); auto password = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_password"); if(username.isEmpty()) { - Utils::showMessageBox("Error", "Please specify a receiving address on the Settings screen", true); + QString err = "Please specify a receiving address on the Settings screen"; + ui->console->appendPlainText(err); + Utils::showMessageBox("Error", err, true); return; } - m_rig->start(m_threads, pool_name, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked()); + QString address; + if(solo) + address = ui->lineEdit_solo->text().trimmed(); + else + address = config()->get(Config::xmrigPool).toString(); + + m_ctx->XMRig->start(xmrigPath, m_threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked()); ui->btn_start->setEnabled(false); ui->btn_stop->setEnabled(true); emit miningStarted(); } void XMRigWidget::onStopClicked() { - m_rig->terminate(); + m_ctx->XMRig->terminate(); ui->btn_start->setEnabled(true); ui->btn_stop->setEnabled(false); ui->label_status->hide(); @@ -257,6 +279,28 @@ void XMRigWidget::showContextMenu(const QPoint &pos) { m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos)); } +void XMRigWidget::onCustomPathChecked(int state) { + if(state == 2) { + ui->pathFrame->show(); + } else { + ui->lineEdit_path->setText(""); + config()->set(Config::xmrigPath, ""); + ui->pathFrame->hide(); + } +} + +void XMRigWidget::onSoloChecked(int state) { + if(state == 2) { + ui->poolFrame->hide(); + ui->soloFrame->show(); + ui->check_tls->setChecked(false); + } + else { + ui->poolFrame->show(); + ui->soloFrame->hide(); + } +} + void XMRigWidget::linkClicked() { QModelIndex index = ui->tableView->currentIndex(); auto download_link = m_urls.at(index.row()); diff --git a/src/widgets/xmrigwidget.h b/src/widgets/xmrigwidget.h index 4517264..87cdeca 100644 --- a/src/widgets/xmrigwidget.h +++ b/src/widgets/xmrigwidget.h @@ -33,14 +33,16 @@ public slots: void onClearClicked(); void onDownloads(const QJsonObject &data); void linkClicked(); + void onProcessError(const QString &msg); + void onProcessOutput(const QByteArray &msg); + void onHashrate(const QString &hashrate); + void onCustomPathChecked(int state); + void onSoloChecked(int state); private slots: void onBrowseClicked(); - void onProcessError(const QString &msg); - void onProcessOutput(const QByteArray &msg); void onThreadsValueChanged(int date); void onPoolChanged(int pos); - void onHashrate(const QString &hashrate); signals: void miningStarted(); @@ -56,7 +58,6 @@ private: unsigned int m_threads; QStringList m_urls; QStringList m_pools{"pool.xmr.pt:9000", "pool.supportxmr.com:9000", "mine.xmrpool.net:443", "xmrpool.eu:9999", "xmr-eu1.nanopool.org:14433", "pool.minexmr.com:6666", "us-west.minexmr.com:6666", "monerohash.com:9999"}; - XMRig *m_rig; }; #endif // REDDITWIDGET_H diff --git a/src/widgets/xmrigwidget.ui b/src/widgets/xmrigwidget.ui index ced7240..6151a4c 100644 --- a/src/widgets/xmrigwidget.ui +++ b/src/widgets/xmrigwidget.ui @@ -29,7 +29,7 @@ - 0 + 1 @@ -125,86 +125,13 @@ Settings - + - - - Path to XMRig executable - - - - - - - - - - - - Browse - - - - - - - - - - - - - Pool - - - - - - - - - - 0 - 0 - - - - - - - - TLS - - - - - - - Tor - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + @@ -227,22 +154,8 @@ - - - - - - Pool worker name (optional) - - - - - - - - - + Qt::Horizontal @@ -256,6 +169,204 @@ + + + + + + Solo mine + + + + + + + Custom XMRig executable + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + /path/to/xmrig + + + + + + + Browse + + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Pool + + + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Node address + + + + + + + + + 127.0.0.1:18081 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + @@ -266,6 +377,71 @@ + + + + + + Password (optional) + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 60 + 20 + + + + + + + + + + + + + + TLS + + + + + + + Tor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/utils/build_macos.sh b/utils/build_macos.sh index cdcbafd..f96db3e 100644 --- a/utils/build_macos.sh +++ b/utils/build_macos.sh @@ -10,12 +10,11 @@ rm ~/feather.zip 2>&1 >/dev/null cd ~/feather git fetch --all git reset --hard "$HASH" -git submodule update --init --depth 50 contrib/tor -git submodule update --init --depth 50 contrib/torsocks git submodule update --init --depth 120 monero git submodule update --init --depth 120 --recursive monero -CMAKE_PREFIX_PATH=~/Qt/5.15.1/clang_64 make -j3 mac-release +cp "/Users/administrator/tor/libevent-2.1.7.dylib" "/Users/administrator/feather/src/assets/exec/libevent-2.1.7.dylib" +CMAKE_PREFIX_PATH="~/Qt/5.15.1/clang_64" TOR="/Users/administrator/tor/tor" XMRIG="/Users/administrator/xmrig/xmrig" make -j3 mac-release if [[ $? -eq 0 ]]; then echo "[+] Feather built OK"