diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/main/main.cpp | 5 | ||||
| -rw-r--r-- | src/p2pool/P2PoolManager.cpp | 238 | ||||
| -rw-r--r-- | src/p2pool/P2PoolManager.h | 72 |
4 files changed, 318 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27b4dd09..b5718df3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,8 @@ file(GLOB SOURCE_FILES "libwalletqt/UnsignedTransaction.h" "daemon/*.h" "daemon/*.cpp" + "p2pool/*.h" + "p2pool/*.cpp" "model/*.h" "model/*.cpp" "qt/*.h" @@ -97,6 +99,7 @@ target_include_directories(monero-wallet-gui PUBLIC ${CMAKE_SOURCE_DIR}/monero/external/qrcodegen ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/daemon + ${CMAKE_CURRENT_SOURCE_DIR}/p2pool ${CMAKE_CURRENT_SOURCE_DIR}/libwalletqt ${CMAKE_CURRENT_SOURCE_DIR}/model ${CMAKE_CURRENT_SOURCE_DIR}/QR-Code-scanner diff --git a/src/main/main.cpp b/src/main/main.cpp index a6a77a5b..db339d71 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -79,6 +79,7 @@ // IOS exclusions #ifndef Q_OS_IOS #include "daemon/DaemonManager.h" +#include "p2pool/P2PoolManager.h" #endif #if defined(Q_OS_WIN) @@ -401,6 +402,8 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw #ifndef Q_OS_IOS qmlRegisterUncreatableType<DaemonManager>("moneroComponents.DaemonManager", 1, 0, "DaemonManager", "DaemonManager can't be instantiated directly"); + qmlRegisterUncreatableType<P2PoolManager>("moneroComponents.P2PoolManager", 1, 0, "P2PoolManager", + "P2PoolManager can't be instantiated directly"); #endif qmlRegisterUncreatableType<AddressBookModel>("moneroComponents.AddressBookModel", 1, 0, "AddressBookModel", "AddressBookModel can't be instantiated directly"); @@ -462,7 +465,9 @@ Verify update binary using 'shasum'-compatible (SHA256 algo) output signed by tw // Exclude daemon manager from IOS #ifndef Q_OS_IOS DaemonManager daemonManager; + P2PoolManager p2poolManager; engine.rootContext()->setContextProperty("daemonManager", &daemonManager); + engine.rootContext()->setContextProperty("p2poolManager", &p2poolManager); #endif engine.rootContext()->setContextProperty("isWindows", isWindows); diff --git a/src/p2pool/P2PoolManager.cpp b/src/p2pool/P2PoolManager.cpp new file mode 100644 index 00000000..ccfe4f94 --- /dev/null +++ b/src/p2pool/P2PoolManager.cpp @@ -0,0 +1,238 @@ +// Copyright (c) 2014-2022, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "P2PoolManager.h" +#include "net/http_client.h" +#include "common/util.h" +#include "qt/utils.h" +#include <QElapsedTimer> +#include <QFile> +#include <QMutexLocker> +#include <QFileInfo> +#include <QDir> +#include <QDebug> +#include <QUrl> +#include <QtConcurrent/QtConcurrent> +#include <QApplication> +#include <QProcess> +#include <QMap> +#include <QCryptographicHash> + +void P2PoolManager::download() { + m_scheduler.run([this] { + QUrl url; + QString fileName; + QString validHash; + #ifdef Q_OS_WIN + url = "https://github.com/SChernykh/p2pool/releases/download/v1.9/p2pool-v1.9-windows-x64.zip"; + fileName = "p2pool-v1.9-windows-x64.zip"; + validHash = "2587903dc04a4879dca2b6f5c5b584e869928e716274a7660e24b219c9f18839"; + #elif defined(Q_OS_LINUX) + url = "https://github.com/SChernykh/p2pool/releases/download/v1.9/p2pool-v1.9-linux-x64.tar.gz"; + fileName = "p2pool-v1.9-linux-x64.tar.gz"; + validHash = "0cd85d933ac4a76708d326698d9db3155bb29d0be82984c735fabd9e9a351b8e"; + #elif defined(Q_OS_MACOS) + url = "https://github.com/SChernykh/p2pool/releases/download/v1.9/p2pool-v1.9-macos-x64.tar.gz"; + fileName = "p2pool-v1.9-macos-x64.tar.gz"; + validHash = "47fbdd69d719da80597dd5487f109b61e30b540499cced7b93de1ee01344351e"; + #endif + QFile file(fileName); + epee::net_utils::http::http_simple_client http_client; + const epee::net_utils::http::http_response_info* response = NULL; + std::string userAgent = randomUserAgent().toStdString(); + std::chrono::milliseconds timeout = std::chrono::seconds(10); + http_client.set_server(url.host().toStdString(), "443", {}); + bool success = http_client.invoke_get(url.path().toStdString(), timeout, {}, std::addressof(response), {{"User-Agent", userAgent}}); + if (response->m_response_code == 302) { + epee::net_utils::http::fields_list fields = response->m_header_info.m_etc_fields; + for (std::pair<std::string, std::string> i : fields) { + if (i.first == "Location") { + url = QString::fromStdString(i.second); + http_client.set_server(url.host().toStdString(), "443", {}); + std::string query = url.query(QUrl::FullyEncoded).toStdString(); + std::string path = url.path().toStdString() + "?" + query; + http_client.wipe_response(); + success = http_client.invoke_get(path, timeout, {}, std::addressof(response), {{"User-Agent", userAgent}}); + } + } + } + if (!success) { + emit p2poolDownloadFailure(); + } + else { + std::string stringData = response->m_body; + QByteArray data(stringData.c_str(), stringData.length()); + QByteArray hashData = QCryptographicHash::hash(data, QCryptographicHash::Sha256); + QString hash = hashData.toHex(); + if (hash != validHash) { + emit p2poolDownloadFailure(); + } + else { + file.open(QIODevice::WriteOnly); + file.write(data); + file.close(); + QProcess::execute("tar", {"-xzf", fileName, "--strip=1", "-C", QApplication::applicationDirPath()}); + QFile::remove(fileName); + if (isInstalled()) { + emit p2poolDownloadSuccess(); + } + else { + emit p2poolDownloadFailure(); + } + } + } + }); + return; +} + +bool P2PoolManager::isInstalled() { + if (!QFileInfo(m_p2pool).isFile()) + { + return false; + } + return true; +} + +void P2PoolManager::getStatus() { + QString statsPath = QApplication::applicationDirPath() + "/stats/local/miner"; + bool status = true; + if (!QFileInfo(statsPath).isFile() || !started) + { + status = started; + emit p2poolStatus(status, 0); + return; + } + QFile statsFile(statsPath); + statsFile.open(QIODevice::ReadOnly); + QTextStream statsOut(&statsFile); + QByteArray data; + statsOut >> data; + statsFile.close(); + QJsonDocument json = QJsonDocument::fromJson(data); + QJsonObject jsonObj = json.object(); + int hashrate = jsonObj.value("current_hashrate").toInt(); + emit p2poolStatus(status, hashrate); + return; +} + +bool P2PoolManager::start(const QString &flags, const QString &address, const QString &chain, const QString &threads) +{ + // prepare command line arguments and pass to p2pool + QStringList arguments; + + // Custom startup flags for p2pool + foreach (const QString &str, flags.split(" ")) { + qDebug() << QString(" [%1] ").arg(str); + if (!str.isEmpty()) + arguments << str; + } + + if (!arguments.contains("--local-api")) { + arguments << "--local-api"; + } + + if (!arguments.contains("--data-api")) { + QDir dir; + QString dirName = QApplication::applicationDirPath() + "/stats/"; + QDir statsDir(dirName); + if (dir.exists(dirName)) { + statsDir.removeRecursively(); + } + dir.mkdir(dirName); + arguments << "--data-api" << dirName; + } + + if (!arguments.contains("--start-mining")) { + arguments << "--start-mining" << threads; + } + + if (chain == "mini") { + arguments << "--mini"; + } + + if (!arguments.contains("--wallet")) { + arguments << "--wallet" << address; + } + + qDebug() << "starting p2pool " + m_p2pool; + qDebug() << "With command line arguments " << arguments; + + QMutexLocker locker(&m_p2poolMutex); + + m_p2poold.reset(new QProcess()); + + // Set program parameters + m_p2poold->setProgram(m_p2pool); + m_p2poold->setArguments(arguments); + m_p2poold->setWorkingDirectory(QApplication::applicationDirPath()); + + // Start p2pool + started = m_p2poold->startDetached(); + + if (!started) { + qDebug() << "P2Pool start error: " + m_p2poold->errorString(); + emit p2poolStartFailure(); + return false; + } + + return true; +} + +void P2PoolManager::exit() +{ + qDebug("P2PoolManager: exit()"); + #ifdef Q_OS_WIN + QProcess::execute("taskkill", {"/F", "/IM", "p2pool.exe"}); + #else + QProcess::execute("pkill", {"p2pool"}); + #endif + started = false; + QString dirName = QApplication::applicationDirPath() + "/stats/"; + QDir dir(dirName); + dir.removeRecursively(); +} + +P2PoolManager::P2PoolManager(QObject *parent) + : QObject(parent) + , m_scheduler(this) +{ + started = false; + // Platform dependent path to p2pool +#ifdef Q_OS_WIN + m_p2pool = QApplication::applicationDirPath() + "/p2pool.exe"; +#elif defined(Q_OS_UNIX) + m_p2pool = QApplication::applicationDirPath() + "/p2pool"; +#endif + if (m_p2pool.length() == 0) { + qCritical() << "no p2pool binary defined for current platform"; + } +} + +P2PoolManager::~P2PoolManager() { + m_scheduler.shutdownWaitForFinished(); +} diff --git a/src/p2pool/P2PoolManager.h b/src/p2pool/P2PoolManager.h new file mode 100644 index 00000000..82e7832d --- /dev/null +++ b/src/p2pool/P2PoolManager.h @@ -0,0 +1,72 @@ +// Copyright (c) 2014-2022, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef P2POOLMANAGER_H +#define P2POOLMANAGER_H + +#include <memory> + +#include <QMutex> +#include <QObject> +#include <QUrl> +#include <QProcess> +#include "NetworkType.h" +#include "qt/FutureScheduler.h" + +class P2PoolManager : public QObject +{ + Q_OBJECT + +public: + explicit P2PoolManager(QObject *parent = 0); + ~P2PoolManager(); + + Q_INVOKABLE bool start(const QString &flags, const QString &address, const QString &chain, const QString &threads); + Q_INVOKABLE void exit(); + Q_INVOKABLE bool isInstalled(); + Q_INVOKABLE void getStatus(); + Q_INVOKABLE void download(); +private: + + bool running(NetworkType::Type nettype) const; +signals: + void p2poolStartFailure() const; + void p2poolStatus(bool isMining, int hashrate) const; + void p2poolDownloadFailure() const; + void p2poolDownloadSuccess() const; + +private: + std::unique_ptr<QProcess> m_p2poold; + QMutex m_p2poolMutex; + QString m_p2pool; + bool started = false; + + mutable FutureScheduler m_scheduler; +}; + +#endif // P2POOLMANAGER_H |
