option(WITH_PLUGIN_BOUNTIES "Include Bounties Home plugin" ON)
option(WITH_PLUGIN_REVUO "Include Revuo Home plugin" ON)
option(WITH_PLUGIN_CALC "Include Calc tab plugin" ON)
-option(WITH_PLUGIN_XMRIG "Include XMRig plugin" ON)
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
include(CheckCCompilerFlag)
- Before a minor release:
- Update `src/assets/restore_heights_monero_{mainnet,stagenet}.txt`
- To obtain values, run `contrib/generate-restore-heights/heights.py`
- - Update `m_defaultPools` in `src/widgets/XMRigWidget.h`
- Update default node lists in `src/assets/nodes.json`
- Bump `openssl`, `qt`, `tor_*` packages in `contrib/depends/packages`
- Update or patch any statically linked dependencies that have known vulnerabilities
<string>Outputs</string>
</property>
</action>
- <action name="actionShow_XMRig">
- <property name="text">
- <string>Show Mining</string>
- </property>
- </action>
<action name="actionImportTransaction">
<property name="text">
<string>Transaction</string>
this->onInitialNetworkConfigured();
-// if (!wallet->cacheAttributeExists("feather.xmrig_password") && !wallet->cacheAttributeExists("feather.created")) {
-// auto result = QMessageBox::question(nullptr, "Foreign wallet",
-// "This wallet file was not created with Feather. This may cause unexpected behavior. Please restore your wallet from seed.\n\nOpen this wallet anyway?");
-// if (result == QMessageBox::No) {
-// wallet->deleteLater();
-// this->initWizard();
-// return;
-// }
-// }
-
// Create new mainwindow with wallet
m_splashDialog->hide();
<file>assets/images/update.png</file>
<file>assets/images/warning.png</file>
<file>assets/images/vrdp_32px.png</file>
- <file>assets/images/xmrig.svg</file>
<file>assets/images/zoom.png</file>
<file>assets/restore_heights_monero_mainnet.txt</file>
<file>assets/restore_heights_monero_stagenet.txt</file>
+++ /dev/null
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 496.06 496.06"><title>XMRig</title><defs><style>.a{fill:none;}.b{clip-path:url(#a);}.c{fill:#ec671a;}.d{fill:#575756;}.e{fill:#fff;}</style><clipPath id="a" transform="translate(-106.3 -106.3)"><circle class="a" cx="354.33" cy="354.33" r="248.03"/></clipPath></defs><title>Xr_icon</title><g class="b"><rect class="c" width="496.06" height="496.06"/><polygon class="d" points="496.06 496.06 0 496.06 0 387.21 124.02 387.55 189.12 291.44 254.23 387.55 496.06 387.55 496.06 496.06"/><path class="e" d="M481.44,441.14c0-13.18,0-27,0-37.32,0-54.11,22.15-77.57,55.82-52.71-0.39.07,27.9-43.41,27.9-43.41-35.68-24.09-67.09-10.17-86.81,19.45V295.42H428.74V441.14H391.12l-61-91.46,89.91-134.87H351.85L296,298.52l-55.81-83.71H172l89.91,134.87-61,91.46H106.3v52.37l59.65,0.16-0.12.18H234l62-93,62,93H602.36V441.14H481.44Z" transform="translate(-106.3 -106.3)"/></g></svg>
\ No newline at end of file
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#include "XMRigPlugin.h"
-
-#include "plugins/PluginRegistry.h"
-
-XMRigPlugin::XMRigPlugin()
-{
-}
-
-
-void XMRigPlugin::initialize(Wallet *wallet, QObject *parent) {
- this->setParent(parent);
- m_tab = new XMRigWidget(wallet, nullptr);
-}
-
-QString XMRigPlugin::id() {
- return "xmrig";
-}
-
-int XMRigPlugin::idx() const {
- return 70;
-}
-
-QString XMRigPlugin::parent() {
- return {};
-}
-
-QString XMRigPlugin::displayName() {
- return "Mining";
-}
-
-QString XMRigPlugin::description() {
- return {};
-}
-
-QString XMRigPlugin::icon() {
- return "mining.png";
-}
-
-QStringList XMRigPlugin::socketData() {
- return {"xmrig"};
-}
-
-Plugin::PluginType XMRigPlugin::type() {
- return Plugin::PluginType::TAB;
-}
-
-QWidget* XMRigPlugin::tab() {
- return m_tab;
-}
-
-bool XMRigPlugin::requiresWebsocket() {
- return false;
-}
-
-const bool XMRigPlugin::registered = [] {
- PluginRegistry::registerPlugin(XMRigPlugin::create());
- PluginRegistry::getInstance().registerPluginCreator(&XMRigPlugin::create);
- return true;
-}();
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#ifndef XMRIGPLUGIN_H
-#define XMRIGPLUGIN_H
-
-#include "plugins/Plugin.h"
-#include "XMRigWidget.h"
-
-class XMRigPlugin : public Plugin {
- Q_OBJECT
-
-public:
- explicit XMRigPlugin();
-
- QString id() override;
- int idx() const override;
- QString parent() override;
- QString displayName() override;
- QString description() override;
- QString icon() override;
- QStringList socketData() override;
- PluginType type() override;
- QWidget* tab() override;
- bool requiresWebsocket() override;
-
- void initialize(Wallet *wallet, QObject *parent) override;
-
- static XMRigPlugin* create() { return new XMRigPlugin(); }
-
-private:
- XMRigWidget* m_tab = nullptr;
- static const bool registered;
-};
-
-#endif //XMRIGPLUGIN_H
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#include "XMRigWidget.h"
-#include "ui_XMRigWidget.h"
-
-#include <QDesktopServices>
-#include <QFileDialog>
-#include <QInputDialog>
-#include <QScrollBar>
-#include <QStandardItemModel>
-#include <QTableWidget>
-
-#include "WebsocketNotifier.h"
-#include "utils/Icons.h"
-#include "utils/Utils.h"
-#include "WindowManager.h"
-
-XMRigWidget::XMRigWidget(Wallet *wallet, QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::XMRigWidget)
- , m_wallet(wallet)
- , m_XMRig(new XmRig(Config::defaultConfigDir().path(), this))
- , m_model(new QStandardItemModel(this))
- , m_contextMenu(new QMenu(this))
-{
- ui->setupUi(this);
-
- connect(m_XMRig, &XmRig::stateChanged, this, &XMRigWidget::onXMRigStateChanged);
- connect(m_XMRig, &XmRig::output, this, &XMRigWidget::onProcessOutput);
- connect(m_XMRig, &XmRig::error, this, &XMRigWidget::onProcessError);
- connect(m_XMRig, &XmRig::hashrate, this, &XMRigWidget::onHashrate);
-
- ui->deprecationFrame->setInfo(icons()->icon("warning.png"), "This feature is deprecated and will be removed in an upcoming version.");
-
- // [Downloads] tab
- ui->tableView->setModel(m_model);
- m_contextMenu->addAction(icons()->icon("network.png"), "Download file", this, &XMRigWidget::linkClicked);
- connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &XMRigWidget::showContextMenu);
- connect(ui->tableView, &QTableView::doubleClicked, this, &XMRigWidget::linkClicked);
-
- // [Settings] tab
- ui->poolFrame->show();
- ui->soloFrame->hide();
-
- // XMRig executable
- connect(ui->btn_browse, &QPushButton::clicked, this, &XMRigWidget::onBrowseClicked);
- ui->lineEdit_path->setText(conf()->get(Config::xmrigPath).toString());
-
- // Run as admin/root
- bool elevated = conf()->get(Config::xmrigElevated).toBool();
- if (elevated) {
- ui->radio_elevateYes->setChecked(true);
- } else {
- ui->radio_elevateNo->setChecked(true);
- }
- connect(ui->radio_elevateYes, &QRadioButton::toggled, this, &XMRigWidget::onXMRigElevationChanged);
-#if defined(Q_OS_WIN)
- ui->radio_elevateYes->setToolTip("Not supported on Windows, yet.");
- ui->radio_elevateYes->setEnabled(false);
- ui->radio_elevateNo->setChecked(true);
-#endif
-
- // CPU threads
- ui->threadSlider->setMinimum(1);
- ui->threadSlider->setMaximum(QThread::idealThreadCount());
-
- int threads = conf()->get(Config::xmrigThreads).toInt();
- ui->threadSlider->setValue(threads);
- ui->label_threads->setText(QString("CPU threads: %1").arg(threads));
-
- connect(ui->threadSlider, &QSlider::valueChanged, this, &XMRigWidget::onThreadsValueChanged);
-
- // Mining mode
- connect(ui->combo_miningMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XMRigWidget::onMiningModeChanged);
- ui->combo_miningMode->setCurrentIndex(conf()->get(Config::miningMode).toInt());
-
- // Pool/node address
- this->updatePools();
- connect(ui->combo_pools, &QComboBox::currentTextChanged, this, &XMRigWidget::onPoolChanged);
-
- connect(ui->btn_poolConfig, &QPushButton::clicked, [this]{
- QStringList pools = conf()->get(Config::pools).toStringList();
- bool ok;
- QString poolStr = QInputDialog::getMultiLineText(this, "Pool addresses", "Set pool addresses (one per line):", pools.join("\n"), &ok);
- if (!ok) {
- return;
- }
- QStringList newPools = poolStr.split("\n");
- newPools.removeAll("");
- newPools.removeDuplicates();
- conf()->set(Config::pools, newPools);
- this->updatePools();
- });
-
- ui->lineEdit_solo->setText(conf()->get(Config::xmrigDaemon).toString());
- connect(ui->lineEdit_solo, &QLineEdit::textChanged, [this](){
- conf()->set(Config::xmrigDaemon, ui->lineEdit_solo->text());
- });
-
- // Network settings
- connect(ui->check_tls, &QCheckBox::toggled, this, &XMRigWidget::onNetworkTLSToggled);
- connect(ui->relayTor, &QCheckBox::toggled, this, &XMRigWidget::onNetworkTorToggled);
- ui->check_tls->setChecked(conf()->get(Config::xmrigNetworkTLS).toBool());
- ui->relayTor->setChecked(conf()->get(Config::xmrigNetworkTor).toBool());
-
- // Receiving address
- auto username = m_wallet->getCacheAttribute("feather.xmrig_username");
- if (!username.isEmpty()) {
- ui->lineEdit_address->setText(username);
- }
- connect(ui->lineEdit_address, &QLineEdit::textChanged, [=]() {
- m_wallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text());
- });
- connect(ui->btn_fillPrimaryAddress, &QPushButton::clicked, this, &XMRigWidget::onUsePrimaryAddressClicked);
-
- // Password
- auto password = m_wallet->getCacheAttribute("feather.xmrig_password");
- ui->lineEdit_password->setText(password);
- connect(ui->lineEdit_password, &QLineEdit::textChanged, [=]() {
- m_wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text());
- });
-
- // [Status] tab
- connect(ui->btn_start, &QPushButton::clicked, this, &XMRigWidget::onStartClicked);
- connect(ui->btn_stop, &QPushButton::clicked, this, &XMRigWidget::onStopClicked);
- connect(ui->btn_clear, &QPushButton::clicked, this, &XMRigWidget::onClearClicked);
-
- ui->btn_stop->setEnabled(false);
- ui->check_autoscroll->setChecked(true);
- ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse);
- ui->label_status->hide();
-
- this->printConsoleInfo();
-
- connect(windowManager(), &WindowManager::websocketStatusChanged, this, &XMRigWidget::setDownloadsTabEnabled);
- connect(websocketNotifier(), &WebsocketNotifier::dataReceived, this, [this](const QString &type, const QJsonValue &json) {
- if (type == "xmrig") {
- QJsonObject xmrig_data = json.toObject();
- this->onDownloads(xmrig_data);
- }
- });
-}
-
-bool XMRigWidget::isMining() {
- return m_isMining;
-}
-
-void XMRigWidget::setDownloadsTabEnabled(bool enabled) {
- ui->tabWidget->setTabVisible(2, enabled);
-}
-
-void XMRigWidget::onWalletClosed() {
- this->onStopClicked();
-}
-
-void XMRigWidget::onThreadsValueChanged(int threads) {
- conf()->set(Config::xmrigThreads, threads);
- ui->label_threads->setText(QString("CPU threads: %1").arg(threads));
-}
-
-void XMRigWidget::onPoolChanged(const QString &pool) {
- if (!pool.isEmpty()) {
- conf()->set(Config::xmrigPool, pool);
- }
-}
-
-void XMRigWidget::onXMRigElevationChanged(bool elevated) {
- conf()->set(Config::xmrigElevated, elevated);
-}
-
-void XMRigWidget::onBrowseClicked() {
- QString fileName = QFileDialog::getOpenFileName(this, "Path to XMRig executable", QDir::homePath());
- if (fileName.isEmpty()) {
- return;
- }
- conf()->set(Config::xmrigPath, fileName);
- ui->lineEdit_path->setText(fileName);
-}
-
-void XMRigWidget::onClearClicked() {
- ui->console->clear();
-}
-
-void XMRigWidget::onUsePrimaryAddressClicked() {
- ui->lineEdit_address->setText(m_wallet->address(0, 0));
-}
-
-void XMRigWidget::onStartClicked() {
- QString xmrigPath = conf()->get(Config::xmrigPath).toString();
- if (!this->checkXMRigPath()) {
- return;
- }
-
- QString address = [this](){
- if (ui->combo_miningMode->currentIndex() == Config::MiningMode::Pool) {
- return conf()->get(Config::xmrigPool).toString();
- } else {
- return ui->lineEdit_solo->text().trimmed();
- }
- }();
- if (address.isEmpty()) {
- ui->console->appendPlainText("No pool or node address set. Please configure on the Settings tab.");
- return;
- }
-
- // username is receiving address usually
- auto username = m_wallet->getCacheAttribute("feather.xmrig_username");
- auto password = m_wallet->getCacheAttribute("feather.xmrig_password");
-
- if (username.isEmpty()) {
- ui->console->appendPlainText("Please specify a receiving address on the Settings screen.");
- return;
- }
-
- int threads = ui->threadSlider->value();
- bool solo = (ui->combo_miningMode->currentIndex() == Config::MiningMode::Solo);
- QStringList extraOptions = ui->lineEdit_extraOptions->text().split(" ");
-
- m_XMRig->start(xmrigPath, threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked(),
- ui->radio_elevateYes->isChecked(), solo, extraOptions);
-}
-
-void XMRigWidget::onStopClicked() {
- m_XMRig->stop();
-}
-
-void XMRigWidget::onProcessOutput(const QByteArray &data) {
- auto output = Utils::barrayToString(data);
- if(output.endsWith("\n"))
- output = output.trimmed();
-
- ui->console->appendPlainText(output);
-
- if(ui->check_autoscroll->isChecked())
- ui->console->verticalScrollBar()->setValue(ui->console->verticalScrollBar()->maximum());
-}
-
-void XMRigWidget::onProcessError(const QString &msg) {
- ui->console->appendPlainText("\n" + msg);
- ui->btn_start->setEnabled(true);
- ui->btn_stop->setEnabled(false);
- this->setMiningStopped();
-}
-
-void XMRigWidget::onHashrate(const QString &hashrate) {
- ui->label_status->show();
- ui->label_status->setText(QString("Mining at %1").arg(hashrate));
-}
-
-void XMRigWidget::onDownloads(const QJsonObject &data) {
- // For the downloads table we'll manually update the table
- // with items once, as opposed to creating a class in
- // src/models/. Saves effort; full-blown model
- // is unnecessary in this case.
-
- m_model->clear();
- m_urls.clear();
-
- auto version = data.value("version").toString();
- ui->label_latest_version->setText(QString("Latest version: %1").arg(version));
- QJsonObject assets = data.value("assets").toObject();
-
- const auto _linux = assets.value("linux").toArray();
- const auto macos = assets.value("macos").toArray();
- const auto windows = assets.value("windows").toArray();
-
- auto info = QSysInfo::productType();
- QJsonArray *os_assets;
- if(info == "osx") {
- os_assets = const_cast<QJsonArray *>(&macos);
- } else if (info == "windows") {
- os_assets = const_cast<QJsonArray *>(&windows);
- } else {
- // assume linux
- os_assets = const_cast<QJsonArray *>(&_linux);
- }
-
- int i = 0;
- for(const auto &entry: *os_assets) {
- auto _obj = entry.toObject();
- auto _name = _obj.value("name").toString();
- auto _url = _obj.value("url").toString();
- auto _created_at = _obj.value("created_at").toString();
-
- m_urls.append(_url);
- auto download_count = _obj.value("download_count").toInt();
-
- m_model->setItem(i, 0, Utils::qStandardItem(_name));
- m_model->setItem(i, 1, Utils::qStandardItem(_created_at));
- m_model->setItem(i, 2, Utils::qStandardItem(QString::number(download_count)));
- i++;
- }
-
- m_model->setHeaderData(0, Qt::Horizontal, tr("Filename"), Qt::DisplayRole);
- m_model->setHeaderData(1, Qt::Horizontal, tr("Date"), Qt::DisplayRole);
- m_model->setHeaderData(2, Qt::Horizontal, tr("Downloads"), Qt::DisplayRole);
-
- ui->tableView->verticalHeader()->setVisible(false);
- ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
- ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
- ui->tableView->setColumnWidth(2, 100);
-}
-
-void XMRigWidget::showContextMenu(const QPoint &pos) {
- QModelIndex index = ui->tableView->indexAt(pos);
- if (!index.isValid()) {
- return;
- }
- m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos));
-}
-
-void XMRigWidget::updatePools() {
- QStringList pools = conf()->get(Config::pools).toStringList();
- if (pools.isEmpty()) {
- pools = m_defaultPools;
- conf()->set(Config::pools, pools);
- }
- ui->combo_pools->clear();
- ui->combo_pools->insertItems(0, pools);
-
- QString preferredPool = conf()->get(Config::xmrigPool).toString();
- if (pools.contains(preferredPool)) {
- ui->combo_pools->setCurrentIndex(pools.indexOf(preferredPool));
- } else {
- preferredPool = pools.at(0);
- conf()->set(Config::xmrigPool, preferredPool);
- }
-}
-
-void XMRigWidget::printConsoleInfo() {
- ui->console->appendPlainText(QString("Detected %1 CPU threads.").arg(QThread::idealThreadCount()));
- if (this->checkXMRigPath()) {
- QString path = conf()->get(Config::xmrigPath).toString();
- ui->console->appendPlainText(QString("XMRig path set to %1").arg(path));
- }
-}
-
-void XMRigWidget::onMiningModeChanged(int mode) {
- conf()->set(Config::miningMode, mode);
-
- if (mode == Config::MiningMode::Pool) {
- ui->poolFrame->show();
- ui->soloFrame->hide();
- ui->label_poolNodeAddress->setText("Pool address:");
- ui->check_tls->setChecked(true);
- } else { // Solo mining
- ui->poolFrame->hide();
- ui->soloFrame->show();
- ui->label_poolNodeAddress->setText("Node address:");
- ui->check_tls->setChecked(false);
- }
-}
-
-void XMRigWidget::onNetworkTLSToggled(bool checked) {
- conf()->set(Config::xmrigNetworkTLS, checked);
-}
-
-void XMRigWidget::onNetworkTorToggled(bool checked) {
- conf()->set(Config::xmrigNetworkTor, checked);
-}
-
-void XMRigWidget::onXMRigStateChanged(QProcess::ProcessState state) {
- if (state == QProcess::ProcessState::Starting) {
- ui->btn_start->setEnabled(false);
- ui->btn_stop->setEnabled(false);
- this->setMiningStarted();
- }
- else if (state == QProcess::ProcessState::Running) {
- ui->btn_start->setEnabled(false);
- ui->btn_stop->setEnabled(true);
- this->setMiningStarted();
- }
- else if (state == QProcess::ProcessState::NotRunning) {
- ui->btn_start->setEnabled(true); // todo
- ui->btn_stop->setEnabled(false);
- ui->label_status->hide();
- this->setMiningStopped();
- }
-}
-
-void XMRigWidget::setMiningStopped() {
- m_isMining = false;
- emit miningEnded();
-}
-
-void XMRigWidget::setMiningStarted() {
- m_isMining = true;
- emit miningStarted();
-}
-
-bool XMRigWidget::checkXMRigPath() {
- QString path = conf()->get(Config::xmrigPath).toString();
-
- if (path.isEmpty()) {
- ui->console->appendPlainText("No XMRig executable is set. Please configure on the Settings tab.");
- return false;
- } else if (!Utils::fileExists(path)) {
- ui->console->appendPlainText("Invalid path to XMRig executable detected. Please reconfigure on the Settings tab.");
- return false;
- } else {
- return true;
- }
-}
-
-void XMRigWidget::linkClicked() {
- QModelIndex index = ui->tableView->currentIndex();
- auto download_link = m_urls.at(index.row());
- Utils::externalLinkWarning(this, download_link);
-}
-
-QStandardItemModel *XMRigWidget::model() {
- return m_model;
-}
-
-XMRigWidget::~XMRigWidget() = default;
\ No newline at end of file
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#ifndef FEATHER_XMRIGWIDGET_H
-#define FEATHER_XMRIGWIDGET_H
-
-#include <QMenu>
-#include <QWidget>
-#include <QItemSelection>
-#include <QStandardItemModel>
-
-#include "xmrig.h"
-#include "utils/config.h"
-#include "libwalletqt/Wallet.h"
-
-namespace Ui {
- class XMRigWidget;
-}
-
-class XMRigWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit XMRigWidget(Wallet *wallet, QWidget *parent = nullptr);
- ~XMRigWidget() override;
- QStandardItemModel *model();
-
- bool isMining();
- void setDownloadsTabEnabled(bool enabled);
-
-public slots:
- void onWalletClosed();
- void onStartClicked();
- void onStopClicked();
- void onClearClicked();
- void onUsePrimaryAddressClicked();
- void onDownloads(const QJsonObject &data);
- void linkClicked();
- void onProcessError(const QString &msg);
- void onProcessOutput(const QByteArray &msg);
- void onHashrate(const QString &hashrate);
- void onMiningModeChanged(int mode);
- void onNetworkTLSToggled(bool checked);
- void onNetworkTorToggled(bool checked);
- void onXMRigStateChanged(QProcess::ProcessState state);
-
-private slots:
- void onBrowseClicked();
- void onThreadsValueChanged(int date);
- void onPoolChanged(const QString &pool);
- void onXMRigElevationChanged(bool elevated);
-
-signals:
- void miningStarted();
- void miningEnded();
-
-private:
- void showContextMenu(const QPoint &pos);
- void updatePools();
- void printConsoleInfo();
- void setMiningStopped();
- void setMiningStarted();
- bool checkXMRigPath();
-
- QScopedPointer<Ui::XMRigWidget> ui;
- Wallet *m_wallet;
- XmRig *m_XMRig;
- QStandardItemModel *m_model;
- QMenu *m_contextMenu;
-
- bool m_isMining = false;
- QStringList m_urls;
- QStringList m_defaultPools{"pool.xmr.pt:9000", "pool.supportxmr.com:9000", "mine.xmrpool.net:443", "xmrpool.eu:9999", "xmr-eu1.nanopool.org:14433","monerohash.com:9999"};
-};
-
-#endif // FEATHER_XMRWIDGET_H
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>XMRigWidget</class>
- <widget class="QWidget" name="XMRigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>1329</width>
- <height>540</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>1</number>
- </property>
- <widget class="QWidget" name="tabMining">
- <attribute name="title">
- <string>Status</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QFrame" name="outputFrame">
- <property name="frameShape">
- <enum>QFrame::Shape::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Shadow::Plain</enum>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QPlainTextEdit" name="console">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QPushButton" name="btn_clear">
- <property name="text">
- <string>Clear</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="check_autoscroll">
- <property name="text">
- <string>auto-scroll</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="label_status">
- <property name="text">
- <string>Mining at</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="btn_stop">
- <property name="text">
- <string>Stop</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="btn_start">
- <property name="text">
- <string>Start mining</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tabSettings">
- <attribute name="title">
- <string>Settings</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_9">
- <item>
- <widget class="InfoFrame" name="deprecationFrame">
- <property name="frameShape">
- <enum>QFrame::Shape::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Shadow::Raised</enum>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_6">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_6">
- <item>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>XMRig executable:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_5">
- <item>
- <widget class="QLineEdit" name="lineEdit_path">
- <property name="placeholderText">
- <string>/path/to/xmrig</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="btn_browse">
- <property name="text">
- <string>Browse</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Run as admin/root:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QRadioButton" name="radio_elevateYes">
- <property name="text">
- <string>Yes</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="radio_elevateNo">
- <property name="text">
- <string>No</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_threads">
- <property name="text">
- <string>CPU threads: </string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSlider" name="threadSlider">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Mining mode:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_10">
- <item>
- <widget class="QComboBox" name="combo_miningMode">
- <item>
- <property name="text">
- <string>Pool mining</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Solo mining</string>
- </property>
- </item>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_7">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_poolNodeAddress">
- <property name="text">
- <string>Pool/node address:</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_13">
- <item>
- <widget class="QFrame" name="poolFrame">
- <property name="frameShape">
- <enum>QFrame::Shape::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Shadow::Plain</enum>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QComboBox" name="combo_pools">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="btn_poolConfig">
- <property name="text">
- <string>Configure</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>414</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QFrame" name="soloFrame">
- <property name="frameShape">
- <enum>QFrame::Shape::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Shadow::Plain</enum>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_8">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLineEdit" name="lineEdit_solo">
- <property name="text">
- <string>127.0.0.1:18081</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>173</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Network settings:</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_9">
- <item>
- <widget class="QCheckBox" name="check_tls">
- <property name="text">
- <string>Secure connection (TLS)</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="relayTor">
- <property name="text">
- <string>Connect via Tor</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Orientation::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Receiving address:</string>
- </property>
- </widget>
- </item>
- <item row="6" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLineEdit" name="lineEdit_address"/>
- </item>
- <item>
- <widget class="QPushButton" name="btn_fillPrimaryAddress">
- <property name="text">
- <string>Use primary address</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="7" column="0">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Password (optional):</string>
- </property>
- </widget>
- </item>
- <item row="7" column="1">
- <widget class="QLineEdit" name="lineEdit_password"/>
- </item>
- <item row="8" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Extra command-line options:</string>
- </property>
- </widget>
- </item>
- <item row="8" column="1">
- <widget class="QLineEdit" name="lineEdit_extraOptions"/>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Orientation::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tabDownloads">
- <attribute name="title">
- <string>Downloads</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_7">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_7">
- <item>
- <widget class="QLabel" name="label_latest_version">
- <property name="text">
- <string>Latest version:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_version">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>(right-click to download)</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QTableView" name="tableView">
- <property name="contextMenuPolicy">
- <enum>Qt::ContextMenuPolicy::CustomContextMenu</enum>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
- </property>
- <property name="sortingEnabled">
- <bool>false</bool>
- </property>
- <attribute name="horizontalHeaderStretchLastSection">
- <bool>false</bool>
- </attribute>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>InfoFrame</class>
- <extends>QFrame</extends>
- <header>components.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
- <slots>
- <slot>linkClicked()</slot>
- </slots>
-</ui>
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#include <QScreen>
-#include <QDesktopServices>
-
-#include "utils/config.h"
-#include "utils/Utils.h"
-#include "xmrig.h"
-#include "utils/TorManager.h"
-
-XmRig::XmRig(const QString &configDir, QObject *parent)
- : QObject(parent)
- , m_process(new QProcess(this))
-{
- 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::onStateChanged);
-}
-
-void XmRig::stop() {
- qDebug() << m_process->processId();
- if (m_process->state() == QProcess::Running) {
-#if defined(Q_OS_WIN)
- m_process->kill(); // https://doc.qt.io/qt-5/qprocess.html#terminate
-#elif defined(Q_OS_LINUX)
- if (m_elevated) {
- m_killProcess.start("pkexec", QStringList() << "kill" << QString::number(m_process->processId()));
- return;
- }
-#endif
- m_process->terminate();
- }
-}
-
-void XmRig::start(const QString &path, int threads, const QString &address, const QString &username,
- const QString &password, bool tor, bool tls, bool elevated, bool solo, const QStringList &extraOptions)
-{
- m_elevated = elevated;
-
- auto state = m_process->state();
- if (state == QProcess::ProcessState::Running || state == QProcess::ProcessState::Starting) {
- emit error("Can't start XMRig, already running or starting");
- return;
- }
-
- if (path.isEmpty()) {
- emit error("XmRig->Start path parameter missing.");
- return;
- }
-
- if (!Utils::fileExists(path)) {
- emit error(QString("Path to XMRig binary invalid; file does not exist: %1").arg(path));
- return;
- }
-
- QStringList arguments;
- if (m_elevated) {
- arguments << path;
- }
- arguments << "-o" << address;
- arguments << "-u" << username;
- if (!password.isEmpty()) {
- arguments << "-p" << password;
- }
- arguments << "--no-color";
- arguments << "-t" << QString::number(threads);
- if (tor) {
- QString host = conf()->get(Config::socks5Host).toString();
- QString port = conf()->get(Config::socks5Port).toString();
- if (!torManager()->isLocalTor()) {
- host = torManager()->featherTorHost;
- port = QString::number(torManager()->featherTorPort);
- }
- arguments << "-x" << QString("%1:%2").arg(host, port);
- }
- if (tls) {
- arguments << "--tls";
- }
- if (solo) {
- arguments << "--daemon";
- }
- arguments += extraOptions;
-
- QString cmd = QString("%1 %2").arg(path, arguments.join(" "));
- emit output(cmd.toUtf8());
-
- if (m_elevated) {
- m_process->start("pkexec", arguments);
- } else {
- m_process->start(path, arguments);
- }
-}
-
-void XmRig::onStateChanged(QProcess::ProcessState state) {
- emit stateChanged(state);
-
- if (state == QProcess::ProcessState::Running) {
- emit output("XMRig started");
- }
-
- else if (state == QProcess::ProcessState::NotRunning) {
- emit output("XMRig stopped");
- }
-}
-
-void XmRig::handleProcessOutput() {
- QByteArray _output = m_process->readAllStandardOutput();
- if(_output.contains("miner") && _output.contains("speed")) {
- // detect hashrate
- auto str = Utils::barrayToString(_output);
- auto spl = str.mid(str.indexOf("speed")).split(" ");
- auto rate = spl.at(2) + "H/s";
- qDebug() << "mining hashrate: " << rate;
- emit hashrate(rate);
- }
-
- emit output(_output);
-}
-
-void XmRig::handleProcessError(QProcess::ProcessError err) {
- if (err == QProcess::ProcessError::Crashed)
- emit error("XMRig crashed or killed");
- else if (err == QProcess::ProcessError::FailedToStart) {
- auto path = conf()->get(Config::xmrigPath).toString();
- emit error(QString("XMRig binary failed to start: %1").arg(path));
- }
-}
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: The Monero Project
-
-#ifndef FEATHER_XMRIG_H
-#define FEATHER_XMRIG_H
-
-#include <QProcess>
-
-class XmRig : public QObject
-{
-Q_OBJECT
-
-public:
- explicit XmRig(const QString &configDir, QObject *parent = nullptr);
-
- void start(const QString &path, int threads, const QString &address, const QString &username, const QString &password, bool tor = false, bool tls = true, bool elevated = false, bool solo = false, const QStringList &extraOptions = {});
- void stop();
-
-signals:
- void error(const QString &msg);
- void output(const QByteArray &data);
- void hashrate(const QString &rate);
- void stateChanged(QProcess::ProcessState state);
-
-private slots:
- void onStateChanged(QProcess::ProcessState);
- void handleProcessOutput();
- void handleProcessError(QProcess::ProcessError error);
-
-private:
- QProcess *m_process;
- QProcess m_killProcess;
- bool m_elevated;
-};
-
-#endif //FEATHER_XMRIG_H
{Config::showChangeAddresses,{QS("showChangeAddresses"), false}},
{Config::showAddressIndex,{QS("showAddressIndex"), true}},
{Config::showAddressLabels,{QS("showAddressLabels"), true}},
-
- // Mining
- {Config::miningMode,{QS("miningMode"), Config::MiningMode::Pool}},
- {Config::xmrigPath,{QS("xmrigPath"), ""}},
- {Config::xmrigElevated,{QS("xmrigElevated"), false}},
- {Config::xmrigThreads,{QS("xmrigThreads"), 1}},
- {Config::xmrigPool,{QS("xmrigPool"), "pool.xmr.pt:9000"}},
- {Config::xmrigDaemon,{QS("xmrigDaemon"), "127.0.0.1:18081"}},
- {Config::xmrigNetworkTLS,{QS("xmrigNetworkTLS"), true}},
- {Config::xmrigNetworkTor,{QS("xmrigNetworkTor"), false}},
- {Config::pools,{QS("pools"), {}}},
// Settings
{Config::lastSettingsPage, {QS("lastSettingsPage"), 0}},
{Config::useLocalTor, {QS("useLocalTor"), false}},
{Config::initSyncThreshold, {QS("initSyncThreshold"), 360}},
- {Config::enabledPlugins, {QS("enabledPlugins"), QStringList{"tickers", "crowdfunding", "bounties", "revuo", "calc", "xmrig"}}},
+ {Config::enabledPlugins, {QS("enabledPlugins"), QStringList{"tickers", "crowdfunding", "bounties", "revuo", "calc"}}},
{Config::restartRequired, {QS("restartRequired"), false}},
{Config::tickers, {QS("tickers"), QStringList{"XMR", "BTC", "XMR/BTC"}}},
showAddressIndex,
showAddressLabels,
- // Mining
- miningMode,
- xmrigPath,
- xmrigElevated,
- xmrigThreads,
- xmrigPool,
- xmrigDaemon,
- xmrigNetworkTLS,
- xmrigNetworkTor,
- pools,
-
// Settings
lastSettingsPage,