From 5dfd53941365e5ec007a9ae41e1f1b1c098eadec Mon Sep 17 00:00:00 2001 From: Indeed Miners <32953696+IndeedMiners@users.noreply.github.com> Date: Thu, 11 Oct 2018 15:31:06 +0200 Subject: [PATCH] XMRig 2.8.0 Monero V8 (CNv2) --- CHANGELOG.md | 18 + CMakeLists.txt | 174 +-- README.md | 28 +- cmake/CUDA.cmake | 7 +- cmake/FindNVML.cmake | 1 + cmake/OpenSSL.cmake | 23 + cmake/cpu.cmake | 25 + res/app.rc | 4 +- src/3rdparty/aligned_malloc.h | 65 ++ src/3rdparty/rapidjson/prettywriter.h | 3 +- src/3rdparty/rapidjson/writer.h | 3 +- src/App.cpp | 101 +- src/App.h | 14 +- src/App_unix.cpp | 8 +- src/App_win.cpp | 10 +- src/Summary.cpp | 185 +-- src/Summary.h | 17 +- src/api/Api.cpp | 59 +- src/api/Api.h | 26 +- src/api/ApiRouter.cpp | 362 ++++++ src/api/ApiRouter.h | 75 ++ src/api/NetworkState.cpp | 6 +- src/common/Console.cpp | 61 + src/common/Console.h | 49 + src/common/Platform.cpp | 89 ++ src/common/Platform.h | 53 + src/common/Platform_mac.cpp | 109 ++ src/common/Platform_unix.cpp | 145 +++ src/common/Platform_win.cpp | 168 +++ src/common/api/HttpBody.h | 69 ++ src/common/api/HttpReply.h | 53 + src/common/api/HttpRequest.cpp | 175 +++ src/common/api/HttpRequest.h | 84 ++ src/common/api/Httpd.cpp | 148 +++ src/common/api/Httpd.h | 70 ++ src/common/config/CommonConfig.cpp | 495 ++++++++ src/common/config/CommonConfig.h | 120 ++ src/common/config/ConfigLoader.cpp | 330 ++++++ src/common/config/ConfigLoader.h | 71 ++ src/common/config/ConfigWatcher.cpp | 105 ++ src/common/config/ConfigWatcher.h | 71 ++ src/common/cpu/BasicCpuInfo.cpp | 131 +++ src/common/cpu/BasicCpuInfo.h | 70 ++ src/common/cpu/BasicCpuInfo_arm.cpp | 47 + src/common/cpu/Cpu.cpp | 57 + src/common/cpu/Cpu.h | 46 + src/common/crypto/Algorithm.cpp | 240 ++++ src/common/crypto/Algorithm.h | 92 ++ src/common/crypto/keccak.cpp | 200 ++++ src/common/crypto/keccak.h | 55 + src/common/interfaces/IClientListener.h | 48 + src/common/interfaces/IConfig.h | 140 +++ src/common/interfaces/IConfigCreator.h | 45 + src/common/interfaces/IConsoleListener.h | 37 + src/common/interfaces/IControllerListener.h | 46 + src/common/interfaces/ICpuInfo.h | 60 + src/common/interfaces/ILogBackend.h | 56 + src/common/interfaces/IStrategy.h | 48 + src/common/interfaces/IStrategyListener.h | 49 + src/common/interfaces/IWatcherListener.h | 46 + src/common/log/BasicLog.cpp | 89 ++ src/common/log/BasicLog.h | 55 + src/common/log/ConsoleLog.cpp | 131 +++ src/common/log/ConsoleLog.h | 59 + src/common/log/FileLog.cpp | 105 ++ src/common/log/FileLog.h | 57 + src/common/log/Log.cpp | 126 ++ src/common/log/Log.h | 101 ++ src/common/log/SysLog.cpp | 47 + src/common/log/SysLog.h | 40 + src/common/net/Client.cpp | 1016 +++++++++++++++++ src/common/net/Client.h | 172 +++ src/common/net/Id.h | 98 ++ src/common/net/Job.cpp | 248 ++++ src/common/net/Job.h | 108 ++ src/common/net/Pool.cpp | 407 +++++++ src/common/net/Pool.h | 116 ++ src/common/net/Storage.h | 95 ++ src/common/net/SubmitResult.cpp | 45 + src/common/net/SubmitResult.h | 49 + src/common/net/Tls.cpp | 190 +++ src/common/net/Tls.h | 62 + .../net/strategies/FailoverStrategy.cpp | 165 +++ src/common/net/strategies/FailoverStrategy.h | 74 ++ .../net/strategies/SinglePoolStrategy.cpp | 110 ++ .../net/strategies/SinglePoolStrategy.h | 64 ++ src/common/utils/c_str.h | 102 ++ src/common/utils/mm_malloc.h | 43 + src/common/utils/timestamp.h | 47 + src/common/xmrig.h | 109 ++ src/config.json | 34 +- src/core/Config.cpp | 235 ++++ src/core/Config.h | 81 ++ src/core/ConfigCreator.h | 50 + src/core/ConfigLoader_platform.h | 197 ++++ src/core/Controller.cpp | 150 +++ src/core/Controller.h | 64 ++ src/crypto/CryptoNight.cpp | 202 ++-- src/crypto/CryptoNight.h | 28 +- src/crypto/CryptoNight_constants.h | 67 +- src/crypto/CryptoNight_monero.h | 111 +- src/crypto/CryptoNight_test.h | 194 +++- src/crypto/CryptoNight_x86.h | 717 +++++++++++- src/crypto/soft_aes.h | 17 + src/donate.h | 4 +- src/interfaces/IThread.h | 77 ++ src/interfaces/IWorker.h | 6 +- src/net/JobResult.h | 24 +- src/net/Network.cpp | 63 +- src/net/Network.h | 13 +- src/net/strategies/DonateStrategy.cpp | 53 +- src/net/strategies/DonateStrategy.h | 17 +- src/nvidia/CudaCLI.cpp | 22 +- src/nvidia/CudaCLI.h | 35 +- src/nvidia/NvmlApi.cpp | 14 +- src/nvidia/NvmlApi.h | 15 +- src/nvidia/NvmlApi_stub.cpp | 7 +- src/nvidia/cryptonight.h | 19 +- src/nvidia/cuda_core.cu | 638 ++++++++--- src/nvidia/cuda_extra.cu | 188 +-- src/nvidia/cuda_extra.h | 2 - src/nvidia/cuda_fast_int_math_v2.hpp | 61 + src/version.h | 17 +- src/workers/CudaThread.cpp | 206 ++++ src/workers/CudaThread.h | 110 ++ src/workers/CudaWorker.cpp | 39 +- src/workers/CudaWorker.h | 16 +- src/workers/Handle.cpp | 16 +- src/workers/Handle.h | 36 +- src/workers/Hashrate.cpp | 87 +- src/workers/Hashrate.h | 24 +- src/workers/Workers.cpp | 165 +-- src/workers/Workers.h | 29 +- 133 files changed, 12393 insertions(+), 1079 deletions(-) create mode 100644 cmake/OpenSSL.cmake create mode 100644 cmake/cpu.cmake create mode 100644 src/3rdparty/aligned_malloc.h create mode 100644 src/api/ApiRouter.cpp create mode 100644 src/api/ApiRouter.h create mode 100644 src/common/Console.cpp create mode 100644 src/common/Console.h create mode 100644 src/common/Platform.cpp create mode 100644 src/common/Platform.h create mode 100644 src/common/Platform_mac.cpp create mode 100644 src/common/Platform_unix.cpp create mode 100644 src/common/Platform_win.cpp create mode 100644 src/common/api/HttpBody.h create mode 100644 src/common/api/HttpReply.h create mode 100644 src/common/api/HttpRequest.cpp create mode 100644 src/common/api/HttpRequest.h create mode 100644 src/common/api/Httpd.cpp create mode 100644 src/common/api/Httpd.h create mode 100644 src/common/config/CommonConfig.cpp create mode 100644 src/common/config/CommonConfig.h create mode 100644 src/common/config/ConfigLoader.cpp create mode 100644 src/common/config/ConfigLoader.h create mode 100644 src/common/config/ConfigWatcher.cpp create mode 100644 src/common/config/ConfigWatcher.h create mode 100644 src/common/cpu/BasicCpuInfo.cpp create mode 100644 src/common/cpu/BasicCpuInfo.h create mode 100644 src/common/cpu/BasicCpuInfo_arm.cpp create mode 100644 src/common/cpu/Cpu.cpp create mode 100644 src/common/cpu/Cpu.h create mode 100644 src/common/crypto/Algorithm.cpp create mode 100644 src/common/crypto/Algorithm.h create mode 100644 src/common/crypto/keccak.cpp create mode 100644 src/common/crypto/keccak.h create mode 100644 src/common/interfaces/IClientListener.h create mode 100644 src/common/interfaces/IConfig.h create mode 100644 src/common/interfaces/IConfigCreator.h create mode 100644 src/common/interfaces/IConsoleListener.h create mode 100644 src/common/interfaces/IControllerListener.h create mode 100644 src/common/interfaces/ICpuInfo.h create mode 100644 src/common/interfaces/ILogBackend.h create mode 100644 src/common/interfaces/IStrategy.h create mode 100644 src/common/interfaces/IStrategyListener.h create mode 100644 src/common/interfaces/IWatcherListener.h create mode 100644 src/common/log/BasicLog.cpp create mode 100644 src/common/log/BasicLog.h create mode 100644 src/common/log/ConsoleLog.cpp create mode 100644 src/common/log/ConsoleLog.h create mode 100644 src/common/log/FileLog.cpp create mode 100644 src/common/log/FileLog.h create mode 100644 src/common/log/Log.cpp create mode 100644 src/common/log/Log.h create mode 100644 src/common/log/SysLog.cpp create mode 100644 src/common/log/SysLog.h create mode 100644 src/common/net/Client.cpp create mode 100644 src/common/net/Client.h create mode 100644 src/common/net/Id.h create mode 100644 src/common/net/Job.cpp create mode 100644 src/common/net/Job.h create mode 100644 src/common/net/Pool.cpp create mode 100644 src/common/net/Pool.h create mode 100644 src/common/net/Storage.h create mode 100644 src/common/net/SubmitResult.cpp create mode 100644 src/common/net/SubmitResult.h create mode 100644 src/common/net/Tls.cpp create mode 100644 src/common/net/Tls.h create mode 100644 src/common/net/strategies/FailoverStrategy.cpp create mode 100644 src/common/net/strategies/FailoverStrategy.h create mode 100644 src/common/net/strategies/SinglePoolStrategy.cpp create mode 100644 src/common/net/strategies/SinglePoolStrategy.h create mode 100644 src/common/utils/c_str.h create mode 100644 src/common/utils/mm_malloc.h create mode 100644 src/common/utils/timestamp.h create mode 100644 src/common/xmrig.h create mode 100644 src/core/Config.cpp create mode 100644 src/core/Config.h create mode 100644 src/core/ConfigCreator.h create mode 100644 src/core/ConfigLoader_platform.h create mode 100644 src/core/Controller.cpp create mode 100644 src/core/Controller.h create mode 100644 src/interfaces/IThread.h create mode 100644 src/nvidia/cuda_fast_int_math_v2.hpp create mode 100644 src/workers/CudaThread.cpp create mode 100644 src/workers/CudaThread.h diff --git a/CHANGELOG.md b/CHANGELOG.md index cec311b5..602fda06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# v2.8.1 +- **[#753](https://github.com/xmrig/xmrig/issues/753) Added new algorithm [CryptoNight variant 2](https://github.com/xmrig/xmrig/issues/753) for Monero fork, thanks [@SChernykh](https://github.com/SChernykh).** +- **[#758](https://github.com/xmrig/xmrig/issues/758) Added SSL/TLS support for secure connections to pools.** + - Added per pool options `"tls"` and `"tls-fingerprint"` and command line equivalents. +- [#245](https://github.com/xmrig/xmrig-proxy/issues/245) Fixed API ID collision when run multiple miners on same machine. +- [#757](https://github.com/xmrig/xmrig/issues/757) Fixed send buffer overflow. +- [#777](https://github.com/xmrig/xmrig/issues/777) Better report about pool connection issues. + +# v2.7.0-beta +- Algorithm variant `cryptonight-lite/ipbc` replaced to `cryptonight-heavy/tube` for **Bittube (TUBE)** coin. +- Added `cryptonight-heavy/xhv` variant for **Haven Protocol (XHV)** coin. +- Added `cryptonight/rto` (cryptonight variant 1 with IPBC/TUBE mod) variant for **Arto (RTO)** coin. +- Added `cryptonight/xao` (original cryptonight with bigger iteration count) variant for **Alloy (XAO)** coin. +- Added `cryptonight/xtl` variant for **Stellite (XTL)** coin. +- Added `cryptonight/msr` also known as `cryptonight-fast` for **Masari (MSR)** coin. +- Added new detailed hashrate report. +- Added command line option `--dry-run`. + # v2.6.1 - Fixed critical bug, in some cases miner was can't recovery connection and switch to failover pool, version 2.5.2 and v2.6.0-beta1 affected. - [#499](https://github.com/xmrig/xmrig/issues/499) IPv6 support disabled for internal HTTP API. diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bbdc8b8..f78d7c15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,96 +1,126 @@ cmake_minimum_required(VERSION 2.8) project(xmrig-nvidia) -option(WITH_AEON "CryptoNight-Lite support" ON) -option(WITH_IPBC "CryptoNight-IPBC support" ON) -option(WITH_HTTPD "HTTP REST API" ON) +option(WITH_AEON "CryptoNight-Lite support" ON) +option(WITH_SUMO "CryptoNight-Heavy support" ON) +option(WITH_HTTPD "HTTP REST API" ON) +option(WITH_DEBUG_LOG "Enable debug log output" OFF) +option(WITH_TLS "Enable OpenSSL support" ON) +option(BUILD_STATIC "Build static binary" OFF) include (CheckIncludeFile) +include (cmake/cpu.cmake) set(HEADERS - src/api/Api.h - src/api/ApiState.h src/api/NetworkState.h src/App.h - src/Console.h - src/Cpu.h - src/interfaces/IClientListener.h - src/interfaces/IConsoleListener.h + src/common/config/CommonConfig.h + src/common/config/ConfigLoader.h + src/common/config/ConfigWatcher.h + src/common/Console.h + src/common/cpu/BasicCpuInfo.h + src/common/cpu/Cpu.h + src/common/crypto/Algorithm.h + src/common/crypto/keccak.h + src/common/interfaces/IClientListener.h + src/common/interfaces/IConfig.h + src/common/interfaces/IConfigCreator.h + src/common/interfaces/IConsoleListener.h + src/common/interfaces/IControllerListener.h + src/common/interfaces/ICpuInfo.h + src/common/interfaces/ILogBackend.h + src/common/interfaces/IStrategy.h + src/common/interfaces/IStrategyListener.h + src/common/interfaces/IWatcherListener.h + src/common/log/BasicLog.h + src/common/log/ConsoleLog.h + src/common/log/FileLog.h + src/common/log/Log.h + src/common/net/Client.h + src/common/net/Id.h + src/common/net/Job.h + src/common/net/Pool.h + src/common/net/Storage.h + src/common/net/strategies/FailoverStrategy.h + src/common/net/strategies/SinglePoolStrategy.h + src/common/net/SubmitResult.h + src/common/Platform.h + src/common/utils/c_str.h + src/common/utils/mm_malloc.h + src/common/utils/timestamp.h + src/common/xmrig.h + src/core/ConfigLoader_platform.h + src/core/Controller.h src/interfaces/IJobResultListener.h - src/interfaces/ILogBackend.h - src/interfaces/IStrategy.h - src/interfaces/IStrategyListener.h + src/interfaces/IThread.h src/interfaces/IWorker.h - src/log/ConsoleLog.h - src/log/FileLog.h - src/log/Log.h - src/net/Client.h - src/net/Id.h - src/net/Job.h src/net/JobResult.h src/net/Network.h src/net/strategies/DonateStrategy.h - src/net/strategies/FailoverStrategy.h - src/net/strategies/SinglePoolStrategy.h - src/net/SubmitResult.h - src/net/Url.h src/nvidia/CudaCLI.h src/nvidia/Health.h src/nvidia/NvmlApi.h - src/Options.h - src/Platform.h src/Summary.h src/version.h src/workers/CudaWorker.h - src/workers/GpuThread.h + src/workers/CudaThread.h src/workers/Handle.h src/workers/Hashrate.h src/workers/Workers.h - src/xmrig.h ) set(HEADERS_CRYPTO src/crypto/c_blake256.h src/crypto/c_groestl.h src/crypto/c_jh.h - src/crypto/c_keccak.h src/crypto/c_skein.h src/crypto/CryptoNight.h src/crypto/CryptoNight_constants.h src/crypto/CryptoNight_monero.h src/crypto/CryptoNight_test.h - src/crypto/CryptoNight_x86.h src/crypto/groestl_tables.h src/crypto/hash.h src/crypto/skein_port.h src/crypto/soft_aes.h ) +if (XMRIG_ARM) + set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/CryptoNight_arm.h) +else() + set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/CryptoNight_x86.h) +endif() + set(SOURCES - src/api/Api.cpp - src/api/ApiState.cpp src/api/NetworkState.cpp src/App.cpp - src/Console.cpp - src/Cpu_stub.cpp - src/log/ConsoleLog.cpp - src/log/FileLog.cpp - src/log/Log.cpp - src/net/Client.cpp - src/net/Job.cpp + src/common/config/CommonConfig.cpp + src/common/config/ConfigLoader.cpp + src/common/config/ConfigWatcher.cpp + src/common/Console.cpp + src/common/cpu/BasicCpuInfo.cpp + src/common/cpu/Cpu.cpp + src/common/crypto/Algorithm.cpp + src/common/crypto/keccak.cpp + src/common/log/BasicLog.cpp + src/common/log/ConsoleLog.cpp + src/common/log/FileLog.cpp + src/common/log/Log.cpp + src/common/net/Client.cpp + src/common/net/Job.cpp + src/common/net/Pool.cpp + src/common/net/strategies/FailoverStrategy.cpp + src/common/net/strategies/SinglePoolStrategy.cpp + src/common/net/SubmitResult.cpp + src/common/Platform.cpp + src/core/Config.cpp + src/core/Controller.cpp src/net/Network.cpp src/net/strategies/DonateStrategy.cpp - src/net/strategies/FailoverStrategy.cpp - src/net/strategies/SinglePoolStrategy.cpp - src/net/SubmitResult.cpp - src/net/Url.cpp src/nvidia/CudaCLI.cpp - src/Options.cpp - src/Platform.cpp src/Summary.cpp src/workers/CudaWorker.cpp - src/workers/GpuThread.cpp + src/workers/CudaThread.cpp src/workers/Handle.cpp src/workers/Hashrate.cpp src/workers/Workers.cpp @@ -98,7 +128,6 @@ set(SOURCES ) set(SOURCES_CRYPTO - src/crypto/c_keccak.c src/crypto/c_groestl.c src/crypto/c_blake256.c src/crypto/c_jh.c @@ -110,8 +139,7 @@ if (WIN32) set(SOURCES_OS res/app.rc src/App_win.cpp - src/Cpu_win.cpp - src/Platform_win.cpp + src/common/Platform_win.cpp ) add_definitions(/DWIN32) @@ -119,25 +147,22 @@ if (WIN32) elseif (APPLE) set(SOURCES_OS src/App_unix.cpp - src/Cpu_mac.cpp - src/Platform_mac.cpp + src/common/Platform_mac.cpp ) else() set(SOURCES_OS src/App_unix.cpp - src/Cpu_unix.cpp - src/Platform_unix.cpp + src/common/Platform_unix.cpp ) - set(EXTRA_LIBS pthread) + set(EXTRA_LIBS pthread rt dl) endif() -add_definitions(/DXMRIG_NVIDIA_PROJECT) +add_definitions(/D__STDC_FORMAT_MACROS) add_definitions(/DUNICODE) +add_definitions(/DXMRIG_NVIDIA_PROJECT) add_definitions(/DXMRIG_NO_LIBCPUID) -add_definitions(/D__STDC_FORMAT_MACROS) -add_definitions(/DRAPIDJSON_SSE2) -#add_definitions(/DAPP_DEBUG) +add_definitions(/DXMRIG_NO_ASM) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -147,8 +172,8 @@ if (NOT WITH_AEON) add_definitions(/DXMRIG_NO_AEON) endif() -if (NOT WITH_IPBC) - add_definitions(/XMRIG_NO_IPBC) +if (NOT WITH_SUMO) + add_definitions(/DXMRIG_NO_SUMO) endif() include_directories(src) @@ -167,10 +192,12 @@ else() set(SOURCES_NVML src/nvidia/NvmlApi_stub.cpp) endif() +include(cmake/OpenSSL.cmake) + CHECK_INCLUDE_FILE (syslog.h HAVE_SYSLOG_H) if (HAVE_SYSLOG_H) add_definitions(/DHAVE_SYSLOG_H) - set(SOURCES_SYSLOG src/log/SysLog.h src/log/SysLog.cpp) + set(SOURCES_SYSLOG src/common/log/SysLog.h src/common/log/SysLog.cpp) endif() if (WITH_HTTPD) @@ -178,19 +205,38 @@ if (WITH_HTTPD) if (MHD_FOUND) include_directories(${MHD_INCLUDE_DIRS}) - set(HTTPD_SOURCES src/api/Httpd.h src/api/Httpd.cpp) + set(HTTPD_SOURCES + src/api/Api.h + src/api/ApiRouter.h + src/common/api/HttpBody.h + src/common/api/Httpd.h + src/common/api/HttpReply.h + src/common/api/HttpRequest.h + src/api/Api.cpp + src/api/ApiRouter.cpp + src/common/api/Httpd.cpp + src/common/api/HttpRequest.cpp + ) else() message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_HTTPD=OFF` to build without http deamon support") endif() else() + set(HTTPD_SOURCES "") + set(MHD_LIBRARY "") add_definitions(/DXMRIG_NO_HTTPD) add_definitions(/DXMRIG_NO_API) - - set(MHD_LIBRARY "") endif() include_directories(src/3rdparty) include_directories(${UV_INCLUDE_DIR}) -add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_NVML} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES}) -target_link_libraries(${PROJECT_NAME} xmrig-cuda ${UV_LIBRARIES} ${MHD_LIBRARY} ${LIBS} ${EXTRA_LIBS} ${CPUID_LIB}) +if (BUILD_STATIC) + set(CMAKE_EXE_LINKER_FLAGS " -static") +endif() + +if (WITH_DEBUG_LOG) + add_definitions(/DAPP_DEBUG) +endif() + +add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_NVML} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${TLS_SOURCES}) +target_link_libraries(${PROJECT_NAME} xmrig-cuda ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${MHD_LIBRARY} ${LIBS} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/README.md b/README.md index 6a33817d..792b13ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # XMRig NVIDIA -:warning: **You must update miners to version 2.5 before April 6 due [Monero PoW change](https://getmonero.org/2018/02/11/PoW-change-and-key-reuse.html).** +:warning: **[Monero will change PoW algorithm on October 18](https://github.com/xmrig/xmrig/issues/753), all miners and proxy should be updated to [v2.8+](https://github.com/xmrig/xmrig-nvidia/releases/tag/v2.8.1)** :warning: [![Github All Releases](https://img.shields.io/github/downloads/xmrig/xmrig-nvidia/total.svg)](https://github.com/xmrig/xmrig-nvidia/releases) [![GitHub release](https://img.shields.io/github/release/xmrig/xmrig-nvidia/all.svg)](https://github.com/xmrig/xmrig-nvidia/releases) @@ -49,32 +49,43 @@ Use [config.xmrig.com](https://config.xmrig.com/nvidia) to generate, edit or sha ### Command line options ``` - -a, --algo=ALGO cryptonight (default) or cryptonight-lite + -a, --algo=ALGO specify the algorithm to use + cryptonight + cryptonight-lite + cryptonight-heavy -o, --url=URL URL of mining server -O, --userpass=U:P username:password pair for mining server -u, --user=USERNAME username for mining server -p, --pass=PASSWORD password for mining server - -k, --keepalive send keepalived for prevent timeout (need pool support) + --rig-id=ID rig identifier for pool-side statistics (needs pool support) + -k, --keepalive send keepalived packet for prevent timeout (needs pool support) + --nicehash enable nicehash.com support + --tls enable SSL/TLS support (needs pool support) + --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning -r, --retries=N number of times to retry before switch to backup server (default: 5) -R, --retry-pause=N time to pause between retries (default: 5) - --cuda-devices=N List of CUDA devices to use. - --cuda-launch=TxB List of launch config for the CryptoNight kernel + --cuda-devices=N list of CUDA devices to use. + --cuda-launch=TxB list of launch config for the CryptoNight kernel --cuda-max-threads=N limit maximum count of GPU threads in automatic mode --cuda-bfactor=[0-12] run CryptoNight core kernel in smaller pieces --cuda-bsleep=N insert a delay of N microseconds between kernel launches --cuda-affinity=N affine GPU threads to a CPU --no-color disable colored output + --variant algorithm PoW variant --donate-level=N donate level, default 5% (5 minutes in 100 minutes) --user-agent set custom user-agent string for pool -B, --background run the miner in the background -c, --config=FILE load a JSON-format configuration file -l, --log-file=FILE log all output to a file -S, --syslog use system log for output messages - --nicehash enable nicehash support --print-time=N print hashrate report every N seconds --api-port=N port for the miner API --api-access-token=T access token for API --api-worker-id=ID custom worker-id for API + --api-id=ID custom instance ID for API + --api-ipv6 enable IPv6 support for API + --api-no-restricted enable full remote access (only if API token set) + --dry-run test configuration and exit -h, --help display this help and exit -V, --version output version information and exit ``` @@ -88,10 +99,11 @@ Default donation 5% (5 minutes in 100 minutes) can be reduced to 1% via command ## Release checksums ### SHA-256 ``` -54ea918c9d08c71d6d1ebdee3da9bcd476ea48992156a0ff6912f7a1e3091bd9 xmrig-nvidia-2.6.1-cuda8-win64.zip/xmrig-nvidia.exe -5905924c61d96267c176bc9af86c16dcc837b81378e47315231a9ee0c5cc48b7 xmrig-nvidia-2.6.1-cuda9-win64.zip/xmrig-nvidia.exe +30accf8b03c8bfd90034e6e49fe733a438dff6b530faf411aab6fe738a06fa8b xmrig-nvidia-2.7.0-beta-cuda8-win64.zip/xmrig-nvidia.exe +ec408bd837141bb8e0e7e6b4f76264255a3986f1e5a858400e6870bfad7e3214 xmrig-nvidia-2.7.0-beta-cuda9-win64.zip/xmrig-nvidia.exe ``` ## Contacts * support@xmrig.com * [reddit](https://www.reddit.com/user/XMRig/) +* [twitter](https://twitter.com/xmrig_dev) diff --git a/cmake/CUDA.cmake b/cmake/CUDA.cmake index 0d5955d9..45642c4f 100644 --- a/cmake/CUDA.cmake +++ b/cmake/CUDA.cmake @@ -119,16 +119,17 @@ endif() set(CUDA_SOURCES src/nvidia/cryptonight.h - src/nvidia/cuda_extra.h src/nvidia/cuda_aes.hpp src/nvidia/cuda_blake.hpp + src/nvidia/cuda_core.cu src/nvidia/cuda_device.hpp + src/nvidia/cuda_extra.cu + src/nvidia/cuda_extra.h + src/nvidia/cuda_fast_int_math_v2.hpp src/nvidia/cuda_groestl.hpp src/nvidia/cuda_jh.hpp src/nvidia/cuda_keccak.hpp src/nvidia/cuda_skein.hpp - src/nvidia/cuda_core.cu - src/nvidia/cuda_extra.cu ) if("${CUDA_COMPILER}" STREQUAL "clang") diff --git a/cmake/FindNVML.cmake b/cmake/FindNVML.cmake index daa2acce..887c50fa 100644 --- a/cmake/FindNVML.cmake +++ b/cmake/FindNVML.cmake @@ -131,6 +131,7 @@ endif() #find_library(NVML_LIBRARY NAMES ${NVML_NAMES} PATHS ${NVML_LIB_PATHS} ) +find_path(NVML_INCLUDE_DIR nvml.h PATHS ${NVML_INC_PATHS} NO_DEFAULT_PATH) find_path(NVML_INCLUDE_DIR nvml.h PATHS ${NVML_INC_PATHS}) # handle the QUIETLY and REQUIRED arguments and set NVML_FOUND to TRUE if diff --git a/cmake/OpenSSL.cmake b/cmake/OpenSSL.cmake new file mode 100644 index 00000000..ed287e7e --- /dev/null +++ b/cmake/OpenSSL.cmake @@ -0,0 +1,23 @@ +if (WITH_TLS) + set(OPENSSL_ROOT_DIR ${XMRIG_DEPS}) + + if (WIN32) + set(OPENSSL_USE_STATIC_LIBS TRUE) + set(OPENSSL_MSVC_STATIC_RT TRUE) + + set(EXTRA_LIBS ${EXTRA_LIBS} Crypt32) + endif() + + find_package(OpenSSL) + + if (OPENSSL_FOUND) + set(TLS_SOURCES src/common/net/Tls.h src/common/net/Tls.cpp) + include_directories(${OPENSSL_INCLUDE_DIR}) + else() + message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support") + endif() +else() + set(TLS_SOURCES "") + set(OPENSSL_LIBRARIES "") + add_definitions(/DXMRIG_NO_TLS) +endif() diff --git a/cmake/cpu.cmake b/cmake/cpu.cmake new file mode 100644 index 00000000..96e61e2b --- /dev/null +++ b/cmake/cpu.cmake @@ -0,0 +1,25 @@ +if (NOT CMAKE_SYSTEM_PROCESSOR) + message(WARNING "CMAKE_SYSTEM_PROCESSOR not defined") +endif() + + +if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$") + add_definitions(/DRAPIDJSON_SSE2) +endif() + + +if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64)$") + set(XMRIG_ARM ON) + set(XMRIG_ARMv8 ON) + set(WITH_LIBCPUID OFF) + + add_definitions(/DXMRIG_ARM) + add_definitions(/DXMRIG_ARMv8) +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7|armv7f|armv7s|armv7k|armv7-a|armv7l)$") + set(XMRIG_ARM ON) + set(XMRIG_ARMv7 ON) + set(WITH_LIBCPUID OFF) + + add_definitions(/DXMRIG_ARM) + add_definitions(/DXMRIG_ARMv7) +endif() diff --git a/res/app.rc b/res/app.rc index aa41334b..68762542 100644 --- a/res/app.rc +++ b/res/app.rc @@ -4,8 +4,8 @@ IDI_ICON1 ICON DISCARDABLE "app.ico" VS_VERSION_INFO VERSIONINFO - FILEVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_BUILD,APP_VER_REV - PRODUCTVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_BUILD,APP_VER_REV + FILEVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_PATCH,0 + PRODUCTVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_PATCH,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG diff --git a/src/3rdparty/aligned_malloc.h b/src/3rdparty/aligned_malloc.h new file mode 100644 index 00000000..0b74b17e --- /dev/null +++ b/src/3rdparty/aligned_malloc.h @@ -0,0 +1,65 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ALIGNED_MALLOC_H__ +#define __ALIGNED_MALLOC_H__ + + +#include + + +#ifndef __cplusplus +extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size); +#else +// Some systems (e.g. those with GNU libc) declare posix_memalign with an +// exception specifier. Via an "egregious workaround" in +// Sema::CheckEquivalentExceptionSpec, Clang accepts the following as a valid +// redeclaration of glibc's declaration. +extern "C" int posix_memalign(void **__memptr, size_t __alignment, size_t __size); +#endif + + +static __inline__ void *__attribute__((__always_inline__, __malloc__)) _mm_malloc(size_t __size, size_t __align) +{ + if (__align == 1) { + return malloc(__size); + } + + if (!(__align & (__align - 1)) && __align < sizeof(void *)) + __align = sizeof(void *); + + void *__mallocedMemory; + if (posix_memalign(&__mallocedMemory, __align, __size)) { + return 0; + } + + return __mallocedMemory; +} + + +static __inline__ void __attribute__((__always_inline__)) _mm_free(void *__p) +{ + free(__p); +} + +#endif /* __ALIGNED_MALLOC_H__ */ diff --git a/src/3rdparty/rapidjson/prettywriter.h b/src/3rdparty/rapidjson/prettywriter.h index 76843cc1..0dcb0fee 100644 --- a/src/3rdparty/rapidjson/prettywriter.h +++ b/src/3rdparty/rapidjson/prettywriter.h @@ -221,9 +221,8 @@ class PrettyWriter : public WritervalueCount % 2 == 0) WriteIndent(); } - if (!level->inArray && level->valueCount % 2 == 0) { + if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - } level->valueCount++; } else { diff --git a/src/3rdparty/rapidjson/writer.h b/src/3rdparty/rapidjson/writer.h index d1b73b25..94f22dd5 100644 --- a/src/3rdparty/rapidjson/writer.h +++ b/src/3rdparty/rapidjson/writer.h @@ -444,9 +444,8 @@ class Writer { else // in object os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } - if (!level->inArray && level->valueCount % 2 == 0) { + if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - } level->valueCount++; } else { diff --git a/src/App.cpp b/src/App.cpp index fdeb801f..519363df 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2018 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,26 +28,20 @@ #include "api/Api.h" #include "App.h" -#include "Console.h" -#include "Cpu.h" +#include "common/Console.h" +#include "common/log/Log.h" +#include "common/Platform.h" +#include "core/Config.h" +#include "core/Controller.h" #include "crypto/CryptoNight.h" -#include "log/ConsoleLog.h" -#include "log/FileLog.h" -#include "log/Log.h" #include "net/Network.h" -#include "Options.h" -#include "Platform.h" #include "Summary.h" #include "version.h" #include "workers/Workers.h" -#ifdef HAVE_SYSLOG_H -# include "log/SysLog.h" -#endif - #ifndef XMRIG_NO_HTTPD -# include "api/Httpd.h" +# include "common/api/Httpd.h" #endif @@ -57,39 +51,19 @@ App *App::m_self = nullptr; App::App(int argc, char **argv) : m_console(nullptr), - m_httpd(nullptr), - m_network(nullptr), - m_options(nullptr) + m_httpd(nullptr) { m_self = this; - Cpu::init(); - m_options = Options::parse(argc, argv); - if (!m_options) { + m_controller = new xmrig::Controller(); + if (m_controller->init(argc, argv) != 0) { return; } - Log::init(); - - if (!m_options->background()) { - Log::add(new ConsoleLog(m_options->colors())); + if (!m_controller->config()->isBackground()) { m_console = new Console(this); } - if (m_options->logFile()) { - Log::add(new FileLog(m_options->logFile())); - } - -# ifdef HAVE_SYSLOG_H - if (m_options->syslog()) { - Log::add(new SysLog()); - } -# endif - - Platform::init(m_options->userAgent()); - - m_network = new Network(m_options); - uv_signal_init(uv_default_loop(), &m_sigHUP); uv_signal_init(uv_default_loop(), &m_sigINT); uv_signal_init(uv_default_loop(), &m_sigTERM); @@ -100,18 +74,19 @@ App::~App() { uv_tty_reset_mode(); + delete m_console; + delete m_controller; + # ifndef XMRIG_NO_HTTPD delete m_httpd; # endif - - delete m_console; } int App::exec() { - if (!m_options) { - return 0; + if (!m_controller->isReady()) { + return 2; } uv_signal_start(&m_sigHUP, App::onSignal, SIGHUP); @@ -120,36 +95,48 @@ int App::exec() background(); - if (!CryptoNight::init(m_options->algorithm())) { - LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName()); + if (!CryptoNight::init(m_controller->config()->algorithm().algo())) { + LOG_ERR("\"%s\" hash self-test failed.", m_controller->config()->algorithm().name()); return 1; } - if (!Summary::print()) { + Summary::print(m_controller); + + if (m_controller->config()->threads().empty()) { + LOG_ERR("No CUDA device found!"); return 1; } + if (m_controller->config()->isDryRun()) { + LOG_NOTICE("OK"); + return 0; + } + # ifndef XMRIG_NO_API - Api::start(); + Api::start(m_controller); # endif # ifndef XMRIG_NO_HTTPD - m_httpd = new Httpd(m_options->apiPort(), m_options->apiToken()); + m_httpd = new Httpd( + m_controller->config()->apiPort(), + m_controller->config()->apiToken(), + m_controller->config()->isApiIPv6(), + m_controller->config()->isApiRestricted() + ); + m_httpd->start(); # endif - Workers::start(m_options->threads()); + if (!Workers::start(m_controller)) { + LOG_ERR("Failed to start threads"); + return 1; + } - m_network->connect(); + m_controller->network()->connect(); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); - delete m_network; - - Options::release(); - Platform::release(); - return r; } @@ -165,7 +152,7 @@ void App::onConsoleCommand(char command) case 'p': case 'P': if (Workers::isEnabled()) { - LOG_INFO(m_options->colors() ? "\x1B[01;33mpaused\x1B[0m, press \x1B[01;35mr\x1B[0m to resume" : "paused, press 'r' to resume"); + LOG_INFO(m_controller->config()->isColors() ? "\x1B[01;33mpaused\x1B[0m, press \x1B[01;35mr\x1B[0m to resume" : "paused, press 'r' to resume"); Workers::setEnabled(false); } break; @@ -173,7 +160,7 @@ void App::onConsoleCommand(char command) case 'r': case 'R': if (!Workers::isEnabled()) { - LOG_INFO(m_options->colors() ? "\x1B[01;32mresumed" : "resumed"); + LOG_INFO(m_controller->config()->isColors() ? "\x1B[01;32mresumed" : "resumed"); Workers::setEnabled(true); } break; @@ -196,7 +183,7 @@ void App::onConsoleCommand(char command) void App::close() { - m_network->stop(); + m_controller->network()->stop(); Workers::stop(); uv_stop(uv_default_loop()); diff --git a/src/App.h b/src/App.h index d6fe3037..10042baa 100644 --- a/src/App.h +++ b/src/App.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2018 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include -#include "interfaces/IConsoleListener.h" +#include "common/interfaces/IConsoleListener.h" class Console; @@ -37,6 +37,11 @@ class Network; class Options; +namespace xmrig { + class Controller; +} + + class App : public IConsoleListener { public: @@ -58,11 +63,10 @@ class App : public IConsoleListener Console *m_console; Httpd *m_httpd; - Network *m_network; - Options *m_options; uv_signal_t m_sigHUP; uv_signal_t m_sigINT; uv_signal_t m_sigTERM; + xmrig::Controller *m_controller; }; diff --git a/src/App_unix.cpp b/src/App_unix.cpp index 5c8c3f68..45f73d2d 100644 --- a/src/App_unix.cpp +++ b/src/App_unix.cpp @@ -29,16 +29,16 @@ #include "App.h" -#include "Cpu.h" -#include "log/Log.h" -#include "Options.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" void App::background() { signal(SIGPIPE, SIG_IGN); - if (!m_options->background()) { + if (!m_controller->config()->isBackground()) { return; } diff --git a/src/App_win.cpp b/src/App_win.cpp index 6b2716f0..9b923870 100644 --- a/src/App_win.cpp +++ b/src/App_win.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,13 +27,13 @@ #include "App.h" -#include "Options.h" -#include "Cpu.h" +#include "core/Controller.h" +#include "core/Config.h" void App::background() { - if (!m_options->background()) { + if (!m_controller->config()->isBackground()) { return; } diff --git a/src/Summary.cpp b/src/Summary.cpp index e2e2fe6e..5e4e3830 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,170 +23,105 @@ #include +#include #include -#include "Cpu.h" -#include "log/Log.h" -#include "net/Url.h" -#include "nvidia/cryptonight.h" -#include "Options.h" +#include "common/cpu/Cpu.h" +#include "common/log/Log.h" +#include "common/net/Pool.h" +#include "core/Config.h" +#include "core/Controller.h" #include "Summary.h" #include "version.h" -#include "workers/GpuThread.h" - - -static void print_versions() -{ - char buf[16]; - -# if defined(__clang__) - snprintf(buf, 16, " clang/%d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__); -# elif defined(__GNUC__) - snprintf(buf, 16, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); -# elif defined(_MSC_VER) - snprintf(buf, 16, " MSVC/%d", MSVC_VERSION); -# else - buf[0] = '\0'; -# endif - - const int cudaVersion = cuda_get_runtime_version(); - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s CUDA/%d.%d%s" : " * VERSIONS: XMRig/%s libuv/%s CUDA/%d.%d%s", - APP_VERSION, uv_version_string(), cudaVersion / 1000, cudaVersion % 100, buf); -} +#include "workers/CudaThread.h" -static void print_cpu() +static void print_cpu(xmrig::Config *config) { - if (Options::i()->colors()) { - Log::i()->text("\x1B[01;32m * \x1B[01;37mCPU: %s %sx64 %sAES-NI", - Cpu::brand(), - Cpu::isX64() ? "\x1B[01;32m" : "\x1B[01;31m-", - Cpu::hasAES() ? "\x1B[01;32m" : "\x1B[01;31m-"); + if (config->isColors()) { + Log::i()->text(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s %sx64 %sAES"), + "CPU", + xmrig::Cpu::info()->brand(), + xmrig::Cpu::info()->isX64() ? "\x1B[1;32m" : "\x1B[1;31m-", + xmrig::Cpu::info()->hasAES() ? "\x1B[1;32m" : "\x1B[1;31m-"); } else { - Log::i()->text(" * CPU: %s (%d) %sx64 %sAES-NI", Cpu::brand(), Cpu::sockets(), Cpu::isX64() ? "" : "-", Cpu::hasAES() ? "" : "-"); + Log::i()->text(" * %-13s%s %sx64 %sAES", "CPU", xmrig::Cpu::info()->brand(), xmrig::Cpu::info()->isX64() ? "" : "-", xmrig::Cpu::info()->hasAES() ? "" : "-"); } } -static void print_algo() +static void print_algo(xmrig::Config *config) { - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mALGO: %s, %sdonate=%.1f%%" : " * ALGO: %s, %sdonate=%.1f%%", - Options::i()->algoName(), - Options::i()->colors() && Options::i()->donateLevel() == 0 ? "\x1B[01;31m" : "", - Options::i()->donateLevel() + Log::i()->text(config->isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s, %sdonate=%d%%") + : " * %-13s%s, %sdonate=%d%%", + "ALGO", + config->algorithm().name(), + config->isColors() && config->donateLevel() == 0 ? "\x1B[1;31m" : "", + config->donateLevel() ); } -static void print_pools() +static void print_gpu(xmrig::Config *config) { - const std::vector &pools = Options::i()->pools(); - - for (size_t i = 0; i < pools.size(); ++i) { - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s:%d" : " * POOL #%d: %s:%d", - i + 1, - pools[i]->host(), - pools[i]->port()); - } - -# ifdef APP_DEBUG - for (size_t i = 0; i < pools.size(); ++i) { - Log::i()->text("%s:%d, user: %s, pass: %s, ka: %d, nicehash: %d", pools[i]->host(), pools[i]->port(), pools[i]->user(), pools[i]->password(), pools[i]->isKeepAlive(), pools[i]->isNicehash()); - } -# endif -} - - -static void print_gpu() -{ - for (const GpuThread *thread : Options::i()->threads()) { - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mGPU #%d: \x1B[22;32m%s @ %d/%d MHz \x1B[01;30m%dx%d %dx%d arch:%d%d SMX:%d" : " * GPU #%d: %s @ %d/%d MHz %dx%d %dx%d arch:%d%d SMX:%d", - thread->index(), - thread->name(), - thread->clockRate() / 1000, - thread->memoryClockRate() / 1000, - thread->threads(), - thread->blocks(), - thread->bfactor(), - thread->bsleep(), - thread->arch()[0], - thread->arch()[1], - thread->smx() + for (const xmrig::IThread *t : config->threads()) { + auto thread = static_cast(t); + Log::i()->text(config->isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("GPU #%-8zu") YELLOW("PCI:%04x:%02x:%02x") GREEN(" %s @ %d/%d MHz") " \x1B[1;30m%dx%d %dx%d arch:%d%d SMX:%d" + : " * GPU #%-8zuPCI:%04x:%02x:%02x %s @ %d/%d MHz %dx%d %dx%d arch:%d%d SMX:%d", + thread->index(), + thread->pciDomainID(), + thread->pciBusID(), + thread->pciDeviceID(), + thread->name(), + thread->clockRate() / 1000, + thread->memoryClockRate() / 1000, + thread->threads(), + thread->blocks(), + thread->bfactor(), + thread->bsleep(), + thread->arch()[0], + thread->arch()[1], + thread->smx() ); } } -#ifndef XMRIG_NO_API -static void print_api() +static void print_commands(xmrig::Config *config) { - if (Options::i()->apiPort() == 0) { - return; - } - - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mAPI PORT: \x1B[01;36m%d" : " * API PORT: %d", Options::i()->apiPort()); -} -#endif - - -static void print_commands() -{ - if (Options::i()->colors()) { - Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mh\x1B[01;37mashrate, \x1B[01;35mp\x1B[01;37mause, \x1B[01;35mr\x1B[01;37mesume"); + if (config->isColors()) { + Log::i()->text(GREEN_BOLD(" * ") WHITE_BOLD("COMMANDS ") MAGENTA_BOLD("h") WHITE_BOLD("ashrate, ") + MAGENTA_BOLD("p") WHITE_BOLD("ause, ") + MAGENTA_BOLD("r") WHITE_BOLD("esume")); Log::i()->text("-----------------------------Compiled by Indeed Miners-----------------------------"); Log::i()->text("88 88b 88 8888b. 888888 888888 8888b. 8b d8 88 88b 88 888888 88''Yb .dP'Y8"); Log::i()->text("88 88Yb88 8I Yb 88__ 88__ 8I Yb 88b d88 88 88Yb88 88__ 88__dP `Ybo.'"); Log::i()->text("88 88 Y88 8I dY 88'' 88'' 8I dY 88YbdP88 88 88 Y88 88'' 88'Yb o.`Y8b"); - Log::i()->text("88 88 Y8 8888Y' 888888 888888 8888Y' 88 YY 88 88 88 Y8 888888 88 Yb 8bodP'"); + Log::i()->text("88 88 Y8 8888Y' 888888 888888 8888Y' 88 YY 88 88 88 Y8 888888 88 Yb 8bodP'"); } else { - Log::i()->text(" * COMMANDS: 'h' hashrate, 'p' pause, 'r' resume"); + Log::i()->text(" * COMMANDS 'h' hashrate, 'p' pause, 'r' resume"); Log::i()->text("-----------------------------Compiled by Indeed Miners-----------------------------"); Log::i()->text("88 88b 88 8888b. 888888 888888 8888b. 8b d8 88 88b 88 888888 88''Yb .dP'Y8"); Log::i()->text("88 88Yb88 8I Yb 88__ 88__ 8I Yb 88b d88 88 88Yb88 88__ 88__dP `Ybo.'"); Log::i()->text("88 88 Y88 8I dY 88'' 88'' 8I dY 88YbdP88 88 88 Y88 88'' 88'Yb o.`Y8b"); - Log::i()->text("88 88 Y8 8888Y' 888888 888888 8888Y' 88 YY 88 88 88 Y8 888888 88 Yb 8bodP'"); - } -} - - -static bool print_extra() -{ - const std::vector &threads = Options::i()->threads(); - if (threads.empty()) { - LOG_ERR("No CUDA device found!"); - return false; - } - - if (!Options::i()->isAutoConf()) { - return true; + Log::i()->text("88 88 Y8 8888Y' 888888 888888 8888Y' 88 YY 88 88 88 Y8 888888 88 Yb 8bodP'"); } - - if (Options::i()->save()) { - Log::i()->text("Initial configuration saved to: %s", Options::i()->configName()); - } - - return true; } -bool Summary::print() +void Summary::print(xmrig::Controller *controller) { - print_versions(); - print_cpu(); - print_gpu(); - print_algo(); - print_pools(); - -# ifndef XMRIG_NO_API - print_api(); -# endif - - print_commands(); - - return print_extra(); + controller->config()->printVersions(); + print_cpu(controller->config()); + print_gpu(controller->config()); + print_algo(controller->config()); + controller->config()->printPools(); + controller->config()->printAPI(); + + print_commands(controller->config()); } diff --git a/src/Summary.h b/src/Summary.h index ab4e12ac..eedb5dd0 100644 --- a/src/Summary.h +++ b/src/Summary.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,15 +21,20 @@ * along with this program. If not, see . */ -#ifndef __SUMMARY_H__ -#define __SUMMARY_H__ +#ifndef XMRIG_SUMMARY_H +#define XMRIG_SUMMARY_H + + +namespace xmrig { + class Controller; +} class Summary { public: - static bool print(); + static void print(xmrig::Controller *controller); }; -#endif /* __SUMMARY_H__ */ +#endif /* XMRIG_SUMMARY_H */ diff --git a/src/api/Api.cpp b/src/api/Api.cpp index b6927d0a..3fff45b5 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,17 +25,17 @@ #include "api/Api.h" -#include "api/ApiState.h" +#include "api/ApiRouter.h" +#include "common/api/HttpReply.h" +#include "common/api/HttpRequest.h" -ApiState *Api::m_state = nullptr; -uv_mutex_t Api::m_mutex; +ApiRouter *Api::m_router = nullptr; -bool Api::start() +bool Api::start(xmrig::Controller *controller) { - uv_mutex_init(&m_mutex); - m_state = new ApiState(); + m_router = new ApiRouter(controller); return true; } @@ -43,55 +43,30 @@ bool Api::start() void Api::release() { - delete m_state; + delete m_router; } -char *Api::get(const char *url, int *status) +void Api::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) { - if (!m_state) { - return nullptr; - } - - uv_mutex_lock(&m_mutex); - char *buf = m_state->get(url, status); - uv_mutex_unlock(&m_mutex); - - return buf; -} - - -void Api::setHealth(const std::vector &health) -{ - if (!m_state) { + if (!m_router) { + reply.status = 500; return; } - uv_mutex_lock(&m_mutex); - m_state->setHealth(health); - uv_mutex_unlock(&m_mutex); -} - - -void Api::tick(const Hashrate *hashrate) -{ - if (!m_state) { - return; + if (req.method() == xmrig::HttpRequest::Get) { + return m_router->get(req, reply); } - uv_mutex_lock(&m_mutex); - m_state->tick(hashrate); - uv_mutex_unlock(&m_mutex); + m_router->exec(req, reply); } void Api::tick(const NetworkState &network) { - if (!m_state) { + if (!m_router) { return; } - uv_mutex_lock(&m_mutex); - m_state->tick(network); - uv_mutex_unlock(&m_mutex); + m_router->tick(network); } diff --git a/src/api/Api.h b/src/api/Api.h index e873f4ed..316bb0fa 100644 --- a/src/api/Api.h +++ b/src/api/Api.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,32 +25,32 @@ #define __API_H__ -#include #include -#include "nvidia/Health.h" - - -class ApiState; +class ApiRouter; class Hashrate; class NetworkState; +namespace xmrig { + class Controller; + class HttpReply; + class HttpRequest; +} + + class Api { public: - static bool start(); + static bool start(xmrig::Controller *controller); static void release(); - static char *get(const char *url, int *status); - static void setHealth(const std::vector &health); - static void tick(const Hashrate *hashrate); + static void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply); static void tick(const NetworkState &results); private: - static ApiState *m_state; - static uv_mutex_t m_mutex; + static ApiRouter *m_router; }; #endif /* __API_H__ */ diff --git a/src/api/ApiRouter.cpp b/src/api/ApiRouter.cpp new file mode 100644 index 00000000..94696f2b --- /dev/null +++ b/src/api/ApiRouter.cpp @@ -0,0 +1,362 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#if _WIN32 +# include "WinSock2.h" +#else +# include "unistd.h" +#endif + + +#include "api/ApiRouter.h" +#include "common/api/HttpReply.h" +#include "common/api/HttpRequest.h" +#include "common/cpu/Cpu.h" +#include "common/crypto/keccak.h" +#include "common/net/Job.h" +#include "common/Platform.h" +#include "core/Config.h" +#include "core/Controller.h" +#include "interfaces/IThread.h" +#include "nvidia/NvmlApi.h" +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" +#include "version.h" +#include "workers/CudaThread.h" +#include "workers/Hashrate.h" +#include "workers/Workers.h" + + +static inline double normalize(double d) +{ + if (!isnormal(d)) { + return 0.0; + } + + return floor(d * 100.0) / 100.0; +} + + +ApiRouter::ApiRouter(xmrig::Controller *controller) : + m_controller(controller) +{ + memset(m_workerId, 0, sizeof(m_workerId)); + + setWorkerId(controller->config()->apiWorkerId()); + genId(controller->config()->apiId()); +} + + +void ApiRouter::ApiRouter::get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const +{ + rapidjson::Document doc; + + if (req.match("/1/config")) { + if (req.isRestricted()) { + reply.status = 403; + return; + } + + m_controller->config()->getJSON(doc); + + return finalize(reply, doc); + } + + if (req.match("/1/threads")) { + getThreads(doc); + + return finalize(reply, doc); + } + + doc.SetObject(); + + getIdentify(doc); + getMiner(doc); + getHashrate(doc); + getHealth(doc); + getResults(doc); + getConnection(doc); + + return finalize(reply, doc); +} + + +void ApiRouter::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) +{ + if (req.method() == xmrig::HttpRequest::Put && req.match("/1/config")) { + m_controller->config()->reload(req.body()); + return; + } + + reply.status = 404; +} + + +void ApiRouter::tick(const NetworkState &network) +{ + m_network = network; +} + + +void ApiRouter::onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) +{ + updateWorkerId(config->apiWorkerId(), previousConfig->apiWorkerId()); +} + + +void ApiRouter::finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const +{ + rapidjson::StringBuffer buffer(nullptr, 4096); + rapidjson::PrettyWriter writer(buffer); + writer.SetMaxDecimalPlaces(10); + doc.Accept(writer); + + reply.status = 200; + reply.buf = strdup(buffer.GetString()); + reply.size = buffer.GetSize(); +} + + +void ApiRouter::genId(const char *id) +{ + memset(m_id, 0, sizeof(m_id)); + + if (id && strlen(id) > 0) { + strncpy(m_id, id, sizeof(m_id) - 1); + return; + } + + uv_interface_address_t *interfaces; + int count = 0; + + if (uv_interface_addresses(&interfaces, &count) < 0) { + return; + } + + for (int i = 0; i < count; i++) { + if (!interfaces[i].is_internal && interfaces[i].address.address4.sin_family == AF_INET) { + uint8_t hash[200]; + const size_t addrSize = sizeof(interfaces[i].phys_addr); + const size_t inSize = strlen(APP_KIND) + addrSize + sizeof(uint16_t); + const uint16_t port = static_cast(m_controller->config()->apiPort()); + + uint8_t *input = new uint8_t[inSize](); + memcpy(input, &port, sizeof(uint16_t)); + memcpy(input + sizeof(uint16_t), interfaces[i].phys_addr, addrSize); + memcpy(input + sizeof(uint16_t) + addrSize, APP_KIND, strlen(APP_KIND)); + + xmrig::keccak(input, inSize, hash); + Job::toHex(hash, 8, m_id); + + delete[] input; + break; + } + } + + uv_free_interface_addresses(interfaces, count); +} + + +void ApiRouter::getConnection(rapidjson::Document &doc) const +{ + auto &allocator = doc.GetAllocator(); + + rapidjson::Value connection(rapidjson::kObjectType); + connection.AddMember("pool", rapidjson::StringRef(m_network.pool), allocator); + connection.AddMember("uptime", m_network.connectionTime(), allocator); + connection.AddMember("ping", m_network.latency(), allocator); + connection.AddMember("failures", m_network.failures, allocator); + connection.AddMember("error_log", rapidjson::Value(rapidjson::kArrayType), allocator); + + doc.AddMember("connection", connection, allocator); +} + + +void ApiRouter::getHashrate(rapidjson::Document &doc) const +{ + auto &allocator = doc.GetAllocator(); + + rapidjson::Value hashrate(rapidjson::kObjectType); + rapidjson::Value total(rapidjson::kArrayType); + rapidjson::Value threads(rapidjson::kArrayType); + + const Hashrate *hr = Workers::hashrate(); + + total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); + total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); + total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); + + for (size_t i = 0; i < Workers::threads(); i++) { + rapidjson::Value thread(rapidjson::kArrayType); + thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + threads.PushBack(thread, allocator); + } + + hashrate.AddMember("total", total, allocator); + hashrate.AddMember("highest", normalize(hr->highest()), allocator); + hashrate.AddMember("threads", threads, allocator); + doc.AddMember("hashrate", hashrate, allocator); +} + + +void ApiRouter::getHealth(rapidjson::Document &doc) const +{ + auto &allocator = doc.GetAllocator(); + rapidjson::Value array(rapidjson::kArrayType); + std::vector records; + Health health; + + size_t i = 0; + for (const xmrig::IThread *t : m_controller->config()->threads()) { + auto thread = static_cast(t); + NvmlApi::health(thread->nvmlId(), health); + records.push_back(health); + + rapidjson::Value record(rapidjson::kObjectType); + + record.AddMember("name", rapidjson::StringRef(thread->name()), allocator); + record.AddMember("clock", records[i].clock, allocator); + record.AddMember("mem_clock", records[i].memClock, allocator); + record.AddMember("power", records[i].power / 1000, allocator); + record.AddMember("temp", records[i].temperature, allocator); + record.AddMember("fan", records[i].fanSpeed, allocator); + + array.PushBack(record, allocator); + i++; + } + + doc.AddMember("health", array, allocator); +} + + +void ApiRouter::getIdentify(rapidjson::Document &doc) const +{ + doc.AddMember("id", rapidjson::StringRef(m_id), doc.GetAllocator()); + doc.AddMember("worker_id", rapidjson::StringRef(m_workerId), doc.GetAllocator()); +} + + +void ApiRouter::getMiner(rapidjson::Document &doc) const +{ + auto &allocator = doc.GetAllocator(); + + rapidjson::Value cpu(rapidjson::kObjectType); + cpu.AddMember("brand", rapidjson::StringRef(xmrig::Cpu::info()->brand()), allocator); + cpu.AddMember("aes", xmrig::Cpu::info()->hasAES(), allocator); + cpu.AddMember("x64", xmrig::Cpu::info()->isX64(), allocator); + cpu.AddMember("sockets", xmrig::Cpu::info()->sockets(), allocator); + + doc.AddMember("version", APP_VERSION, allocator); + doc.AddMember("kind", APP_KIND, allocator); + doc.AddMember("ua", rapidjson::StringRef(Platform::userAgent()), allocator); + doc.AddMember("cpu", cpu, allocator); + doc.AddMember("algo", rapidjson::StringRef(m_controller->config()->algorithm().name()), allocator); + doc.AddMember("hugepages", Workers::hugePages() > 0, allocator); + doc.AddMember("donate_level", m_controller->config()->donateLevel(), allocator); +} + + +void ApiRouter::getResults(rapidjson::Document &doc) const +{ + auto &allocator = doc.GetAllocator(); + + rapidjson::Value results(rapidjson::kObjectType); + + results.AddMember("diff_current", m_network.diff, allocator); + results.AddMember("shares_good", m_network.accepted, allocator); + results.AddMember("shares_total", m_network.accepted + m_network.rejected, allocator); + results.AddMember("avg_time", m_network.avgTime(), allocator); + results.AddMember("hashes_total", m_network.total, allocator); + + rapidjson::Value best(rapidjson::kArrayType); + for (size_t i = 0; i < m_network.topDiff.size(); ++i) { + best.PushBack(m_network.topDiff[i], allocator); + } + + results.AddMember("best", best, allocator); + results.AddMember("error_log", rapidjson::Value(rapidjson::kArrayType), allocator); + + doc.AddMember("results", results, allocator); +} + + +void ApiRouter::getThreads(rapidjson::Document &doc) const +{ + doc.SetObject(); + auto &allocator = doc.GetAllocator(); + const Hashrate *hr = Workers::hashrate(); + + Workers::threadsSummary(doc); + + const std::vector &threads = m_controller->config()->threads(); + rapidjson::Value list(rapidjson::kArrayType); + + for (const xmrig::IThread *thread : threads) { + rapidjson::Value value = thread->toAPI(doc); + + rapidjson::Value hashrate(rapidjson::kArrayType); + hashrate.PushBack(normalize(hr->calc(thread->index(), Hashrate::ShortInterval)), allocator); + hashrate.PushBack(normalize(hr->calc(thread->index(), Hashrate::MediumInterval)), allocator); + hashrate.PushBack(normalize(hr->calc(thread->index(), Hashrate::LargeInterval)), allocator); + + value.AddMember("hashrate", hashrate, allocator); + list.PushBack(value, allocator); + } + + doc.AddMember("threads", list, allocator); +} + + +void ApiRouter::setWorkerId(const char *id) +{ + memset(m_workerId, 0, sizeof(m_workerId)); + + if (id && strlen(id) > 0) { + strncpy(m_workerId, id, sizeof(m_workerId) - 1); + } + else { + gethostname(m_workerId, sizeof(m_workerId) - 1); + } +} + + +void ApiRouter::updateWorkerId(const char *id, const char *previousId) +{ + if (id == previousId) { + return; + } + + if (id != nullptr && previousId != nullptr && strcmp(id, previousId) == 0) { + return; + } + + setWorkerId(id); +} diff --git a/src/api/ApiRouter.h b/src/api/ApiRouter.h new file mode 100644 index 00000000..7d1f4568 --- /dev/null +++ b/src/api/ApiRouter.h @@ -0,0 +1,75 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_APIROUTER_H +#define XMRIG_APIROUTER_H + + +#include "api/NetworkState.h" +#include "common/interfaces/IControllerListener.h" +#include "rapidjson/fwd.h" + + +class Hashrate; + + +namespace xmrig { + class Controller; + class HttpReply; + class HttpRequest; +} + + +class ApiRouter : public xmrig::IControllerListener +{ +public: + ApiRouter(xmrig::Controller *controller); + + void get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const; + void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply); + + void tick(const NetworkState &results); + +protected: + void onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) override; + +private: + void finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const; + void genId(const char *id); + void getConnection(rapidjson::Document &doc) const; + void getHashrate(rapidjson::Document &doc) const; + void getHealth(rapidjson::Document &doc) const; + void getIdentify(rapidjson::Document &doc) const; + void getMiner(rapidjson::Document &doc) const; + void getResults(rapidjson::Document &doc) const; + void getThreads(rapidjson::Document &doc) const; + void setWorkerId(const char *id); + void updateWorkerId(const char *id, const char *previousId); + + char m_id[32]; + char m_workerId[128]; + NetworkState m_network; + xmrig::Controller *m_controller; +}; + +#endif /* XMRIG_APIROUTER_H */ diff --git a/src/api/NetworkState.cpp b/src/api/NetworkState.cpp index d3ffddd3..0ab80093 100644 --- a/src/api/NetworkState.cpp +++ b/src/api/NetworkState.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ #include "api/NetworkState.h" -#include "net/SubmitResult.h" +#include "common/net/SubmitResult.h" NetworkState::NetworkState() : diff --git a/src/common/Console.cpp b/src/common/Console.cpp new file mode 100644 index 00000000..350fb139 --- /dev/null +++ b/src/common/Console.cpp @@ -0,0 +1,61 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "common/Console.h" +#include "interfaces/IConsoleListener.h" + + +Console::Console(IConsoleListener *listener) + : m_listener(listener) +{ + m_tty.data = this; + uv_tty_init(uv_default_loop(), &m_tty, 0, 1); + + if (!uv_is_readable(reinterpret_cast(&m_tty))) { + return; + } + + uv_tty_set_mode(&m_tty, UV_TTY_MODE_RAW); + uv_read_start(reinterpret_cast(&m_tty), Console::onAllocBuffer, Console::onRead); +} + + +void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) +{ + auto console = static_cast(handle->data); + buf->len = 1; + buf->base = console->m_buf; +} + + +void Console::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) +{ + if (nread < 0) { + return uv_close(reinterpret_cast(stream), nullptr); + } + + if (nread == 1) { + static_cast(stream->data)->m_listener->onConsoleCommand(buf->base[0]); + } +} diff --git a/src/common/Console.h b/src/common/Console.h new file mode 100644 index 00000000..7f2e3cc9 --- /dev/null +++ b/src/common/Console.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONSOLE_H__ +#define __CONSOLE_H__ + + +#include + + +class IConsoleListener; + + +class Console +{ +public: + Console(IConsoleListener *listener); + +private: + static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); + static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); + + char m_buf[1]; + IConsoleListener *m_listener; + uv_tty_t m_tty; +}; + + +#endif /* __CONSOLE_H__ */ diff --git a/src/common/Platform.cpp b/src/common/Platform.cpp new file mode 100644 index 00000000..a95f78e7 --- /dev/null +++ b/src/common/Platform.cpp @@ -0,0 +1,89 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#ifndef XMRIG_NO_TLS +# include +# include +#endif + + +#include "Platform.h" + + +char Platform::m_defaultConfigName[520] = { 0 }; +xmrig::c_str Platform::m_userAgent; + + +const char *Platform::defaultConfigName() +{ + size_t size = 520; + + if (*m_defaultConfigName) { + return m_defaultConfigName; + } + + if (uv_exepath(m_defaultConfigName, &size) < 0) { + return nullptr; + } + + if (size < 500) { +# ifdef WIN32 + char *p = strrchr(m_defaultConfigName, '\\'); +# else + char *p = strrchr(m_defaultConfigName, '/'); +# endif + + if (p) { + strcpy(p + 1, "config.json"); + return m_defaultConfigName; + } + } + + *m_defaultConfigName = '\0'; + return nullptr; +} + + +void Platform::init(const char *userAgent) +{ +# ifndef XMRIG_NO_TLS + SSL_library_init(); + SSL_load_error_strings(); + ERR_load_BIO_strings(); + ERR_load_crypto_strings(); + SSL_load_error_strings(); + OpenSSL_add_all_digests(); +# endif + + if (userAgent) { + m_userAgent = userAgent; + } + else { + m_userAgent = createUserAgent(); + } +} diff --git a/src/common/Platform.h b/src/common/Platform.h new file mode 100644 index 00000000..5dfb9ff7 --- /dev/null +++ b/src/common/Platform.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_PLATFORM_H +#define XMRIG_PLATFORM_H + + +#include + + +#include "common/utils/c_str.h" + + +class Platform +{ +public: + static bool setThreadAffinity(uint64_t cpu_id); + static const char *defaultConfigName(); + static void init(const char *userAgent); + static void setProcessPriority(int priority); + static void setThreadPriority(int priority); + + static inline const char *userAgent() { return m_userAgent.data(); } + +private: + static char *createUserAgent(); + + static char m_defaultConfigName[520]; + static xmrig::c_str m_userAgent; +}; + + +#endif /* XMRIG_PLATFORM_H */ diff --git a/src/common/Platform_mac.cpp b/src/common/Platform_mac.cpp new file mode 100644 index 00000000..d0c533b0 --- /dev/null +++ b/src/common/Platform_mac.cpp @@ -0,0 +1,109 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include + + +#include "Platform.h" +#include "version.h" + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +char *Platform::createUserAgent() +{ + const size_t max = 160; + + char *buf = new char[max]; + +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s CUDA/%d.%d clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), cudaVersion / 1000, cudaVersion % 100, __clang_major__, __clang_minor__, __clang_patchlevel__); +# else + snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__); +# endif + + return buf; +} + + +bool Platform::setThreadAffinity(uint64_t cpu_id) +{ + thread_port_t mach_thread; + thread_affinity_policy_data_t policy = { static_cast(cpu_id) }; + mach_thread = pthread_mach_thread_np(pthread_self()); + + return thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1) == KERN_SUCCESS; +} + + +void Platform::setProcessPriority(int priority) +{ + +} + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = 19; + switch (priority) + { + case 1: + prio = 5; + break; + + case 2: + prio = 0; + break; + + case 3: + prio = -5; + break; + + case 4: + prio = -10; + break; + + case 5: + prio = -15; + break; + + default: + break; + } + + setpriority(PRIO_PROCESS, 0, prio); +} + diff --git a/src/common/Platform_unix.cpp b/src/common/Platform_unix.cpp new file mode 100644 index 00000000..058920ec --- /dev/null +++ b/src/common/Platform_unix.cpp @@ -0,0 +1,145 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef __FreeBSD__ +# include +# include +# include +# include +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "Platform.h" +#include "version.h" + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +#ifdef __FreeBSD__ +typedef cpuset_t cpu_set_t; +#endif + + +char *Platform::createUserAgent() +{ + const size_t max = 160; + + char *buf = new char[max]; + int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION); + +# if defined(__x86_64__) + length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string()); +# else + length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string()); +# endif + +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100); +# endif + +# ifdef __GNUC__ + length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# endif + + return buf; +} + + +bool Platform::setThreadAffinity(uint64_t cpu_id) +{ + cpu_set_t mn; + CPU_ZERO(&mn); + CPU_SET(cpu_id, &mn); + +# ifndef __ANDROID__ + return pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mn) == 0; +# else + return sched_setaffinity(gettid(), sizeof(cpu_set_t), &mn) == 0; +# endif +} + + +void Platform::setProcessPriority(int priority) +{ +} + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = 19; + switch (priority) + { + case 1: + prio = 5; + break; + + case 2: + prio = 0; + break; + + case 3: + prio = -5; + break; + + case 4: + prio = -10; + break; + + case 5: + prio = -15; + break; + + default: + break; + } + + setpriority(PRIO_PROCESS, 0, prio); + +# ifdef SCHED_IDLE + if (priority == 0) { + sched_param param; + param.sched_priority = 0; + + if (sched_setscheduler(0, SCHED_IDLE, ¶m) != 0) { + sched_setscheduler(0, SCHED_BATCH, ¶m); + } + } +# endif +} diff --git a/src/common/Platform_win.cpp b/src/common/Platform_win.cpp new file mode 100644 index 00000000..32b850d1 --- /dev/null +++ b/src/common/Platform_win.cpp @@ -0,0 +1,168 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include + + +#include "log/Log.h" +#include "Platform.h" +#include "version.h" + + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +static inline OSVERSIONINFOEX winOsVersion() +{ + typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO); + OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0}; + + HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + if (ntdll ) { + RtlGetVersionFunction pRtlGetVersion = reinterpret_cast(GetProcAddress(ntdll, "RtlGetVersion")); + + if (pRtlGetVersion) { + pRtlGetVersion((LPOSVERSIONINFO) &result); + } + } + + return result; +} + + +char *Platform::createUserAgent() +{ + const auto osver = winOsVersion(); + const size_t max = 160; + + char *buf = new char[max]; + int length = snprintf(buf, max, "%s/%s (Windows NT %lu.%lu", APP_NAME, APP_VERSION, osver.dwMajorVersion, osver.dwMinorVersion); + +# if defined(__x86_64__) || defined(_M_AMD64) + length += snprintf(buf + length, max - length, "; Win64; x64) libuv/%s", uv_version_string()); +# else + length += snprintf(buf + length, max - length, ") libuv/%s", uv_version_string()); +# endif + +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100); +# endif + +# ifdef __GNUC__ + length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# elif _MSC_VER + length += snprintf(buf + length, max - length, " msvc/%d", MSVC_VERSION); +# endif + + return buf; +} + + +bool Platform::setThreadAffinity(uint64_t cpu_id) +{ + if (cpu_id >= 64) { + LOG_ERR("Unable to set affinity. Windows supports only affinity up to 63."); + } + + return SetThreadAffinityMask(GetCurrentThread(), 1ULL << cpu_id) != 0; +} + + +void Platform::setProcessPriority(int priority) +{ + if (priority == -1) { + return; + } + + DWORD prio = IDLE_PRIORITY_CLASS; + switch (priority) + { + case 1: + prio = BELOW_NORMAL_PRIORITY_CLASS; + break; + + case 2: + prio = NORMAL_PRIORITY_CLASS; + break; + + case 3: + prio = ABOVE_NORMAL_PRIORITY_CLASS; + break; + + case 4: + prio = HIGH_PRIORITY_CLASS; + break; + + case 5: + prio = REALTIME_PRIORITY_CLASS; + + default: + break; + } + + SetPriorityClass(GetCurrentProcess(), prio); +} + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = THREAD_PRIORITY_IDLE; + switch (priority) + { + case 1: + prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + + case 2: + prio = THREAD_PRIORITY_NORMAL; + break; + + case 3: + prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + + case 4: + prio = THREAD_PRIORITY_HIGHEST; + break; + + case 5: + prio = THREAD_PRIORITY_TIME_CRITICAL; + break; + + default: + break; + } + + SetThreadPriority(GetCurrentThread(), prio); +} + diff --git a/src/common/api/HttpBody.h b/src/common/api/HttpBody.h new file mode 100644 index 00000000..0b143fb7 --- /dev/null +++ b/src/common/api/HttpBody.h @@ -0,0 +1,69 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __HTTPBODY_H__ +#define __HTTPBODY_H__ + + +#include + + +namespace xmrig { + + +class HttpBody +{ +public: + inline HttpBody() : + m_pos(0) + {} + + + inline bool write(const char *data, size_t size) + { + if (size > (sizeof(m_data) - m_pos - 1)) { + return false; + } + + memcpy(m_data + m_pos, data, size); + + m_pos += size; + m_data[m_pos] = '\0'; + + return true; + } + + + inline const char *data() const { return m_data; } + +private: + char m_data[32768]; + size_t m_pos; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPBODY_H__ */ diff --git a/src/common/api/HttpReply.h b/src/common/api/HttpReply.h new file mode 100644 index 00000000..6a6cb802 --- /dev/null +++ b/src/common/api/HttpReply.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __HTTPREPLY_H__ +#define __HTTPREPLY_H__ + + +#include + + +namespace xmrig { + + +class HttpReply +{ +public: + HttpReply() : + buf(nullptr), + status(200), + size(0) + {} + + char *buf; + int status; + size_t size; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPREPLY_H__ */ diff --git a/src/common/api/HttpRequest.cpp b/src/common/api/HttpRequest.cpp new file mode 100644 index 00000000..6898a385 --- /dev/null +++ b/src/common/api/HttpRequest.cpp @@ -0,0 +1,175 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + +#include "common/api/HttpBody.h" +#include "common/api/HttpRequest.h" +#include "common/api/HttpReply.h" + + +#ifndef MHD_HTTP_PAYLOAD_TOO_LARGE +# define MHD_HTTP_PAYLOAD_TOO_LARGE 413 +#endif + + +xmrig::HttpRequest::HttpRequest(MHD_Connection *connection, const char *url, const char *method, const char *uploadData, size_t *uploadSize, void **cls) : + m_fulfilled(true), + m_restricted(true), + m_uploadData(uploadData), + m_url(url), + m_body(static_cast(*cls)), + m_method(Unsupported), + m_connection(connection), + m_uploadSize(uploadSize), + m_cls(cls) +{ + if (strcmp(method, MHD_HTTP_METHOD_OPTIONS) == 0) { + m_method = Options; + } + else if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) { + m_method = Get; + } + else if (strcmp(method, MHD_HTTP_METHOD_PUT) == 0) { + m_method = Put; + } +} + + +xmrig::HttpRequest::~HttpRequest() +{ + if (m_fulfilled) { + delete m_body; + } +} + + +bool xmrig::HttpRequest::match(const char *path) const +{ + return strcmp(m_url, path) == 0; +} + + +bool xmrig::HttpRequest::process(const char *accessToken, bool restricted, xmrig::HttpReply &reply) +{ + m_restricted = restricted || !accessToken; + + if (m_body) { + if (*m_uploadSize != 0) { + if (!m_body->write(m_uploadData, *m_uploadSize)) { + *m_cls = nullptr; + m_fulfilled = true; + reply.status = MHD_HTTP_PAYLOAD_TOO_LARGE; + return false; + } + + *m_uploadSize = 0; + m_fulfilled = false; + return true; + } + + m_fulfilled = true; + return true; + } + + reply.status = auth(accessToken); + if (reply.status != MHD_HTTP_OK) { + return false; + } + + if (m_restricted && m_method != Get) { + reply.status = MHD_HTTP_FORBIDDEN; + return false; + } + + if (m_method == Get) { + return true; + } + + const char *contentType = MHD_lookup_connection_value(m_connection, MHD_HEADER_KIND, "Content-Type"); + if (!contentType || strcmp(contentType, "application/json") != 0) { + reply.status = MHD_HTTP_UNSUPPORTED_MEDIA_TYPE; + return false; + } + + m_body = new xmrig::HttpBody(); + m_fulfilled = false; + *m_cls = m_body; + + return true; +} + + +const char *xmrig::HttpRequest::body() const +{ + return m_body ? m_body->data() : nullptr; +} + + +int xmrig::HttpRequest::end(const HttpReply &reply) +{ + if (reply.buf) { + return end(reply.status, MHD_create_response_from_buffer(reply.size ? reply.size : strlen(reply.buf), (void*) reply.buf, MHD_RESPMEM_MUST_FREE)); + } + + return end(reply.status, nullptr); +} + + +int xmrig::HttpRequest::end(int status, MHD_Response *rsp) +{ + if (!rsp) { + rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT); + } + + MHD_add_response_header(rsp, "Content-Type", "application/json"); + MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*"); + MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "GET, PUT"); + MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization, Content-Type"); + + const int ret = MHD_queue_response(m_connection, status, rsp); + MHD_destroy_response(rsp); + return ret; +} + + +int xmrig::HttpRequest::auth(const char *accessToken) +{ + if (!accessToken) { + return MHD_HTTP_OK; + } + + const char *header = MHD_lookup_connection_value(m_connection, MHD_HEADER_KIND, "Authorization"); + if (accessToken && !header) { + return MHD_HTTP_UNAUTHORIZED; + } + + const size_t size = strlen(header); + if (size < 8 || strlen(accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) { + return MHD_HTTP_FORBIDDEN; + } + + return strncmp(accessToken, header + 7, strlen(accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN; +} diff --git a/src/common/api/HttpRequest.h b/src/common/api/HttpRequest.h new file mode 100644 index 00000000..f6ff9a40 --- /dev/null +++ b/src/common/api/HttpRequest.h @@ -0,0 +1,84 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __HTTPREQUEST_H__ +#define __HTTPREQUEST_H__ + + +#include + + +struct MHD_Connection; +struct MHD_Response; + + +namespace xmrig { + + +class HttpBody; +class HttpReply; + + +class HttpRequest +{ +public: + enum Method { + Unsupported, + Options, + Get, + Put + }; + + HttpRequest(MHD_Connection *connection, const char *url, const char *method, const char *uploadData, size_t *uploadSize, void **cls); + ~HttpRequest(); + + inline bool isFulfilled() const { return m_fulfilled; } + inline bool isRestricted() const { return m_restricted; } + inline Method method() const { return m_method; } + + bool match(const char *path) const; + bool process(const char *accessToken, bool restricted, xmrig::HttpReply &reply); + const char *body() const; + int end(const HttpReply &reply); + int end(int status, MHD_Response *rsp); + +private: + int auth(const char *accessToken); + + bool m_fulfilled; + bool m_restricted; + const char *m_uploadData; + const char *m_url; + HttpBody *m_body; + Method m_method; + MHD_Connection *m_connection; + size_t *m_uploadSize; + void **m_cls; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPREQUEST_H__ */ diff --git a/src/common/api/Httpd.cpp b/src/common/api/Httpd.cpp new file mode 100644 index 00000000..eb6a4ba6 --- /dev/null +++ b/src/common/api/Httpd.cpp @@ -0,0 +1,148 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "api/Api.h" +#include "common/api/Httpd.h" +#include "common/api/HttpReply.h" +#include "common/api/HttpRequest.h" +#include "common/log/Log.h" + + +Httpd::Httpd(int port, const char *accessToken, bool IPv6, bool restricted) : + m_idle(true), + m_IPv6(IPv6), + m_restricted(restricted), + m_accessToken(accessToken ? strdup(accessToken) : nullptr), + m_port(port), + m_daemon(nullptr) +{ + uv_timer_init(uv_default_loop(), &m_timer); + m_timer.data = this; +} + + +Httpd::~Httpd() +{ + uv_timer_stop(&m_timer); + + if (m_daemon) { + MHD_stop_daemon(m_daemon); + } + + delete m_accessToken; +} + + +bool Httpd::start() +{ + if (!m_port) { + return false; + } + + unsigned int flags = 0; +# if MHD_VERSION >= 0x00093500 + if (m_IPv6 && MHD_is_feature_supported(MHD_FEATURE_IPv6)) { + flags |= MHD_USE_DUAL_STACK; + } + + if (MHD_is_feature_supported(MHD_FEATURE_EPOLL)) { + flags |= MHD_USE_EPOLL_LINUX_ONLY; + } +# endif + + m_daemon = MHD_start_daemon(flags, m_port, nullptr, nullptr, &Httpd::handler, this, MHD_OPTION_END); + if (!m_daemon) { + LOG_ERR("HTTP Daemon failed to start."); + return false; + } + +# if MHD_VERSION >= 0x00093900 + uv_timer_start(&m_timer, Httpd::onTimer, kIdleInterval, kIdleInterval); +# else + uv_timer_start(&m_timer, Httpd::onTimer, kActiveInterval, kActiveInterval); +# endif + + return true; +} + + +int Httpd::process(xmrig::HttpRequest &req) +{ + xmrig::HttpReply reply; + if (!req.process(m_accessToken, m_restricted, reply)) { + return req.end(reply); + } + + if (!req.isFulfilled()) { + return MHD_YES; + } + + Api::exec(req, reply); + + return req.end(reply); +} + + +void Httpd::run() +{ + MHD_run(m_daemon); + +# if MHD_VERSION >= 0x00093900 + const MHD_DaemonInfo *info = MHD_get_daemon_info(m_daemon, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); + if (m_idle && info->num_connections) { + uv_timer_set_repeat(&m_timer, kActiveInterval); + m_idle = false; + } + else if (!m_idle && !info->num_connections) { + uv_timer_set_repeat(&m_timer, kIdleInterval); + m_idle = true; + } +# endif +} + + +int Httpd::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *uploadData, size_t *uploadSize, void **con_cls) +{ + xmrig::HttpRequest req(connection, url, method, uploadData, uploadSize, con_cls); + + if (req.method() == xmrig::HttpRequest::Options) { + return req.end(MHD_HTTP_OK, nullptr); + } + + if (req.method() == xmrig::HttpRequest::Unsupported) { + return req.end(MHD_HTTP_METHOD_NOT_ALLOWED, nullptr); + } + + return static_cast(cls)->process(req); +} + + +void Httpd::onTimer(uv_timer_t *handle) +{ + static_cast(handle->data)->run(); +} diff --git a/src/common/api/Httpd.h b/src/common/api/Httpd.h new file mode 100644 index 00000000..adec1d71 --- /dev/null +++ b/src/common/api/Httpd.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __HTTPD_H__ +#define __HTTPD_H__ + + +#include + + +struct MHD_Connection; +struct MHD_Daemon; +struct MHD_Response; + + +class UploadCtx; + + +namespace xmrig { + class HttpRequest; +} + + +class Httpd +{ +public: + Httpd(int port, const char *accessToken, bool IPv6, bool restricted); + ~Httpd(); + bool start(); + +private: + constexpr static const int kIdleInterval = 200; + constexpr static const int kActiveInterval = 25; + + int process(xmrig::HttpRequest &req); + void run(); + + static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *uploadData, size_t *uploadSize, void **con_cls); + static void onTimer(uv_timer_t *handle); + + bool m_idle; + bool m_IPv6; + bool m_restricted; + const char *m_accessToken; + const int m_port; + MHD_Daemon *m_daemon; + uv_timer_t m_timer; +}; + +#endif /* __HTTPD_H__ */ diff --git a/src/common/config/CommonConfig.cpp b/src/common/config/CommonConfig.cpp new file mode 100644 index 00000000..beb2d0c9 --- /dev/null +++ b/src/common/config/CommonConfig.cpp @@ -0,0 +1,495 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include + + +#ifndef XMRIG_NO_HTTPD +# include +#endif + + +#ifndef XMRIG_NO_TLS +# include +#endif + + +#ifdef XMRIG_AMD_PROJECT +# if defined(__APPLE__) +# include +# else +# include "3rdparty/CL/cl.h" +# endif +#endif + + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +#include "common/config/CommonConfig.h" +#include "common/log/Log.h" +#include "donate.h" +#include "rapidjson/document.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/prettywriter.h" +#include "version.h" + + +xmrig::CommonConfig::CommonConfig() : + m_algorithm(CRYPTONIGHT, VARIANT_AUTO), + m_adjusted(false), + m_apiIPv6(false), + m_apiRestricted(true), + m_autoSave(true), + m_background(false), + m_colors(true), + m_dryRun(false), + m_syslog(false), + +# ifdef XMRIG_PROXY_PROJECT + m_watch(true), +# else + m_watch(false), // TODO: enable config file watch by default when this feature propertly handled and tested. +# endif + + m_apiPort(0), + m_donateLevel(kDefaultDonateLevel), + m_printTime(60), + m_retries(5), + m_retryPause(5), + m_state(NoneState) +{ + m_pools.push_back(Pool()); + +# ifdef XMRIG_PROXY_PROJECT + m_retries = 2; + m_retryPause = 1; +# endif +} + + +void xmrig::CommonConfig::printAPI() +{ +# ifndef XMRIG_NO_API + if (apiPort() == 0) { + return; + } + + Log::i()->text(isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN("%s:") CYAN_BOLD("%d") + : " * %-13s%s:%d", + "API BIND", isApiIPv6() ? "[::]" : "0.0.0.0", apiPort()); +# endif +} + + +void xmrig::CommonConfig::printPools() +{ + for (size_t i = 0; i < m_activePools.size(); ++i) { + if (!isColors()) { + Log::i()->text(" * POOL #%-7zu%s variant=%s, TLS=%d", + i + 1, + m_activePools[i].url(), + m_activePools[i].algorithm().variantName(), + static_cast(m_activePools[i].isTLS()) + ); + } + else { + Log::i()->text(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") "\x1B[1;%dm%s\x1B[0m variant " WHITE_BOLD("%s"), + i + 1, + m_activePools[i].isTLS() ? 32 : 36, + m_activePools[i].url(), + m_activePools[i].algorithm().variantName() + ); + } + } + +# ifdef APP_DEBUG + LOG_NOTICE("POOLS --------------------------------------------------------------------"); + for (const Pool &pool : m_activePools) { + pool.print(); + } + LOG_NOTICE("--------------------------------------------------------------------------"); +# endif +} + + +void xmrig::CommonConfig::printVersions() +{ + char buf[256] = { 0 }; + +# if defined(__clang__) + snprintf(buf, sizeof buf, "clang/%d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__); +# elif defined(__GNUC__) + snprintf(buf, sizeof buf, "gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# elif defined(_MSC_VER) + snprintf(buf, sizeof buf, "MSVC/%d", MSVC_VERSION); +# endif + + Log::i()->text(isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%s/%s") WHITE_BOLD(" %s") + : " * %-13s%s/%s %s", + "ABOUT", APP_NAME, APP_VERSION, buf); + +# if defined(XMRIG_AMD_PROJECT) +# if CL_VERSION_2_0 + const char *ocl = "2.0"; +# elif CL_VERSION_1_2 + const char *ocl = "1.2"; +# elif CL_VERSION_1_1 + const char *ocl = "1.1"; +# elif CL_VERSION_1_0 + const char *ocl = "1.0"; +# else + const char *ocl = "0.0"; +# endif + int length = snprintf(buf, sizeof buf, "OpenCL/%s ", ocl); +# elif defined(XMRIG_NVIDIA_PROJECT) + const int cudaVersion = cuda_get_runtime_version(); + int length = snprintf(buf, sizeof buf, "CUDA/%d.%d ", cudaVersion / 1000, cudaVersion % 100); +# else + memset(buf, 0, 16); + int length = 0; +# endif + +# if !defined(XMRIG_NO_TLS) && defined(OPENSSL_VERSION_TEXT) + { + constexpr const char *v = OPENSSL_VERSION_TEXT + 8; + length += snprintf(buf + length, (sizeof buf) - length, "OpenSSL/%.*s ", static_cast(strchr(v, ' ') - v), v); + } +# endif + +# ifndef XMRIG_NO_HTTPD + length += snprintf(buf + length, (sizeof buf) - length, "microhttpd/%s ", MHD_get_version()); +# endif + + Log::i()->text(isColors() ? GREEN_BOLD(" * ") WHITE_BOLD("%-13slibuv/%s %s") + : " * %-13slibuv/%s %s", + "LIBS", uv_version_string(), buf); +} + + +bool xmrig::CommonConfig::save() +{ + if (m_fileName.isNull()) { + return false; + } + + uv_fs_t req; + const int fd = uv_fs_open(uv_default_loop(), &req, m_fileName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644, nullptr); + if (fd < 0) { + return false; + } + + uv_fs_req_cleanup(&req); + + rapidjson::Document doc; + getJSON(doc); + + FILE *fp = fdopen(fd, "w"); + + char buf[4096]; + rapidjson::FileWriteStream os(fp, buf, sizeof(buf)); + rapidjson::PrettyWriter writer(os); + doc.Accept(writer); + + fflush(fp); + + uv_fs_close(uv_default_loop(), &req, fd, nullptr); + uv_fs_req_cleanup(&req); + + LOG_NOTICE("configuration saved to: \"%s\"", m_fileName.data()); + return true; +} + + +bool xmrig::CommonConfig::finalize() +{ + if (m_state == ReadyState) { + return true; + } + + if (m_state == ErrorState) { + return false; + } + + if (!m_algorithm.isValid()) { + return false; + } + + for (Pool &pool : m_pools) { + pool.adjust(m_algorithm); + + if (pool.isValid() && pool.algorithm().isValid()) { +# ifdef XMRIG_NO_TLS + if (pool.isTLS()) { + continue; + } +# endif + + m_activePools.push_back(std::move(pool)); + } + } + + m_pools.clear(); + + if (m_activePools.empty()) { + m_state = ErrorState; + return false; + } + + m_state = ReadyState; + return true; +} + + +bool xmrig::CommonConfig::parseBoolean(int key, bool enable) +{ + switch (key) { + case BackgroundKey: /* --background */ + m_background = enable; + break; + + case SyslogKey: /* --syslog */ + m_syslog = enable; + break; + + case KeepAliveKey: /* --keepalive */ + m_pools.back().setKeepAlive(enable ? Pool::kKeepAliveTimeout : 0); + break; + + case TlsKey: /* --tls */ + m_pools.back().setTLS(enable); + break; + +# ifndef XMRIG_PROXY_PROJECT + case NicehashKey: /* --nicehash */ + m_pools.back().setNicehash(enable); + break; +# endif + + case ColorKey: /* --no-color */ + m_colors = enable; + break; + + case WatchKey: /* watch */ + m_watch = enable; + break; + + case ApiIPv6Key: /* ipv6 */ + m_apiIPv6 = enable; + break; + + case ApiRestrictedKey: /* restricted */ + m_apiRestricted = enable; + break; + + case DryRunKey: /* --dry-run */ + m_dryRun = enable; + break; + + case AutoSaveKey: + m_autoSave = enable; + break; + + default: + break; + } + + return true; +} + + +bool xmrig::CommonConfig::parseString(int key, const char *arg) +{ + switch (key) { + case AlgorithmKey: /* --algo */ + m_algorithm.parseAlgorithm(arg); + break; + + case UserpassKey: /* --userpass */ + if (!m_pools.back().setUserpass(arg)) { + return false; + } + + break; + + case UrlKey: /* --url */ + if (m_pools.size() > 1 || m_pools[0].isValid()) { + Pool pool(arg); + + if (pool.isValid()) { + m_pools.push_back(std::move(pool)); + } + } + else { + m_pools[0].parse(arg); + } + + if (!m_pools.back().isValid()) { + return false; + } + + break; + + case UserKey: /* --user */ + m_pools.back().setUser(arg); + break; + + case PasswordKey: /* --pass */ + m_pools.back().setPassword(arg); + break; + + case RigIdKey: /* --rig-id */ + m_pools.back().setRigId(arg); + break; + + case FingerprintKey: /* --tls-fingerprint */ + m_pools.back().setFingerprint(arg); + break; + + case VariantKey: /* --variant */ + m_pools.back().algorithm().parseVariant(arg); + break; + + case LogFileKey: /* --log-file */ + m_logFile = arg; + break; + + case ApiAccessTokenKey: /* --api-access-token */ + m_apiToken = arg; + break; + + case ApiWorkerIdKey: /* --api-worker-id */ + m_apiWorkerId = arg; + break; + + case ApiIdKey: /* --api-id */ + m_apiId = arg; + break; + + case UserAgentKey: /* --user-agent */ + m_userAgent = arg; + break; + + case RetriesKey: /* --retries */ + case RetryPauseKey: /* --retry-pause */ + case ApiPort: /* --api-port */ + case PrintTimeKey: /* --cpu-priority */ + return parseUint64(key, strtol(arg, nullptr, 10)); + + case BackgroundKey: /* --background */ + case SyslogKey: /* --syslog */ + case KeepAliveKey: /* --keepalive */ + case NicehashKey: /* --nicehash */ + case TlsKey: /* --tls */ + case ApiIPv6Key: /* --api-ipv6 */ + case DryRunKey: /* --dry-run */ + return parseBoolean(key, true); + + case ColorKey: /* --no-color */ + case WatchKey: /* --no-watch */ + case ApiRestrictedKey: /* --api-no-restricted */ + return parseBoolean(key, false); + + case DonateLevelKey: /* --donate-level */ +# ifdef XMRIG_PROXY_PROJECT + if (strncmp(arg, "minemonero.pro", 14) == 0) { + m_donateLevel = 0; + return true; + } +# endif + return parseUint64(key, strtol(arg, nullptr, 10)); + + default: + break; + } + + return true; +} + + +bool xmrig::CommonConfig::parseUint64(int key, uint64_t arg) +{ + return parseInt(key, static_cast(arg)); +} + + +void xmrig::CommonConfig::setFileName(const char *fileName) +{ + m_fileName = fileName; +} + + +bool xmrig::CommonConfig::parseInt(int key, int arg) +{ + switch (key) { + case RetriesKey: /* --retries */ + if (arg > 0 && arg <= 1000) { + m_retries = arg; + } + break; + + case RetryPauseKey: /* --retry-pause */ + if (arg > 0 && arg <= 3600) { + m_retryPause = arg; + } + break; + + case KeepAliveKey: /* --keepalive */ + m_pools.back().setKeepAlive(arg); + break; + + case VariantKey: /* --variant */ + m_pools.back().algorithm().parseVariant(arg); + break; + + case DonateLevelKey: /* --donate-level */ + if (arg >= kMinimumDonateLevel && arg <= 99) { + m_donateLevel = arg; + } + break; + + case ApiPort: /* --api-port */ + if (arg > 0 && arg <= 65536) { + m_apiPort = arg; + } + break; + + case PrintTimeKey: /* --print-time */ + if (arg >= 0 && arg <= 3600) { + m_printTime = arg; + } + break; + + default: + break; + } + + return true; +} diff --git a/src/common/config/CommonConfig.h b/src/common/config/CommonConfig.h new file mode 100644 index 00000000..422a6bb2 --- /dev/null +++ b/src/common/config/CommonConfig.h @@ -0,0 +1,120 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_COMMONCONFIG_H +#define XMRIG_COMMONCONFIG_H + + +#include + + +#include "common/interfaces/IConfig.h" +#include "common/net/Pool.h" +#include "common/utils/c_str.h" +#include "common/xmrig.h" + + +namespace xmrig { + + +class CommonConfig : public IConfig +{ +public: + CommonConfig(); + + inline bool isApiIPv6() const { return m_apiIPv6; } + inline bool isApiRestricted() const { return m_apiRestricted; } + inline bool isAutoSave() const { return m_autoSave; } + inline bool isBackground() const { return m_background; } + inline bool isColors() const { return m_colors; } + inline bool isDryRun() const { return m_dryRun; } + inline bool isSyslog() const { return m_syslog; } + inline const char *apiId() const { return m_apiId.data(); } + inline const char *apiToken() const { return m_apiToken.data(); } + inline const char *apiWorkerId() const { return m_apiWorkerId.data(); } + inline const char *logFile() const { return m_logFile.data(); } + inline const char *userAgent() const { return m_userAgent.data(); } + inline const std::vector &pools() const { return m_activePools; } + inline int apiPort() const { return m_apiPort; } + inline int donateLevel() const { return m_donateLevel; } + inline int printTime() const { return m_printTime; } + inline int retries() const { return m_retries; } + inline int retryPause() const { return m_retryPause; } + inline void setColors(bool colors) { m_colors = colors; } + + inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } + inline const Algorithm &algorithm() const override { return m_algorithm; } + inline const char *fileName() const override { return m_fileName.data(); } + + bool save() override; + + void printAPI(); + void printPools(); + void printVersions(); + +protected: + enum State { + NoneState, + ReadyState, + ErrorState + }; + + bool finalize() override; + bool parseBoolean(int key, bool enable) override; + bool parseString(int key, const char *arg) override; + bool parseUint64(int key, uint64_t arg) override; + void setFileName(const char *fileName) override; + + Algorithm m_algorithm; + bool m_adjusted; + bool m_apiIPv6; + bool m_apiRestricted; + bool m_autoSave; + bool m_background; + bool m_colors; + bool m_dryRun; + bool m_syslog; + bool m_watch; + int m_apiPort; + int m_donateLevel; + int m_printTime; + int m_retries; + int m_retryPause; + State m_state; + std::vector m_activePools; + std::vector m_pools; + xmrig::c_str m_apiId; + xmrig::c_str m_apiToken; + xmrig::c_str m_apiWorkerId; + xmrig::c_str m_fileName; + xmrig::c_str m_logFile; + xmrig::c_str m_userAgent; + +private: + bool parseInt(int key, int arg); +}; + + +} /* namespace xmrig */ + +#endif /* __COMMONCONFIG_H__ */ diff --git a/src/common/config/ConfigLoader.cpp b/src/common/config/ConfigLoader.cpp new file mode 100644 index 00000000..484c2f8f --- /dev/null +++ b/src/common/config/ConfigLoader.cpp @@ -0,0 +1,330 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include + + +#ifndef XMRIG_NO_HTTPD +# include +#endif + + +#ifndef XMRIG_NO_TLS +# include +#endif + + +#include "common/config/ConfigLoader.h" +#include "common/config/ConfigWatcher.h" +#include "common/interfaces/IConfig.h" +#include "common/interfaces/IWatcherListener.h" +#include "common/net/Pool.h" +#include "common/Platform.h" +#include "core/ConfigCreator.h" +#include "core/ConfigLoader_platform.h" +#include "rapidjson/document.h" +#include "rapidjson/error/en.h" +#include "rapidjson/filereadstream.h" + + +xmrig::ConfigWatcher *xmrig::ConfigLoader::m_watcher = nullptr; +xmrig::IConfigCreator *xmrig::ConfigLoader::m_creator = nullptr; +xmrig::IWatcherListener *xmrig::ConfigLoader::m_listener = nullptr; + + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + + +bool xmrig::ConfigLoader::loadFromFile(xmrig::IConfig *config, const char *fileName) +{ + rapidjson::Document doc; + if (!getJSON(fileName, doc)) { + return false; + } + + config->setFileName(fileName); + + return loadFromJSON(config, doc); +} + + +bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const char *json) +{ + rapidjson::Document doc; + doc.Parse(json); + + if (doc.HasParseError() || !doc.IsObject()) { + return false; + } + + return loadFromJSON(config, doc); +} + + +bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const rapidjson::Document &doc) +{ + for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) { + parseJSON(config, &config_options[i], doc); + } + + const rapidjson::Value &pools = doc["pools"]; + if (pools.IsArray()) { + for (const rapidjson::Value &value : pools.GetArray()) { + if (!value.IsObject()) { + continue; + } + + for (size_t i = 0; i < ARRAY_SIZE(pool_options); i++) { + parseJSON(config, &pool_options[i], value); + } + } + } + + const rapidjson::Value &api = doc["api"]; + if (api.IsObject()) { + for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) { + parseJSON(config, &api_options[i], api); + } + } + + config->parseJSON(doc); + + return config->finalize(); +} + + +bool xmrig::ConfigLoader::reload(xmrig::IConfig *oldConfig, const char *json) +{ + xmrig::IConfig *config = m_creator->create(); + if (!loadFromJSON(config, json)) { + delete config; + + return false; + } + + config->setFileName(oldConfig->fileName()); + const bool saved = config->save(); + + if (config->isWatch() && m_watcher && saved) { + delete config; + + return true; + } + + m_listener->onNewConfig(config); + return true; +} + + +xmrig::IConfig *xmrig::ConfigLoader::load(int argc, char **argv, IConfigCreator *creator, IWatcherListener *listener) +{ + m_creator = creator; + m_listener = listener; + + xmrig::IConfig *config = m_creator->create(); + int key; + + while (1) { + key = getopt_long(argc, argv, short_options, options, NULL); + if (key < 0) { + break; + } + + if (!parseArg(config, key, optarg)) { + delete config; + return nullptr; + } + } + + if (optind < argc) { + fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], argv[optind]); + delete config; + return nullptr; + } + + if (!config->finalize()) { + delete config; + + config = m_creator->create(); + loadFromFile(config, Platform::defaultConfigName()); + } + + if (!config->finalize()) { + if (!config->algorithm().isValid()) { + fprintf(stderr, "No valid algorithm specified. Exiting.\n"); + } + else { + fprintf(stderr, "No valid configuration found. Exiting.\n"); + } + + delete config; + return nullptr; + } + + if (config->isWatch()) { + m_watcher = new xmrig::ConfigWatcher(config->fileName(), creator, listener); + } + + return config; +} + + +void xmrig::ConfigLoader::release() +{ + delete m_watcher; + delete m_creator; + + m_watcher = nullptr; + m_creator = nullptr; +} + + +bool xmrig::ConfigLoader::getJSON(const char *fileName, rapidjson::Document &doc) +{ + uv_fs_t req; + const int fd = uv_fs_open(uv_default_loop(), &req, fileName, O_RDONLY, 0644, nullptr); + if (fd < 0) { + fprintf(stderr, "unable to open %s: %s\n", fileName, uv_strerror(fd)); + return false; + } + + uv_fs_req_cleanup(&req); + + FILE *fp = fdopen(fd, "rb"); + char buf[8192]; + rapidjson::FileReadStream is(fp, buf, sizeof(buf)); + + doc.ParseStream(is); + + uv_fs_close(uv_default_loop(), &req, fd, nullptr); + uv_fs_req_cleanup(&req); + + if (doc.HasParseError()) { + printf("%s<%d>: %s\n", fileName, (int) doc.GetErrorOffset(), rapidjson::GetParseError_En(doc.GetParseError())); + return false; + } + + return doc.IsObject(); +} + + +bool xmrig::ConfigLoader::parseArg(xmrig::IConfig *config, int key, const char *arg) +{ + switch (key) { + case xmrig::IConfig::VersionKey: /* --version */ + showVersion(); + return false; + + case xmrig::IConfig::HelpKey: /* --help */ + showUsage(); + return false; + + case xmrig::IConfig::ConfigKey: /* --config */ + loadFromFile(config, arg); + break; + + default: + return config->parseString(key, arg);; + } + + return true; +} + + +void xmrig::ConfigLoader::parseJSON(xmrig::IConfig *config, const struct option *option, const rapidjson::Value &object) +{ + if (!option->name || !object.HasMember(option->name)) { + return; + } + + const rapidjson::Value &value = object[option->name]; + + if (option->has_arg) { + if (value.IsString()) { + config->parseString(option->val, value.GetString()); + } + else if (value.IsInt64()) { + config->parseUint64(option->val, value.GetUint64()); + } + else if (value.IsBool()) { + config->parseBoolean(option->val, value.IsTrue()); + } + } + else if (value.IsBool()) { + config->parseBoolean(option->val, value.IsTrue()); + } +} + + +void xmrig::ConfigLoader::showUsage() +{ + printf(usage); +} + + +void xmrig::ConfigLoader::showVersion() +{ + printf(APP_NAME " " APP_VERSION "\n built on " __DATE__ + +# if defined(__clang__) + " with clang " __clang_version__); +# elif defined(__GNUC__) + " with GCC"); + printf(" %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# elif defined(_MSC_VER) + " with MSVC"); + printf(" %d", MSVC_VERSION); +# else + ); +# endif + + printf("\n features:" +# if defined(__i386__) || defined(_M_IX86) + " 32-bit" +# elif defined(__x86_64__) || defined(_M_AMD64) + " 64-bit" +# endif + +# if defined(__AES__) || defined(_MSC_VER) + " AES" +# endif + "\n"); + + printf("\nlibuv/%s\n", uv_version_string()); + +# ifndef XMRIG_NO_HTTPD + printf("microhttpd/%s\n", MHD_get_version()); +# endif + +# if !defined(XMRIG_NO_TLS) && defined(OPENSSL_VERSION_TEXT) + { + constexpr const char *v = OPENSSL_VERSION_TEXT + 8; + printf("OpenSSL/%.*s\n", static_cast(strchr(v, ' ') - v), v); + } +# endif +} diff --git a/src/common/config/ConfigLoader.h b/src/common/config/ConfigLoader.h new file mode 100644 index 00000000..64638af3 --- /dev/null +++ b/src/common/config/ConfigLoader.h @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONFIGLOADER_H__ +#define __CONFIGLOADER_H__ + + +#include + + +#include "rapidjson/fwd.h" + + +struct option; + + +namespace xmrig { + + +class ConfigWatcher; +class IConfigCreator; +class IWatcherListener; +class IConfig; + + +class ConfigLoader +{ +public: + static bool loadFromFile(IConfig *config, const char *fileName); + static bool loadFromJSON(IConfig *config, const char *json); + static bool loadFromJSON(IConfig *config, const rapidjson::Document &doc); + static bool reload(IConfig *oldConfig, const char *json); + static IConfig *load(int argc, char **argv, IConfigCreator *creator, IWatcherListener *listener); + static void release(); + +private: + static bool getJSON(const char *fileName, rapidjson::Document &doc); + static bool parseArg(IConfig *config, int key, const char *arg); + static void parseJSON(IConfig *config, const struct option *option, const rapidjson::Value &object); + static void showUsage(); + static void showVersion(); + + static ConfigWatcher *m_watcher; + static IConfigCreator *m_creator; + static IWatcherListener *m_listener; +}; + + +} /* namespace xmrig */ + +#endif /* __CONFIGLOADER_H__ */ diff --git a/src/common/config/ConfigWatcher.cpp b/src/common/config/ConfigWatcher.cpp new file mode 100644 index 00000000..14107b62 --- /dev/null +++ b/src/common/config/ConfigWatcher.cpp @@ -0,0 +1,105 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/config/ConfigLoader.h" +#include "common/config/ConfigWatcher.h" +#include "common/interfaces/IWatcherListener.h" +#include "common/log/Log.h" +#include "core/ConfigCreator.h" + + +xmrig::ConfigWatcher::ConfigWatcher(const char *path, IConfigCreator *creator, IWatcherListener *listener) : + m_creator(creator), + m_listener(listener), + m_path(path) +{ + uv_fs_event_init(uv_default_loop(), &m_fsEvent); + uv_timer_init(uv_default_loop(), &m_timer); + + m_fsEvent.data = m_timer.data = this; + + start(); +} + + +xmrig::ConfigWatcher::~ConfigWatcher() +{ + uv_timer_stop(&m_timer); + uv_fs_event_stop(&m_fsEvent); +} + + +void xmrig::ConfigWatcher::onTimer(uv_timer_t* handle) +{ + static_cast(handle->data)->reload(); +} + + +void xmrig::ConfigWatcher::onFsEvent(uv_fs_event_t* handle, const char *filename, int events, int status) +{ + if (!filename) { + return; + } + + static_cast(handle->data)->queueUpdate(); +} + + +void xmrig::ConfigWatcher::queueUpdate() +{ + uv_timer_stop(&m_timer); + uv_timer_start(&m_timer, xmrig::ConfigWatcher::onTimer, kDelay, 0); +} + + +void xmrig::ConfigWatcher::reload() +{ + LOG_WARN("\"%s\" was changed, reloading configuration", m_path.data()); + + IConfig *config = m_creator->create(); + ConfigLoader::loadFromFile(config, m_path.data()); + + if (!config->finalize()) { + LOG_ERR("reloading failed"); + + delete config; + return; + } + + m_listener->onNewConfig(config); + +# ifndef _WIN32 + uv_fs_event_stop(&m_fsEvent); + start(); +# endif +} + + +void xmrig::ConfigWatcher::start() +{ + uv_fs_event_start(&m_fsEvent, xmrig::ConfigWatcher::onFsEvent, m_path.data(), 0); +} diff --git a/src/common/config/ConfigWatcher.h b/src/common/config/ConfigWatcher.h new file mode 100644 index 00000000..7f38b45a --- /dev/null +++ b/src/common/config/ConfigWatcher.h @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONFIGWATCHER_H__ +#define __CONFIGWATCHER_H__ + + +#include +#include + + +#include "common/utils/c_str.h" +#include "rapidjson/fwd.h" + + +struct option; + + +namespace xmrig { + + +class IConfigCreator; +class IWatcherListener; + + +class ConfigWatcher +{ +public: + ConfigWatcher(const char *path, IConfigCreator *creator, IWatcherListener *listener); + ~ConfigWatcher(); + +private: + constexpr static int kDelay = 500; + + static void onFsEvent(uv_fs_event_t* handle, const char *filename, int events, int status); + static void onTimer(uv_timer_t* handle); + void queueUpdate(); + void reload(); + void start(); + + IConfigCreator *m_creator; + IWatcherListener *m_listener; + uv_fs_event_t m_fsEvent; + uv_timer_t m_timer; + xmrig::c_str m_path; +}; + + +} /* namespace xmrig */ + +#endif /* __CONFIGWATCHER_H__ */ diff --git a/src/common/cpu/BasicCpuInfo.cpp b/src/common/cpu/BasicCpuInfo.cpp new file mode 100644 index 00000000..cb1e6d1d --- /dev/null +++ b/src/common/cpu/BasicCpuInfo.cpp @@ -0,0 +1,131 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + + +#ifdef _MSC_VER +# include +#else +# include +#endif + +#ifndef bit_AES +# define bit_AES (1 << 25) +#endif + + +#include "common/cpu/BasicCpuInfo.h" + + +#define VENDOR_ID (0) +#define PROCESSOR_INFO (1) +#define CACHE_TLB_DESCRIPTOR (2) +#define EXTENDED_FEATURES (7) +#define PROCESSOR_BRAND_STRING_1 (0x80000002) +#define PROCESSOR_BRAND_STRING_2 (0x80000003) +#define PROCESSOR_BRAND_STRING_3 (0x80000004) + +#define EAX_Reg (0) +#define EBX_Reg (1) +#define ECX_Reg (2) +#define EDX_Reg (3) + + +#ifdef _MSC_VER +static inline void cpuid(int level, int output[4]) { + __cpuid(output, level); +} +#else +static inline void cpuid(int level, int output[4]) { + int a, b, c, d; + __cpuid_count(level, 0, a, b, c, d); + + output[0] = a; + output[1] = b; + output[2] = c; + output[3] = d; +} +#endif + + +static inline void cpu_brand_string(char* s) { + int32_t cpu_info[4] = { 0 }; + cpuid(VENDOR_ID, cpu_info); + + if (cpu_info[EAX_Reg] >= 4) { + for (int i = 0; i < 4; i++) { + cpuid(0x80000002 + i, cpu_info); + memcpy(s, cpu_info, sizeof(cpu_info)); + s += 16; + } + } +} + + +static inline bool has_aes_ni() +{ + int32_t cpu_info[4] = { 0 }; + cpuid(PROCESSOR_INFO, cpu_info); + + return (cpu_info[ECX_Reg] & bit_AES) != 0; +} + + +xmrig::BasicCpuInfo::BasicCpuInfo() : + m_assembly(ASM_NONE), + m_aes(has_aes_ni()), + m_brand(), + m_threads(std::thread::hardware_concurrency()) +{ + cpu_brand_string(m_brand); + +# ifndef XMRIG_NO_ASM + if (hasAES()) { + char vendor[13] = { 0 }; + int32_t data[4] = { 0 }; + + cpuid(0, data); + + memcpy(vendor + 0, &data[1], 4); + memcpy(vendor + 4, &data[3], 4); + memcpy(vendor + 8, &data[2], 4); + + if (memcmp(vendor, "GenuineIntel", 12) == 0) { + m_assembly = ASM_INTEL; + } + else if (memcmp(vendor, "AuthenticAMD", 12) == 0) { + m_assembly = ASM_RYZEN; + } + } +# endif +} + + +size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +{ + const size_t count = threads() / 2; + + return count < 1 ? 1 : count; +} diff --git a/src/common/cpu/BasicCpuInfo.h b/src/common/cpu/BasicCpuInfo.h new file mode 100644 index 00000000..911674ea --- /dev/null +++ b/src/common/cpu/BasicCpuInfo.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_BASICCPUINFO_H +#define XMRIG_BASICCPUINFO_H + + +#include "common/interfaces/ICpuInfo.h" + + +namespace xmrig { + + +class BasicCpuInfo : public ICpuInfo +{ +public: + BasicCpuInfo(); + +protected: + size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + + inline Assembly assembly() const override { return m_assembly; } + inline bool hasAES() const override { return m_aes; } + inline bool isSupported() const override { return true; } + inline const char *brand() const override { return m_brand; } + inline int32_t cores() const override { return -1; } + inline int32_t L2() const override { return -1; } + inline int32_t L3() const override { return -1; } + inline int32_t nodes() const override { return -1; } + inline int32_t sockets() const override { return 1; } + inline int32_t threads() const override { return m_threads; } + +# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) + inline bool isX64() const override { return true; } +# else + inline bool isX64() const override { return false; } +# endif + +private: + Assembly m_assembly; + bool m_aes; + char m_brand[64]; + int32_t m_threads; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_BASICCPUINFO_H */ diff --git a/src/common/cpu/BasicCpuInfo_arm.cpp b/src/common/cpu/BasicCpuInfo_arm.cpp new file mode 100644 index 00000000..c1c127db --- /dev/null +++ b/src/common/cpu/BasicCpuInfo_arm.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + + +#include "common/cpu/BasicCpuInfo.h" + + +xmrig::BasicCpuInfo::BasicCpuInfo() : + m_aes(false), + m_brand(), + m_threads(std::thread::hardware_concurrency()) +{ + memcpy(m_brand, "Unknown", 7); + +# if __ARM_FEATURE_CRYPTO + m_aes = true; +# endif +} + + +size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +{ + return threads(); +} diff --git a/src/common/cpu/Cpu.cpp b/src/common/cpu/Cpu.cpp new file mode 100644 index 00000000..b1bb28ac --- /dev/null +++ b/src/common/cpu/Cpu.cpp @@ -0,0 +1,57 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/cpu/BasicCpuInfo.h" +#include "common/cpu/Cpu.h" + + +static xmrig::ICpuInfo *cpuInfo = nullptr; + + +xmrig::ICpuInfo *xmrig::Cpu::info() +{ + assert(cpuInfo != nullptr); + + return cpuInfo; +} + + +void xmrig::Cpu::init() +{ + assert(cpuInfo == nullptr); + + cpuInfo = new BasicCpuInfo(); +} + + +void xmrig::Cpu::release() +{ + assert(cpuInfo != nullptr); + + delete cpuInfo; + cpuInfo = nullptr; +} diff --git a/src/common/cpu/Cpu.h b/src/common/cpu/Cpu.h new file mode 100644 index 00000000..1d5a9fb1 --- /dev/null +++ b/src/common/cpu/Cpu.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPU_H +#define XMRIG_CPU_H + + +#include "common/interfaces/ICpuInfo.h" + + +namespace xmrig { + + +class Cpu +{ +public: + static ICpuInfo *info(); + static void init(); + static void release(); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPU_H */ diff --git a/src/common/crypto/Algorithm.cpp b/src/common/crypto/Algorithm.cpp new file mode 100644 index 00000000..a3cf48b2 --- /dev/null +++ b/src/common/crypto/Algorithm.cpp @@ -0,0 +1,240 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include + + +#include "common/crypto/Algorithm.h" + + +#ifdef _MSC_VER +# define strncasecmp _strnicmp +# define strcasecmp _stricmp +#endif + + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + + +struct AlgoData +{ + const char *name; + const char *shortName; + xmrig::Algo algo; + xmrig::Variant variant; +}; + + +static AlgoData const algorithms[] = { + { "cryptonight", "cn", xmrig::CRYPTONIGHT, xmrig::VARIANT_AUTO }, + { "cryptonight/0", "cn/0", xmrig::CRYPTONIGHT, xmrig::VARIANT_0 }, + { "cryptonight/1", "cn/1", xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, + { "cryptonight/xtl", "cn/xtl", xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, + { "cryptonight/msr", "cn/msr", xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, + { "cryptonight/xao", "cn/xao", xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, + { "cryptonight/rto", "cn/rto", xmrig::CRYPTONIGHT, xmrig::VARIANT_RTO }, + { "cryptonight/2", "cn/2", xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, + +# ifndef XMRIG_NO_AEON + { "cryptonight-lite", "cn-lite", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, + { "cryptonight-light", "cn-light", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, + { "cryptonight-lite/0", "cn-lite/0", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, + { "cryptonight-lite/1", "cn-lite/1", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, +# endif + +# ifndef XMRIG_NO_SUMO + { "cryptonight-heavy", "cn-heavy", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_AUTO }, + { "cryptonight-heavy/0", "cn-heavy/0", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, + { "cryptonight-heavy/xhv", "cn-heavy/xhv", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, + { "cryptonight-heavy/tube", "cn-heavy/tube", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, +# endif +}; + + +#ifdef XMRIG_PROXY_PROJECT +static AlgoData const xmrStakAlgorithms[] = { + { "cryptonight-monerov7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, + { "cryptonight_v7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, + { "cryptonight-monerov8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, + { "cryptonight_v8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, + { "cryptonight_v7_stellite", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, + { "cryptonight_lite", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, + { "cryptonight-aeonv7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, + { "cryptonight_lite_v7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, + { "cryptonight_heavy", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, + { "cryptonight_haven", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, + { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, + { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, + { "cryptonight-bittube2", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, // bittube-miner + { "cryptonight_alloy", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, // xmr-stak-alloy +}; +#endif + + +static const char *variants[] = { + "0", + "1", + "tube", + "xtl", + "msr", + "xhv", + "xao", + "rto", + "2", +}; + + +bool xmrig::Algorithm::isValid() const +{ + if (m_algo == INVALID_ALGO) { + return false; + } + + for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { + if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { + return true; + } + } + + return false; +} + + +const char *xmrig::Algorithm::variantName() const +{ + if (m_variant == VARIANT_AUTO) { + return "auto"; + } + + return variants[m_variant]; +} + + +void xmrig::Algorithm::parseAlgorithm(const char *algo) +{ + m_algo = INVALID_ALGO; + m_variant = VARIANT_AUTO; + + assert(algo != nullptr); + if (algo == nullptr) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { + if ((strcasecmp(algo, algorithms[i].name) == 0) || (strcasecmp(algo, algorithms[i].shortName) == 0)) { + m_algo = algorithms[i].algo; + m_variant = algorithms[i].variant; + break; + } + } + + if (m_algo == INVALID_ALGO) { + assert(false); + } +} + + +void xmrig::Algorithm::parseVariant(const char *variant) +{ + m_variant = VARIANT_AUTO; + + for (size_t i = 0; i < ARRAY_SIZE(variants); i++) { + if (strcasecmp(variant, variants[i]) == 0) { + m_variant = static_cast(i); + break; + } + } +} + + +void xmrig::Algorithm::parseVariant(int variant) +{ + assert(variant >= -1 && variant <= 2); + + switch (variant) { + case -1: + case 0: + case 1: + m_variant = static_cast(variant); + break; + + case 2: + m_variant = VARIANT_2; + break; + + default: + break; + } +} + + +void xmrig::Algorithm::setAlgo(Algo algo) +{ + m_algo = algo; +} + + +#ifdef XMRIG_PROXY_PROJECT +void xmrig::Algorithm::parseXmrStakAlgorithm(const char *algo) +{ + m_algo = INVALID_ALGO; + m_variant = VARIANT_AUTO; + + assert(algo != nullptr); + if (algo == nullptr) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(xmrStakAlgorithms); i++) { + if (strcasecmp(algo, xmrStakAlgorithms[i].name) == 0) { + m_algo = xmrStakAlgorithms[i].algo; + m_variant = xmrStakAlgorithms[i].variant; + break; + } + } + + if (m_algo == INVALID_ALGO) { + assert(false); + } +} +#endif + + +const char *xmrig::Algorithm::name(bool shortName) const +{ + for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { + if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { + return shortName ? algorithms[i].shortName : algorithms[i].name; + } + } + + return "invalid"; +} diff --git a/src/common/crypto/Algorithm.h b/src/common/crypto/Algorithm.h new file mode 100644 index 00000000..731fa793 --- /dev/null +++ b/src/common/crypto/Algorithm.h @@ -0,0 +1,92 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ALGORITHM_H +#define XMRIG_ALGORITHM_H + + +#include + + +#include "common/xmrig.h" + + +namespace xmrig { + + +class Algorithm +{ +public: + inline Algorithm() : + m_algo(INVALID_ALGO), + m_variant(VARIANT_AUTO) + {} + + inline Algorithm(Algo algo, Variant variant) : + m_variant(variant) + { + setAlgo(algo); + } + + inline Algorithm(const char *algo) + { + parseAlgorithm(algo); + } + + bool isEqual(const Algorithm &other) const { return m_algo == other.m_algo && m_variant == other.m_variant; } + inline Algo algo() const { return m_algo; } + inline const char *name() const { return name(false); } + inline const char *shortName() const { return name(true); } + inline Variant variant() const { return m_variant; } + inline void setVariant(Variant variant) { m_variant = variant; } + + inline bool operator!=(const Algorithm &other) const { return !isEqual(other); } + inline bool operator==(const Algorithm &other) const { return isEqual(other); } + + bool isValid() const; + const char *variantName() const; + void parseAlgorithm(const char *algo); + void parseVariant(const char *variant); + void parseVariant(int variant); + void setAlgo(Algo algo); + +# ifdef XMRIG_PROXY_PROJECT + void parseXmrStakAlgorithm(const char *algo); +# endif + +private: + const char *name(bool shortName) const; + + Algo m_algo; + Variant m_variant; +}; + + +typedef std::vector Algorithms; + + +} /* namespace xmrig */ + +#endif /* __ALGORITHM_H__ */ diff --git a/src/common/crypto/keccak.cpp b/src/common/crypto/keccak.cpp new file mode 100644 index 00000000..0219ce36 --- /dev/null +++ b/src/common/crypto/keccak.cpp @@ -0,0 +1,200 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2011 Markku-Juhani O. Saarinen + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "common/crypto/keccak.h" + + +#define HASH_DATA_AREA 136 +#define KECCAK_ROUNDS 24 + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +const uint64_t keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + +// update the state with given number of rounds + +void xmrig::keccakf(uint64_t st[25], int rounds) +{ + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; ++round) { + + // Theta + bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; + bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; + bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; + bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; + bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; + + for (i = 0; i < 5; ++i) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + st[i ] ^= t; + st[i + 5] ^= t; + st[i + 10] ^= t; + st[i + 15] ^= t; + st[i + 20] ^= t; + } + + // Rho Pi + t = st[1]; + st[ 1] = ROTL64(st[ 6], 44); + st[ 6] = ROTL64(st[ 9], 20); + st[ 9] = ROTL64(st[22], 61); + st[22] = ROTL64(st[14], 39); + st[14] = ROTL64(st[20], 18); + st[20] = ROTL64(st[ 2], 62); + st[ 2] = ROTL64(st[12], 43); + st[12] = ROTL64(st[13], 25); + st[13] = ROTL64(st[19], 8); + st[19] = ROTL64(st[23], 56); + st[23] = ROTL64(st[15], 41); + st[15] = ROTL64(st[ 4], 27); + st[ 4] = ROTL64(st[24], 14); + st[24] = ROTL64(st[21], 2); + st[21] = ROTL64(st[ 8], 55); + st[ 8] = ROTL64(st[16], 45); + st[16] = ROTL64(st[ 5], 36); + st[ 5] = ROTL64(st[ 3], 28); + st[ 3] = ROTL64(st[18], 21); + st[18] = ROTL64(st[17], 15); + st[17] = ROTL64(st[11], 10); + st[11] = ROTL64(st[ 7], 6); + st[ 7] = ROTL64(st[10], 3); + st[10] = ROTL64(t, 1); + + // Chi + // unrolled loop, where only last iteration is different + j = 0; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 5; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 10; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 15; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 20; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + bc[2] = st[j + 2]; + bc[3] = st[j + 3]; + bc[4] = st[j + 4]; + + st[j ] ^= (~bc[1]) & bc[2]; + st[j + 1] ^= (~bc[2]) & bc[3]; + st[j + 2] ^= (~bc[3]) & bc[4]; + st[j + 3] ^= (~bc[4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +// compute a keccak hash (md) of given byte length from "in" +typedef uint64_t state_t[25]; + + +void xmrig::keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) +{ + state_t st; + uint8_t temp[144]; + int i, rsiz, rsizw; + + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) { + st[i] ^= ((uint64_t *) in)[i]; + } + + xmrig::keccakf(st, KECCAK_ROUNDS); + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) { + st[i] ^= ((uint64_t *) temp)[i]; + } + + keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); +} diff --git a/src/common/crypto/keccak.h b/src/common/crypto/keccak.h new file mode 100644 index 00000000..6121044a --- /dev/null +++ b/src/common/crypto/keccak.h @@ -0,0 +1,55 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2011 Markku-Juhani O. Saarinen + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef XMRIG_KECCAK_H +#define XMRIG_KECCAK_H + +#include +#include + + +namespace xmrig { + +// compute a keccak hash (md) of given byte length from "in" +void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); + + +inline void keccak(const uint8_t *in, size_t inlen, uint8_t *md) +{ + keccak(in, static_cast(inlen), md, 200); +} + + +inline void keccak(const char *in, size_t inlen, uint8_t *md) +{ + keccak(reinterpret_cast(in), static_cast(inlen), md, 200); +} + +// update the state +void keccakf(uint64_t st[25], int norounds); + +} /* namespace xmrig */ + +#endif /* XMRIG_KECCAK_H */ diff --git a/src/common/interfaces/IClientListener.h b/src/common/interfaces/IClientListener.h new file mode 100644 index 00000000..f6e7fd3c --- /dev/null +++ b/src/common/interfaces/IClientListener.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ICLIENTLISTENER_H__ +#define __ICLIENTLISTENER_H__ + + +#include + + +class Client; +class Job; +class SubmitResult; + + +class IClientListener +{ +public: + virtual ~IClientListener() {} + + virtual void onClose(Client *client, int failures) = 0; + virtual void onJobReceived(Client *client, const Job &job) = 0; + virtual void onLoginSuccess(Client *client) = 0; + virtual void onResultAccepted(Client *client, const SubmitResult &result, const char *error) = 0; +}; + + +#endif // __ICLIENTLISTENER_H__ diff --git a/src/common/interfaces/IConfig.h b/src/common/interfaces/IConfig.h new file mode 100644 index 00000000..69f2ffab --- /dev/null +++ b/src/common/interfaces/IConfig.h @@ -0,0 +1,140 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ICONFIG_H +#define XMRIG_ICONFIG_H + + +#include "common/crypto/Algorithm.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class IConfig +{ +public: + enum Keys { + // common + AlgorithmKey = 'a', + ApiAccessTokenKey = 4001, + ApiIPv6Key = 4003, + ApiPort = 4000, + ApiRestrictedKey = 4004, + ApiWorkerIdKey = 4002, + ApiIdKey = 4005, + BackgroundKey = 'B', + ColorKey = 1002, + ConfigKey = 'c', + DonateLevelKey = 1003, + HelpKey = 'h', + KeepAliveKey = 'k', + LogFileKey = 'l', + PasswordKey = 'p', + RetriesKey = 'r', + RetryPauseKey = 'R', + RigIdKey = 1012, + SyslogKey = 'S', + UrlKey = 'o', + UserAgentKey = 1008, + UserKey = 'u', + UserpassKey = 'O', + VariantKey = 1010, + VerboseKey = 1100, + VersionKey = 'V', + WatchKey = 1105, + TlsKey = 1013, + FingerprintKey = 1014, + AutoSaveKey = 1016, + + // xmrig common + CPUPriorityKey = 1021, + NicehashKey = 1006, + PrintTimeKey = 1007, + + // xmrig cpu + AVKey = 'v', + CPUAffinityKey = 1020, + DryRunKey = 5000, + HugePagesKey = 1009, + MaxCPUUsageKey = 1004, + SafeKey = 1005, + ThreadsKey = 't', + HardwareAESKey = 1011, + AssemblyKey = 1015, + + // xmrig amd + OclPlatformKey = 1400, + OclAffinityKey = 1401, + OclDevicesKey = 1402, + OclLaunchKey = 1403, + OclCacheKey = 1404, + OclPrintKey = 1405, + OclLoaderKey = 1406, + OclSridedIndexKey = 1407, + OclMemChunkKey = 1408, + OclUnrollKey = 1409, + OclCompModeKey = 1410, + + // xmrig-proxy + AccessLogFileKey = 'A', + BindKey = 'b', + CoinKey = 1104, + CustomDiffKey = 1102, + DebugKey = 1101, + ModeKey = 'm', + PoolCoinKey = 'C', + ReuseTimeoutKey = 1106, + WorkersKey = 1103, + WorkersAdvKey = 1107, + + // xmrig nvidia + CudaMaxThreadsKey = 1200, + CudaBFactorKey = 1201, + CudaBSleepKey = 1202, + CudaDevicesKey = 1203, + CudaLaunchKey = 1204, + CudaAffinityKey = 1205, + CudaMaxUsageKey = 1206, + }; + + virtual ~IConfig() {} + + virtual bool finalize() = 0; + virtual bool isWatch() const = 0; + virtual bool parseBoolean(int key, bool enable) = 0; + virtual bool parseString(int key, const char *arg) = 0; + virtual bool parseUint64(int key, uint64_t arg) = 0; + virtual bool save() = 0; + virtual const Algorithm &algorithm() const = 0; + virtual const char *fileName() const = 0; + virtual void getJSON(rapidjson::Document &doc) const = 0; + virtual void parseJSON(const rapidjson::Document &doc) = 0; + virtual void setFileName(const char *fileName) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_ICONFIG_H diff --git a/src/common/interfaces/IConfigCreator.h b/src/common/interfaces/IConfigCreator.h new file mode 100644 index 00000000..597a6b74 --- /dev/null +++ b/src/common/interfaces/IConfigCreator.h @@ -0,0 +1,45 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ICONFIGCREATOR_H__ +#define __ICONFIGCREATOR_H__ + + +namespace xmrig { + + +class IConfig; + + +class IConfigCreator +{ +public: + virtual ~IConfigCreator() {} + + virtual IConfig *create() const = 0; +}; + + +} /* namespace xmrig */ + + +#endif // __ICONFIGCREATOR_H__ diff --git a/src/common/interfaces/IConsoleListener.h b/src/common/interfaces/IConsoleListener.h new file mode 100644 index 00000000..723f87df --- /dev/null +++ b/src/common/interfaces/IConsoleListener.h @@ -0,0 +1,37 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ICONSOLELISTENER_H__ +#define __ICONSOLELISTENER_H__ + + +class IConsoleListener +{ +public: + virtual ~IConsoleListener() {} + + virtual void onConsoleCommand(char command) = 0; +}; + + +#endif // __ICONSOLELISTENER_H__ diff --git a/src/common/interfaces/IControllerListener.h b/src/common/interfaces/IControllerListener.h new file mode 100644 index 00000000..35249bcd --- /dev/null +++ b/src/common/interfaces/IControllerListener.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ICONTROLLERLISTENER_H +#define XMRIG_ICONTROLLERLISTENER_H + + +namespace xmrig { + + +class Config; + + +class IControllerListener +{ +public: + virtual ~IControllerListener() {} + + virtual void onConfigChanged(Config *config, Config *previousConfig) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_ICONTROLLERLISTENER_H diff --git a/src/common/interfaces/ICpuInfo.h b/src/common/interfaces/ICpuInfo.h new file mode 100644 index 00000000..267616d0 --- /dev/null +++ b/src/common/interfaces/ICpuInfo.h @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPUINFO_H +#define XMRIG_CPUINFO_H + + +#include +#include + + +#include "common/xmrig.h" + + +namespace xmrig { + + +class ICpuInfo +{ +public: + virtual ~ICpuInfo() {} + + virtual bool hasAES() const = 0; + virtual bool isSupported() const = 0; + virtual bool isX64() const = 0; + virtual const char *brand() const = 0; + virtual int32_t cores() const = 0; + virtual int32_t L2() const = 0; + virtual int32_t L3() const = 0; + virtual int32_t nodes() const = 0; + virtual int32_t sockets() const = 0; + virtual int32_t threads() const = 0; + virtual size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; + virtual xmrig::Assembly assembly() const = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_CPUINFO_H diff --git a/src/common/interfaces/ILogBackend.h b/src/common/interfaces/ILogBackend.h new file mode 100644 index 00000000..85a04e93 --- /dev/null +++ b/src/common/interfaces/ILogBackend.h @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ILOGBACKEND_H__ +#define __ILOGBACKEND_H__ + + +#include +#include + + +class ILogBackend +{ +public: + enum Level { + ERR, + WARNING, + NOTICE, + INFO, + DEBUG + }; + +# ifdef APP_DEBUG + constexpr static const size_t kBufferSize = 1024; +# else + constexpr static const size_t kBufferSize = 512; +# endif + + virtual ~ILogBackend() {} + + virtual void message(Level level, const char* fmt, va_list args) = 0; + virtual void text(const char* fmt, va_list args) = 0; +}; + + +#endif // __ILOGBACKEND_H__ diff --git a/src/common/interfaces/IStrategy.h b/src/common/interfaces/IStrategy.h new file mode 100644 index 00000000..9f2795f9 --- /dev/null +++ b/src/common/interfaces/IStrategy.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ISTRATEGY_H__ +#define __ISTRATEGY_H__ + + +#include + + +class JobResult; + + +class IStrategy +{ +public: + virtual ~IStrategy() {} + + virtual bool isActive() const = 0; + virtual int64_t submit(const JobResult &result) = 0; + virtual void connect() = 0; + virtual void resume() = 0; + virtual void stop() = 0; + virtual void tick(uint64_t now) = 0; +}; + + +#endif // __ISTRATEGY_H__ diff --git a/src/common/interfaces/IStrategyListener.h b/src/common/interfaces/IStrategyListener.h new file mode 100644 index 00000000..9f2c4487 --- /dev/null +++ b/src/common/interfaces/IStrategyListener.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ISTRATEGYLISTENER_H__ +#define __ISTRATEGYLISTENER_H__ + + +#include + + +class Client; +class IStrategy; +class Job; +class SubmitResult; + + +class IStrategyListener +{ +public: + virtual ~IStrategyListener() {} + + virtual void onActive(IStrategy *strategy, Client *client) = 0; + virtual void onJob(IStrategy *strategy, Client *client, const Job &job) = 0; + virtual void onPause(IStrategy *strategy) = 0; + virtual void onResultAccepted(IStrategy *strategy, Client *client, const SubmitResult &result, const char *error) = 0; +}; + + +#endif // __ISTRATEGYLISTENER_H__ diff --git a/src/common/interfaces/IWatcherListener.h b/src/common/interfaces/IWatcherListener.h new file mode 100644 index 00000000..bfafb9a0 --- /dev/null +++ b/src/common/interfaces/IWatcherListener.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __IWATCHERLISTENER_H__ +#define __IWATCHERLISTENER_H__ + + +namespace xmrig { + + +class IConfig; + + +class IWatcherListener +{ +public: + virtual ~IWatcherListener() {} + + virtual void onNewConfig(IConfig *config) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // __IWATCHERLISTENER_H__ diff --git a/src/common/log/BasicLog.cpp b/src/common/log/BasicLog.cpp new file mode 100644 index 00000000..cb4defcd --- /dev/null +++ b/src/common/log/BasicLog.cpp @@ -0,0 +1,89 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +# include +#endif + + +#include "common/log/BasicLog.h" +#include "common/log/Log.h" + + +BasicLog::BasicLog() +{ +} + + +void BasicLog::message(Level level, const char* fmt, va_list args) +{ + time_t now = time(nullptr); + tm stime; + +# ifdef _WIN32 + localtime_s(&stime, &now); +# else + localtime_r(&now, &stime); +# endif + + snprintf(m_fmt, sizeof(m_fmt) - 1, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s", + stime.tm_year + 1900, + stime.tm_mon + 1, + stime.tm_mday, + stime.tm_hour, + stime.tm_min, + stime.tm_sec, + Log::colorByLevel(level, false), + fmt, + Log::endl(false) + ); + + print(args); +} + + +void BasicLog::text(const char* fmt, va_list args) +{ + snprintf(m_fmt, sizeof(m_fmt) - 1, "%s%s", fmt, Log::endl(false)); + + print(args); +} + + +void BasicLog::print(va_list args) +{ + if (vsnprintf(m_buf, sizeof(m_buf) - 1, m_fmt, args) <= 0) { + return; + } + + fputs(m_buf, stdout); + fflush(stdout); +} diff --git a/src/common/log/BasicLog.h b/src/common/log/BasicLog.h new file mode 100644 index 00000000..523538e9 --- /dev/null +++ b/src/common/log/BasicLog.h @@ -0,0 +1,55 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __BASICLOG_H__ +#define __BASICLOG_H__ + + +#include + + +#include "common/interfaces/ILogBackend.h" + + +namespace xmrig { + class Controller; +} + + +class BasicLog : public ILogBackend +{ +public: + BasicLog(); + + void message(Level level, const char *fmt, va_list args) override; + void text(const char *fmt, va_list args) override; + +private: + bool isWritable() const; + void print(va_list args); + + char m_buf[kBufferSize]; + char m_fmt[256]; +}; + +#endif /* __BASICLOG_H__ */ diff --git a/src/common/log/ConsoleLog.cpp b/src/common/log/ConsoleLog.cpp new file mode 100644 index 00000000..6cf61980 --- /dev/null +++ b/src/common/log/ConsoleLog.cpp @@ -0,0 +1,131 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +# include +#endif + + +#include "common/log/ConsoleLog.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" + + +ConsoleLog::ConsoleLog(xmrig::Controller *controller) : + m_stream(nullptr), + m_controller(controller) +{ + if (uv_tty_init(uv_default_loop(), &m_tty, 1, 0) < 0) { + controller->config()->setColors(false); + return; + } + + uv_tty_set_mode(&m_tty, UV_TTY_MODE_NORMAL); + m_uvBuf.base = m_buf; + m_stream = reinterpret_cast(&m_tty); + +# ifdef WIN32 + HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); + if (handle != INVALID_HANDLE_VALUE) { + DWORD mode = 0; + if (GetConsoleMode(handle, &mode)) { + mode &= ~ENABLE_QUICK_EDIT_MODE; + SetConsoleMode(handle, mode | ENABLE_EXTENDED_FLAGS); + } + } +# endif +} + + +void ConsoleLog::message(Level level, const char* fmt, va_list args) +{ + time_t now = time(nullptr); + tm stime; + +# ifdef _WIN32 + localtime_s(&stime, &now); +# else + localtime_r(&now, &stime); +# endif + + const bool isColors = m_controller->config()->isColors(); + + snprintf(m_fmt, sizeof(m_fmt) - 1, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s", + stime.tm_year + 1900, + stime.tm_mon + 1, + stime.tm_mday, + stime.tm_hour, + stime.tm_min, + stime.tm_sec, + Log::colorByLevel(level, isColors), + fmt, + Log::endl(isColors) + ); + + print(args); +} + + +void ConsoleLog::text(const char* fmt, va_list args) +{ + snprintf(m_fmt, sizeof(m_fmt) - 1, "%s%s", fmt, Log::endl(m_controller->config()->isColors())); + + print(args); +} + + +bool ConsoleLog::isWritable() const +{ + if (!m_stream || uv_is_writable(m_stream) != 1) { + return false; + } + + const uv_handle_type type = uv_guess_handle(1); + return type == UV_TTY || type == UV_NAMED_PIPE; +} + + +void ConsoleLog::print(va_list args) +{ + m_uvBuf.len = vsnprintf(m_buf, sizeof(m_buf) - 1, m_fmt, args); + if (m_uvBuf.len <= 0) { + return; + } + + if (!isWritable()) { + fputs(m_buf, stdout); + fflush(stdout); + } + else { + uv_try_write(m_stream, &m_uvBuf, 1); + } +} diff --git a/src/common/log/ConsoleLog.h b/src/common/log/ConsoleLog.h new file mode 100644 index 00000000..bac09a53 --- /dev/null +++ b/src/common/log/ConsoleLog.h @@ -0,0 +1,59 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONSOLELOG_H__ +#define __CONSOLELOG_H__ + + +#include + + +#include "common/interfaces/ILogBackend.h" + + +namespace xmrig { + class Controller; +} + + +class ConsoleLog : public ILogBackend +{ +public: + ConsoleLog(xmrig::Controller *controller); + + void message(Level level, const char *fmt, va_list args) override; + void text(const char *fmt, va_list args) override; + +private: + bool isWritable() const; + void print(va_list args); + + char m_buf[kBufferSize]; + char m_fmt[256]; + uv_buf_t m_uvBuf; + uv_stream_t *m_stream; + uv_tty_t m_tty; + xmrig::Controller *m_controller; +}; + +#endif /* __CONSOLELOG_H__ */ diff --git a/src/common/log/FileLog.cpp b/src/common/log/FileLog.cpp new file mode 100644 index 00000000..9134c7c7 --- /dev/null +++ b/src/common/log/FileLog.cpp @@ -0,0 +1,105 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include + + +#include "common/log/FileLog.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" + + +FileLog::FileLog(xmrig::Controller *controller, const char *fileName) : + m_controller(controller) +{ + uv_fs_t req; + m_file = uv_fs_open(uv_default_loop(), &req, fileName, O_CREAT | O_APPEND | O_WRONLY, 0644, nullptr); + uv_fs_req_cleanup(&req); +} + + +void FileLog::message(Level level, const char* fmt, va_list args) +{ + if (m_file < 0) { + return; + } + + time_t now = time(nullptr); + tm stime; + +# ifdef _WIN32 + localtime_s(&stime, &now); +# else + localtime_r(&now, &stime); +# endif + + const bool isColors = m_controller->config()->isColors(); + + snprintf(m_fmt, sizeof(m_fmt) - 1, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s", + stime.tm_year + 1900, + stime.tm_mon + 1, + stime.tm_mday, + stime.tm_hour, + stime.tm_min, + stime.tm_sec, + Log::colorByLevel(level, isColors), + fmt, + Log::endl(isColors) + ); + + char *buf = new char[kBufferSize]; + const int size = vsnprintf(buf, kBufferSize - 1, m_fmt, args); + + write(buf, size); +} + + +void FileLog::text(const char* fmt, va_list args) +{ + message(INFO, fmt, args); +} + + +void FileLog::onWrite(uv_fs_t *req) +{ + delete [] static_cast(req->data); + + uv_fs_req_cleanup(req); + delete req; +} + + +void FileLog::write(char *data, size_t size) +{ + uv_buf_t buf = uv_buf_init(data, (unsigned int) size); + uv_fs_t *req = new uv_fs_t; + req->data = buf.base; + + uv_fs_write(uv_default_loop(), req, m_file, &buf, 1, -1, FileLog::onWrite); +} diff --git a/src/common/log/FileLog.h b/src/common/log/FileLog.h new file mode 100644 index 00000000..8a58d4e4 --- /dev/null +++ b/src/common/log/FileLog.h @@ -0,0 +1,57 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __FILELOG_H__ +#define __FILELOG_H__ + + +#include + + +#include "common/interfaces/ILogBackend.h" + + +namespace xmrig { + class Controller; +} + + +class FileLog : public ILogBackend +{ +public: + FileLog(xmrig::Controller *controller, const char *fileName); + + void message(Level level, const char* fmt, va_list args) override; + void text(const char* fmt, va_list args) override; + +private: + static void onWrite(uv_fs_t *req); + + void write(char *data, size_t size); + + char m_fmt[256]; + int m_file; + xmrig::Controller *m_controller; +}; + +#endif /* __FILELOG_H__ */ diff --git a/src/common/log/Log.cpp b/src/common/log/Log.cpp new file mode 100644 index 00000000..2af90209 --- /dev/null +++ b/src/common/log/Log.cpp @@ -0,0 +1,126 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include + + +#include "common/interfaces/ILogBackend.h" +#include "common/log/BasicLog.h" +#include "common/log/Log.h" + + +Log *Log::m_self = nullptr; + + +static const char *colors[5] = { + "\x1B[0;31m", /* ERR */ + "\x1B[0;33m", /* WARNING */ + "\x1B[1;37m", /* NOTICE */ + "", /* INFO */ +# ifdef WIN32 + "\x1B[1;30m" /* DEBUG */ +# else + "\x1B[90m" /* DEBUG */ +# endif +}; + + +void Log::message(ILogBackend::Level level, const char* fmt, ...) +{ + uv_mutex_lock(&m_mutex); + + va_list args; + va_list copy; + va_start(args, fmt); + + for (ILogBackend *backend : m_backends) { + va_copy(copy, args); + backend->message(level, fmt, copy); + va_end(copy); + } + + va_end(args); + + uv_mutex_unlock(&m_mutex); +} + + +void Log::text(const char* fmt, ...) +{ + uv_mutex_lock(&m_mutex); + + va_list args; + va_list copy; + va_start(args, fmt); + + for (ILogBackend *backend : m_backends) { + va_copy(copy, args); + backend->text(fmt, copy); + va_end(copy); + } + + va_end(args); + + uv_mutex_unlock(&m_mutex); +} + + +const char *Log::colorByLevel(ILogBackend::Level level, bool isColors) +{ + if (!isColors) { + return ""; + } + + return colors[level]; +} + + +const char *Log::endl(bool isColors) +{ +# ifdef _WIN32 + return isColors ? "\x1B[0m\r\n" : "\r\n"; +# else + return isColors ? "\x1B[0m\n" : "\n"; +# endif +} + + +void Log::defaultInit() +{ + m_self = new Log(); + + add(new BasicLog()); +} + + +Log::~Log() +{ + for (auto backend : m_backends) { + delete backend; + } +} diff --git a/src/common/log/Log.h b/src/common/log/Log.h new file mode 100644 index 00000000..2774ae0c --- /dev/null +++ b/src/common/log/Log.h @@ -0,0 +1,101 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + + +#include +#include +#include + + +#include "common/interfaces/ILogBackend.h" + + +class Log +{ +public: + static inline Log* i() { if (!m_self) { defaultInit(); } return m_self; } + static inline void add(ILogBackend *backend) { i()->m_backends.push_back(backend); } + static inline void init() { if (!m_self) { new Log(); } } + static inline void release() { assert(m_self != nullptr); delete m_self; } + + void message(ILogBackend::Level level, const char* fmt, ...); + void text(const char* fmt, ...); + + static const char *colorByLevel(ILogBackend::Level level, bool isColors = true); + static const char *endl(bool isColors = true); + static void defaultInit(); + +private: + inline Log() { + assert(m_self == nullptr); + + uv_mutex_init(&m_mutex); + + m_self = this; + } + + ~Log(); + + static Log *m_self; + std::vector m_backends; + uv_mutex_t m_mutex; +}; + + +#define RED_BOLD(x) "\x1B[1;31m" x "\x1B[0m" +#define RED(x) "\x1B[0;31m" x "\x1B[0m" +#define GREEN_BOLD(x) "\x1B[1;32m" x "\x1B[0m" +#define GREEN(x) "\x1B[0;32m" x "\x1B[0m" +#define YELLOW(x) "\x1B[0;33m" x "\x1B[0m" +#define YELLOW_BOLD(x) "\x1B[1;33m" x "\x1B[0m" +#define MAGENTA_BOLD(x) "\x1B[1;35m" x "\x1B[0m" +#define MAGENTA(x) "\x1B[0;35m" x "\x1B[0m" +#define CYAN_BOLD(x) "\x1B[1;36m" x "\x1B[0m" +#define CYAN(x) "\x1B[0;36m" x "\x1B[0m" +#define WHITE_BOLD(x) "\x1B[1;37m" x "\x1B[0m" +#define WHITE(x) "\x1B[0;37m" x "\x1B[0m" + + +#define LOG_ERR(x, ...) Log::i()->message(ILogBackend::ERR, x, ##__VA_ARGS__) +#define LOG_WARN(x, ...) Log::i()->message(ILogBackend::WARNING, x, ##__VA_ARGS__) +#define LOG_NOTICE(x, ...) Log::i()->message(ILogBackend::NOTICE, x, ##__VA_ARGS__) +#define LOG_INFO(x, ...) Log::i()->message(ILogBackend::INFO, x, ##__VA_ARGS__) + +#ifdef APP_DEBUG +# define LOG_DEBUG(x, ...) Log::i()->message(ILogBackend::DEBUG, x, ##__VA_ARGS__) +#else +# define LOG_DEBUG(x, ...) +#endif + +#if defined(APP_DEBUG) || defined(APP_DEVEL) +# define LOG_DEBUG_ERR(x, ...) Log::i()->message(ILogBackend::ERR, x, ##__VA_ARGS__) +# define LOG_DEBUG_WARN(x, ...) Log::i()->message(ILogBackend::WARNING, x, ##__VA_ARGS__) +#else +# define LOG_DEBUG_ERR(x, ...) +# define LOG_DEBUG_WARN(x, ...) +#endif + +#endif /* __LOG_H__ */ diff --git a/src/common/log/SysLog.cpp b/src/common/log/SysLog.cpp new file mode 100644 index 00000000..bcb96394 --- /dev/null +++ b/src/common/log/SysLog.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/log/SysLog.h" +#include "version.h" + + +SysLog::SysLog() +{ + openlog(APP_ID, LOG_PID, LOG_USER); +} + + +void SysLog::message(Level level, const char *fmt, va_list args) +{ + vsyslog(static_cast(level), fmt, args); +} + + +void SysLog::text(const char *fmt, va_list args) +{ + vsyslog(LOG_INFO, fmt, args); +} diff --git a/src/common/log/SysLog.h b/src/common/log/SysLog.h new file mode 100644 index 00000000..5cfeefcd --- /dev/null +++ b/src/common/log/SysLog.h @@ -0,0 +1,40 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SYSLOG_H__ +#define __SYSLOG_H__ + + +#include "common/interfaces/ILogBackend.h" + + +class SysLog : public ILogBackend +{ +public: + SysLog(); + + void message(Level level, const char *fmt, va_list args) override; + void text(const char *fmt, va_list args) override; +}; + +#endif /* __SYSLOG_BACKEND_H__ */ diff --git a/src/common/net/Client.cpp b/src/common/net/Client.cpp new file mode 100644 index 00000000..1d1d86c7 --- /dev/null +++ b/src/common/net/Client.cpp @@ -0,0 +1,1016 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + + +#ifndef XMRIG_NO_TLS +# include +# include +# include "common/net/Tls.h" +#endif + + +#include "common/interfaces/IClientListener.h" +#include "common/log/Log.h" +#include "common/net/Client.h" +#include "net/JobResult.h" +#include "rapidjson/document.h" +#include "rapidjson/error/en.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + + +#ifdef _MSC_VER +# define strncasecmp(x,y,z) _strnicmp(x,y,z) +#endif + + +int64_t Client::m_sequence = 1; +xmrig::Storage Client::m_storage; + + +#ifdef APP_DEBUG +static const char *states[] = { + "unconnected", + "host-lookup", + "connecting", + "connected", + "closing" +}; +#endif + + +Client::Client(int id, const char *agent, IClientListener *listener) : + m_ipv6(false), + m_nicehash(false), + m_quiet(false), + m_agent(agent), + m_listener(listener), + m_extensions(0), + m_id(id), + m_retries(5), + m_retryPause(5000), + m_failures(0), + m_recvBufPos(0), + m_state(UnconnectedState), + m_tls(nullptr), + m_expire(0), + m_jobs(0), + m_keepAlive(0), + m_key(0), + m_stream(nullptr), + m_socket(nullptr) +{ + m_key = m_storage.add(this); + + memset(m_ip, 0, sizeof(m_ip)); + memset(&m_hints, 0, sizeof(m_hints)); + + m_resolver.data = m_storage.ptr(m_key); + + m_hints.ai_family = AF_UNSPEC; + m_hints.ai_socktype = SOCK_STREAM; + m_hints.ai_protocol = IPPROTO_TCP; + + m_recvBuf.base = m_buf; + m_recvBuf.len = sizeof(m_buf); +} + + +Client::~Client() +{ + delete m_socket; +} + + +void Client::connect() +{ +# ifndef XMRIG_NO_TLS + if (m_pool.isTLS()) { + m_tls = new Tls(this); + } +# endif + + resolve(m_pool.host()); +} + + +/** + * @brief Connect to server. + * + * @param url + */ +void Client::connect(const Pool &url) +{ + setPool(url); + connect(); +} + + +void Client::deleteLater() +{ + if (!m_listener) { + return; + } + + m_listener = nullptr; + + if (!disconnect()) { + m_storage.remove(m_key); + } +} + + + +void Client::setPool(const Pool &pool) +{ + if (!pool.isValid()) { + return; + } + + m_pool = pool; +} + + +void Client::tick(uint64_t now) +{ + if (m_state == ConnectedState) { + if (m_expire && now > m_expire) { + LOG_DEBUG_ERR("[%s] timeout", m_pool.url()); + close(); + } + else if (m_keepAlive && now > m_keepAlive) { + ping(); + } + } + + if (m_expire && now > m_expire && m_state == ConnectingState) { + connect(); + } +} + + +bool Client::disconnect() +{ + m_keepAlive = 0; + m_expire = 0; + m_failures = -1; + + return close(); +} + + +const char *Client::tlsFingerprint() const +{ +# ifndef XMRIG_NO_TLS + if (isTLS() && m_pool.fingerprint() == nullptr) { + return m_tls->fingerprint(); + } +# endif + + return nullptr; +} + + +const char *Client::tlsVersion() const +{ +# ifndef XMRIG_NO_TLS + if (isTLS()) { + return m_tls->version(); + } +# endif + + return nullptr; +} + + +int64_t Client::submit(const JobResult &result) +{ + using namespace rapidjson; + +# ifdef XMRIG_PROXY_PROJECT + const char *nonce = result.nonce; + const char *data = result.result; +# else + char *nonce = m_sendBuf; + char *data = m_sendBuf + 16; + + Job::toHex(reinterpret_cast(&result.nonce), 4, nonce); + nonce[8] = '\0'; + + Job::toHex(result.result, 32, data); + data[64] = '\0'; +# endif + + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + doc.AddMember("id", m_sequence, allocator); + doc.AddMember("jsonrpc", "2.0", allocator); + doc.AddMember("method", "submit", allocator); + + Value params(kObjectType); + params.AddMember("id", StringRef(m_rpcId.data()), allocator); + params.AddMember("job_id", StringRef(result.jobId.data()), allocator); + params.AddMember("nonce", StringRef(nonce), allocator); + params.AddMember("result", StringRef(data), allocator); + + if (m_extensions & AlgoExt) { + params.AddMember("algo", StringRef(result.algorithm.shortName()), allocator); + } + + doc.AddMember("params", params, allocator); + +# ifdef XMRIG_PROXY_PROJECT + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), result.id); +# else + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff()); +# endif + + return send(doc); +} + + +bool Client::close() +{ + if (m_state == ClosingState) { + return m_socket != nullptr; + } + + if (m_state == UnconnectedState || m_socket == nullptr) { + return false; + } + + setState(ClosingState); + + if (uv_is_closing(reinterpret_cast(m_socket)) == 0) { + uv_close(reinterpret_cast(m_socket), Client::onClose); + } + + return true; +} + + +bool Client::isCriticalError(const char *message) +{ + if (!message) { + return false; + } + + if (strncasecmp(message, "Unauthenticated", 15) == 0) { + return true; + } + + if (strncasecmp(message, "your IP is banned", 17) == 0) { + return true; + } + + if (strncasecmp(message, "IP Address currently banned", 27) == 0) { + return true; + } + + return false; +} + + +bool Client::isTLS() const +{ +# ifndef XMRIG_NO_TLS + return m_pool.isTLS() && m_tls; +# else + return false; +# endif +} + + +bool Client::parseJob(const rapidjson::Value ¶ms, int *code) +{ + if (!params.IsObject()) { + *code = 2; + return false; + } + + Job job(m_id, m_nicehash, m_pool.algorithm(), m_rpcId); + + if (!job.setId(params["job_id"].GetString())) { + *code = 3; + return false; + } + + if (!job.setBlob(params["blob"].GetString())) { + *code = 4; + return false; + } + + if (!job.setTarget(params["target"].GetString())) { + *code = 5; + return false; + } + + if (params.HasMember("algo")) { + job.setAlgorithm(params["algo"].GetString()); + } + + if (params.HasMember("variant")) { + const rapidjson::Value &variant = params["variant"]; + + if (variant.IsInt()) { + job.setVariant(variant.GetInt()); + } + else if (variant.IsString()){ + job.setVariant(variant.GetString()); + } + } + + if (!verifyAlgorithm(job.algorithm())) { + *code = 6; + + close(); + return false; + } + + if (m_job != job) { + m_jobs++; + m_job = std::move(job); + return true; + } + + if (m_jobs == 0) { // https://github.com/xmrig/xmrig/issues/459 + return false; + } + + if (!isQuiet()) { + LOG_WARN("[%s] duplicate job received, reconnect", m_pool.url()); + } + + close(); + return false; +} + + +bool Client::parseLogin(const rapidjson::Value &result, int *code) +{ + if (!m_rpcId.setId(result["id"].GetString())) { + *code = 1; + return false; + } + + m_nicehash = m_pool.isNicehash(); + + if (result.HasMember("extensions")) { + parseExtensions(result["extensions"]); + } + + const bool rc = parseJob(result["job"], code); + m_jobs = 0; + + return rc; +} + + +bool Client::send(BIO *bio) +{ +# ifndef XMRIG_NO_TLS + uv_buf_t buf; + buf.len = BIO_get_mem_data(bio, &buf.base); + + if (buf.len == 0) { + return true; + } + + LOG_DEBUG("[%s] TLS send (%d bytes)", m_pool.url(), static_cast(buf.len)); + + bool result = false; + if (state() == ConnectedState && uv_is_writable(m_stream)) { + result = uv_try_write(m_stream, &buf, 1) > 0; + + if (!result) { + close(); + } + } + else { + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + } + + (void) BIO_reset(bio); + + return result; +# else + return false; +# endif +} + + +bool Client::verifyAlgorithm(const xmrig::Algorithm &algorithm) const +{ +# ifdef XMRIG_PROXY_PROJECT + if (m_pool.algorithm().variant() == xmrig::VARIANT_AUTO || m_id == -1) { + return true; + } +# endif + + if (m_pool.isCompatible(algorithm)) { + return true; + } + + if (isQuiet()) { + return false; + } + + if (algorithm.isValid()) { + LOG_ERR("Incompatible algorithm \"%s\" detected, reconnect", algorithm.name()); + } + else { + LOG_ERR("Unknown/unsupported algorithm detected, reconnect"); + } + + return false; +} + + +int Client::resolve(const char *host) +{ + setState(HostLookupState); + + m_expire = 0; + m_recvBufPos = 0; + + if (m_failures == -1) { + m_failures = 0; + } + + const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, nullptr, &m_hints); + if (r) { + if (!isQuiet()) { + LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_pool.port(), uv_strerror(r)); + } + return 1; + } + + return 0; +} + + +int64_t Client::send(const rapidjson::Document &doc) +{ + using namespace rapidjson; + + StringBuffer buffer(0, 512); + Writer writer(buffer); + doc.Accept(writer); + + const size_t size = buffer.GetSize(); + if (size > (sizeof(m_sendBuf) - 2)) { + LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", m_pool.url(), size, (sizeof(m_sendBuf) - 2)); + close(); + return -1; + } + + memcpy(m_sendBuf, buffer.GetString(), size); + m_sendBuf[size] = '\n'; + m_sendBuf[size + 1] = '\0'; + + return send(size + 1); +} + + +int64_t Client::send(size_t size) +{ + LOG_DEBUG("[%s] send (%d bytes): \"%s\"", m_pool.url(), size, m_sendBuf); + +# ifndef XMRIG_NO_TLS + if (isTLS()) { + if (!m_tls->send(m_sendBuf, size)) { + return -1; + } + } + else +# endif + { + if (state() != ConnectedState || !uv_is_writable(m_stream)) { + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + return -1; + } + + uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); + + if (uv_try_write(m_stream, &buf, 1) < 0) { + close(); + return -1; + } + } + + m_expire = uv_now(uv_default_loop()) + kResponseTimeout; + return m_sequence++; +} + + +void Client::connect(const std::vector &ipv4, const std::vector &ipv6) +{ + addrinfo *addr = nullptr; + m_ipv6 = ipv4.empty() && !ipv6.empty(); + + if (m_ipv6) { + addr = ipv6[ipv6.size() == 1 ? 0 : rand() % ipv6.size()]; + uv_ip6_name(reinterpret_cast(addr->ai_addr), m_ip, 45); + } + else { + addr = ipv4[ipv4.size() == 1 ? 0 : rand() % ipv4.size()]; + uv_ip4_name(reinterpret_cast(addr->ai_addr), m_ip, 16); + } + + connect(addr->ai_addr); +} + + +void Client::connect(sockaddr *addr) +{ + setState(ConnectingState); + + reinterpret_cast(addr)->sin_port = htons(m_pool.port()); + + uv_connect_t *req = new uv_connect_t; + req->data = m_storage.ptr(m_key); + + m_socket = new uv_tcp_t; + m_socket->data = m_storage.ptr(m_key); + + uv_tcp_init(uv_default_loop(), m_socket); + uv_tcp_nodelay(m_socket, 1); + +# ifndef WIN32 + uv_tcp_keepalive(m_socket, 1, 60); +# endif + + uv_tcp_connect(req, m_socket, reinterpret_cast(addr), Client::onConnect); +} + + +void Client::handshake() +{ +# ifndef XMRIG_NO_TLS + if (isTLS()) { + m_expire = uv_now(uv_default_loop()) + kResponseTimeout; + + m_tls->handshake(); + } + else +# endif + { + login(); + } +} + + +void Client::login() +{ + using namespace rapidjson; + m_results.clear(); + + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + doc.AddMember("id", 1, allocator); + doc.AddMember("jsonrpc", "2.0", allocator); + doc.AddMember("method", "login", allocator); + + Value params(kObjectType); + params.AddMember("login", StringRef(m_pool.user()), allocator); + params.AddMember("pass", StringRef(m_pool.password()), allocator); + params.AddMember("agent", StringRef(m_agent), allocator); + + if (m_pool.rigId()) { + params.AddMember("rigid", StringRef(m_pool.rigId()), allocator); + } + +# ifdef XMRIG_PROXY_PROJECT + if (m_pool.algorithm().variant() != xmrig::VARIANT_AUTO) +# endif + { + Value algo(kArrayType); + + for (const auto &a : m_pool.algorithms()) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + params.AddMember("algo", algo, allocator); + } + + doc.AddMember("params", params, allocator); + + send(doc); +} + + +void Client::onClose() +{ + delete m_socket; + + m_stream = nullptr; + m_socket = nullptr; + setState(UnconnectedState); + +# ifndef XMRIG_NO_TLS + if (m_tls) { + delete m_tls; + m_tls = nullptr; + } +# endif + + reconnect(); +} + + +void Client::parse(char *line, size_t len) +{ + startTimeout(); + + line[len - 1] = '\0'; + + LOG_DEBUG("[%s] received (%d bytes): \"%s\"", m_pool.url(), len, line); + + if (len < 32 || line[0] != '{') { + if (!isQuiet()) { + LOG_ERR("[%s] JSON decode failed", m_pool.url()); + } + + return; + } + + rapidjson::Document doc; + if (doc.ParseInsitu(line).HasParseError()) { + if (!isQuiet()) { + LOG_ERR("[%s] JSON decode failed: \"%s\"", m_pool.url(), rapidjson::GetParseError_En(doc.GetParseError())); + } + + return; + } + + if (!doc.IsObject()) { + return; + } + + const rapidjson::Value &id = doc["id"]; + if (id.IsInt64()) { + parseResponse(id.GetInt64(), doc["result"], doc["error"]); + } + else { + parseNotification(doc["method"].GetString(), doc["params"], doc["error"]); + } +} + + +void Client::parseExtensions(const rapidjson::Value &value) +{ + m_extensions = 0; + + if (!value.IsArray()) { + return; + } + + for (const rapidjson::Value &ext : value.GetArray()) { + if (!ext.IsString()) { + continue; + } + + if (strcmp(ext.GetString(), "algo") == 0) { + m_extensions |= AlgoExt; + continue; + } + + if (strcmp(ext.GetString(), "nicehash") == 0) { + m_extensions |= NicehashExt; + m_nicehash = true; + continue; + } + } +} + + +void Client::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error) +{ + if (error.IsObject()) { + if (!isQuiet()) { + LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), error["message"].GetString(), error["code"].GetInt()); + } + return; + } + + if (!method) { + return; + } + + if (strcmp(method, "job") == 0) { + int code = -1; + if (parseJob(params, &code)) { + m_listener->onJobReceived(this, m_job); + } + + return; + } + + LOG_WARN("[%s] unsupported method: \"%s\"", m_pool.url(), method); +} + + +void Client::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) +{ + if (error.IsObject()) { + const char *message = error["message"].GetString(); + + auto it = m_results.find(id); + if (it != m_results.end()) { + it->second.done(); + m_listener->onResultAccepted(this, it->second, message); + m_results.erase(it); + } + else if (!isQuiet()) { + LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), message, error["code"].GetInt()); + } + + if (isCriticalError(message)) { + close(); + } + + return; + } + + if (!result.IsObject()) { + return; + } + + if (id == 1) { + int code = -1; + if (!parseLogin(result, &code)) { + if (!isQuiet()) { + LOG_ERR("[%s] login error code: %d", m_pool.url(), code); + } + + close(); + return; + } + + m_failures = 0; + m_listener->onLoginSuccess(this); + m_listener->onJobReceived(this, m_job); + return; + } + + auto it = m_results.find(id); + if (it != m_results.end()) { + it->second.done(); + m_listener->onResultAccepted(this, it->second, nullptr); + m_results.erase(it); + } +} + + +void Client::ping() +{ + send(snprintf(m_sendBuf, sizeof(m_sendBuf), "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId.data())); +} + + +void Client::read() +{ + char* end; + char* start = m_recvBuf.base; + size_t remaining = m_recvBufPos; + + while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { + end++; + size_t len = end - start; + parse(start, len); + + remaining -= len; + start = end; + } + + if (remaining == 0) { + m_recvBufPos = 0; + return; + } + + if (start == m_recvBuf.base) { + return; + } + + memcpy(m_recvBuf.base, start, remaining); + m_recvBufPos = remaining; +} + + +void Client::reconnect() +{ + if (!m_listener) { + m_storage.remove(m_key); + + return; + } + + m_keepAlive = 0; + + if (m_failures == -1) { + return m_listener->onClose(this, -1); + } + + setState(ConnectingState); + + m_failures++; + m_listener->onClose(this, (int) m_failures); + + m_expire = uv_now(uv_default_loop()) + m_retryPause; +} + + +void Client::setState(SocketState state) +{ + LOG_DEBUG("[%s] state: \"%s\"", m_pool.url(), states[state]); + + if (m_state == state) { + return; + } + + m_state = state; +} + + +void Client::startTimeout() +{ + m_expire = 0; + + if (m_pool.keepAlive()) { + m_keepAlive = uv_now(uv_default_loop()) + (m_pool.keepAlive() * 1000); + } +} + + +void Client::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) +{ + auto client = getClient(handle->data); + if (!client) { + return; + } + + buf->base = &client->m_recvBuf.base[client->m_recvBufPos]; + buf->len = client->m_recvBuf.len - client->m_recvBufPos; +} + + +void Client::onClose(uv_handle_t *handle) +{ + auto client = getClient(handle->data); + if (!client) { + return; + } + + client->onClose(); +} + + +void Client::onConnect(uv_connect_t *req, int status) +{ + auto client = getClient(req->data); + if (!client) { + delete req; + return; + } + + if (status < 0) { + if (!client->isQuiet()) { + LOG_ERR("[%s] connect error: \"%s\"", client->m_pool.url(), uv_strerror(status)); + } + + delete req; + client->close(); + return; + } + + client->m_stream = static_cast(req->handle); + client->m_stream->data = req->data; + client->setState(ConnectedState); + + uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); + delete req; + + client->handshake(); +} + + +void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) +{ + auto client = getClient(stream->data); + if (!client) { + return; + } + + if (nread < 0) { + if (!client->isQuiet()) { + LOG_ERR("[%s] read error: \"%s\"", client->m_pool.url(), uv_strerror((int) nread)); + } + + client->close(); + return; + } + + if ((size_t) nread > (sizeof(m_buf) - 8 - client->m_recvBufPos)) { + client->close(); + return; + } + + assert(client->m_listener != nullptr); + if (!client->m_listener) { + return client->reconnect(); + } + + client->m_recvBufPos += nread; + +# ifndef XMRIG_NO_TLS + if (client->isTLS()) { + LOG_DEBUG("[%s] TLS received (%d bytes)", client->m_pool.url(), static_cast(nread)); + + client->m_tls->read(client->m_recvBuf.base, client->m_recvBufPos); + client->m_recvBufPos = 0; + } + else +# endif + { + client->read(); + } +} + + +void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) +{ + auto client = getClient(req->data); + if (!client) { + return; + } + + assert(client->m_listener != nullptr); + if (!client->m_listener) { + return client->reconnect(); + } + + if (status < 0) { + if (!client->isQuiet()) { + LOG_ERR("[%s] DNS error: \"%s\"", client->m_pool.url(), uv_strerror(status)); + } + + return client->reconnect(); + } + + addrinfo *ptr = res; + std::vector ipv4; + std::vector ipv6; + + while (ptr != nullptr) { + if (ptr->ai_family == AF_INET) { + ipv4.push_back(ptr); + } + + if (ptr->ai_family == AF_INET6) { + ipv6.push_back(ptr); + } + + ptr = ptr->ai_next; + } + + if (ipv4.empty() && ipv6.empty()) { + if (!client->isQuiet()) { + LOG_ERR("[%s] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", client->m_pool.url()); + } + + uv_freeaddrinfo(res); + return client->reconnect(); + } + + client->connect(ipv4, ipv6); + uv_freeaddrinfo(res); +} diff --git a/src/common/net/Client.h b/src/common/net/Client.h new file mode 100644 index 00000000..d6418338 --- /dev/null +++ b/src/common/net/Client.h @@ -0,0 +1,172 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CLIENT_H +#define XMRIG_CLIENT_H + + +#include +#include +#include + + +#include "common/crypto/Algorithm.h" +#include "common/net/Id.h" +#include "common/net/Job.h" +#include "common/net/Pool.h" +#include "common/net/Storage.h" +#include "common/net/SubmitResult.h" +#include "rapidjson/fwd.h" + + +class IClientListener; +class JobResult; + + +typedef struct bio_st BIO; + + +class Client +{ +public: + enum SocketState { + UnconnectedState, + HostLookupState, + ConnectingState, + ConnectedState, + ClosingState + }; + + constexpr static int kResponseTimeout = 20 * 1000; + +# ifndef XMRIG_NO_TLS + constexpr static int kInputBufferSize = 1024 * 16; +# else + constexpr static int kInputBufferSize = 1024 * 2; +# endif + + Client(int id, const char *agent, IClientListener *listener); + ~Client(); + + bool disconnect(); + const char *tlsFingerprint() const; + const char *tlsVersion() const; + int64_t submit(const JobResult &result); + void connect(); + void connect(const Pool &pool); + void deleteLater(); + void setPool(const Pool &pool); + void tick(uint64_t now); + + inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } + inline const char *host() const { return m_pool.host(); } + inline const char *ip() const { return m_ip; } + inline const Job &job() const { return m_job; } + inline int id() const { return m_id; } + inline SocketState state() const { return m_state; } + inline uint16_t port() const { return m_pool.port(); } + inline void setAlgo(const xmrig::Algorithm &algo) { m_pool.setAlgo(algo); } + inline void setQuiet(bool quiet) { m_quiet = quiet; } + inline void setRetries(int retries) { m_retries = retries; } + inline void setRetryPause(int ms) { m_retryPause = ms; } + +private: + class Tls; + + + enum Extensions { + NicehashExt = 1, + AlgoExt = 2 + }; + + bool close(); + bool isCriticalError(const char *message); + bool isTLS() const; + bool parseJob(const rapidjson::Value ¶ms, int *code); + bool parseLogin(const rapidjson::Value &result, int *code); + bool send(BIO *bio); + bool verifyAlgorithm(const xmrig::Algorithm &algorithm) const; + int resolve(const char *host); + int64_t send(const rapidjson::Document &doc); + int64_t send(size_t size); + void connect(const std::vector &ipv4, const std::vector &ipv6); + void connect(sockaddr *addr); + void handshake(); + void login(); + void onClose(); + void parse(char *line, size_t len); + void parseExtensions(const rapidjson::Value &value); + void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error); + void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); + void ping(); + void read(); + void reconnect(); + void setState(SocketState state); + void startTimeout(); + + inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } + + static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); + static void onClose(uv_handle_t *handle); + static void onConnect(uv_connect_t *req, int status); + static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); + static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res); + + static inline Client *getClient(void *data) { return m_storage.get(data); } + + addrinfo m_hints; + bool m_ipv6; + bool m_nicehash; + bool m_quiet; + char m_buf[kInputBufferSize]; + char m_ip[46]; + char m_sendBuf[2048]; + const char *m_agent; + IClientListener *m_listener; + int m_extensions; + int m_id; + int m_retries; + int m_retryPause; + int64_t m_failures; + Job m_job; + Pool m_pool; + size_t m_recvBufPos; + SocketState m_state; + std::map m_results; + Tls *m_tls; + uint64_t m_expire; + uint64_t m_jobs; + uint64_t m_keepAlive; + uintptr_t m_key; + uv_buf_t m_recvBuf; + uv_getaddrinfo_t m_resolver; + uv_stream_t *m_stream; + uv_tcp_t *m_socket; + xmrig::Id m_rpcId; + + static int64_t m_sequence; + static xmrig::Storage m_storage; +}; + + +#endif /* XMRIG_CLIENT_H */ diff --git a/src/common/net/Id.h b/src/common/net/Id.h new file mode 100644 index 00000000..5fb2db52 --- /dev/null +++ b/src/common/net/Id.h @@ -0,0 +1,98 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ID_H__ +#define __ID_H__ + + +#include + + +namespace xmrig { + + +class Id +{ +public: + inline Id() : + m_data() + { + } + + + inline Id(const char *id, size_t sizeFix = 0) + { + setId(id, sizeFix); + } + + + inline bool operator==(const Id &other) const + { + return memcmp(m_data, other.m_data, sizeof(m_data)) == 0; + } + + + inline bool operator!=(const Id &other) const + { + return memcmp(m_data, other.m_data, sizeof(m_data)) != 0; + } + + + Id &operator=(const Id &other) + { + memcpy(m_data, other.m_data, sizeof(m_data)); + + return *this; + } + + + inline bool setId(const char *id, size_t sizeFix = 0) + { + memset(m_data, 0, sizeof(m_data)); + if (!id) { + return false; + } + + const size_t size = strlen(id); + if (size >= sizeof(m_data)) { + return false; + } + + memcpy(m_data, id, size - sizeFix); + return true; + } + + + inline const char *data() const { return m_data; } + inline bool isValid() const { return *m_data != '\0'; } + + +private: + char m_data[64]; +}; + + +} /* namespace xmrig */ + + +#endif /* __ID_H__ */ diff --git a/src/common/net/Job.cpp b/src/common/net/Job.cpp new file mode 100644 index 00000000..2bfb39f0 --- /dev/null +++ b/src/common/net/Job.cpp @@ -0,0 +1,248 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "common/net/Job.h" + + +static inline unsigned char hf_hex2bin(char c, bool &err) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + else if (c >= 'a' && c <= 'f') { + return c - 'a' + 0xA; + } + else if (c >= 'A' && c <= 'F') { + return c - 'A' + 0xA; + } + + err = true; + return 0; +} + + +static inline char hf_bin2hex(unsigned char c) +{ + if (c <= 0x9) { + return '0' + c; + } + + return 'a' - 0xA + c; +} + + +Job::Job() : + m_autoVariant(false), + m_nicehash(false), + m_poolId(-2), + m_threadId(-1), + m_size(0), + m_diff(0), + m_target(0), + m_blob() +{ +} + + +Job::Job(int poolId, bool nicehash, const xmrig::Algorithm &algorithm, const xmrig::Id &clientId) : + m_autoVariant(algorithm.variant() == xmrig::VARIANT_AUTO), + m_nicehash(nicehash), + m_poolId(poolId), + m_threadId(-1), + m_size(0), + m_diff(0), + m_target(0), + m_blob(), + m_algorithm(algorithm), + m_clientId(clientId) +{ +} + + +Job::~Job() +{ +} + + +bool Job::setBlob(const char *blob) +{ + if (!blob) { + return false; + } + + m_size = strlen(blob); + if (m_size % 2 != 0) { + return false; + } + + m_size /= 2; + if (m_size < 76 || m_size >= sizeof(m_blob)) { + return false; + } + + if (!fromHex(blob, (int) m_size * 2, m_blob)) { + return false; + } + + if (*nonce() != 0 && !m_nicehash) { + m_nicehash = true; + } + + if (m_autoVariant) { + m_algorithm.setVariant(variant()); + } + +# ifdef XMRIG_PROXY_PROJECT + memset(m_rawBlob, 0, sizeof(m_rawBlob)); + memcpy(m_rawBlob, blob, m_size * 2); +# endif + + return true; +} + + +bool Job::setTarget(const char *target) +{ + if (!target) { + return false; + } + + const size_t len = strlen(target); + + if (len <= 8) { + uint32_t tmp = 0; + char str[8]; + memcpy(str, target, len); + + if (!fromHex(str, 8, reinterpret_cast(&tmp)) || tmp == 0) { + return false; + } + + m_target = 0xFFFFFFFFFFFFFFFFULL / (0xFFFFFFFFULL / static_cast(tmp)); + } + else if (len <= 16) { + m_target = 0; + char str[16]; + memcpy(str, target, len); + + if (!fromHex(str, 16, reinterpret_cast(&m_target)) || m_target == 0) { + return false; + } + } + else { + return false; + } + +# ifdef XMRIG_PROXY_PROJECT + memset(m_rawTarget, 0, sizeof(m_rawTarget)); + memcpy(m_rawTarget, target, len); +# endif + + m_diff = toDiff(m_target); + return true; +} + + +void Job::setAlgorithm(const char *algo) +{ + m_algorithm.parseAlgorithm(algo); + + if (m_algorithm.variant() == xmrig::VARIANT_AUTO) { + m_algorithm.setVariant(variant()); + } +} + + +bool Job::fromHex(const char* in, unsigned int len, unsigned char* out) +{ + bool error = false; + for (unsigned int i = 0; i < len; i += 2) { + out[i / 2] = (hf_hex2bin(in[i], error) << 4) | hf_hex2bin(in[i + 1], error); + + if (error) { + return false; + } + } + return true; +} + + +void Job::toHex(const unsigned char* in, unsigned int len, char* out) +{ + for (unsigned int i = 0; i < len; i++) { + out[i * 2] = hf_bin2hex((in[i] & 0xF0) >> 4); + out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F); + } +} + + +#ifdef APP_DEBUG +char *Job::toHex(const unsigned char* in, unsigned int len) +{ + char *out = new char[len * 2 + 1](); + toHex(in, len, out); + + return out; +} +#endif + + +bool Job::operator==(const Job &other) const +{ + return m_id == other.m_id && memcmp(m_blob, other.m_blob, sizeof(m_blob)) == 0; +} + + +bool Job::operator!=(const Job &other) const +{ + return m_id != other.m_id || memcmp(m_blob, other.m_blob, sizeof(m_blob)) != 0; +} + + +xmrig::Variant Job::variant() const +{ + using namespace xmrig; + + switch (m_algorithm.algo()) { + case CRYPTONIGHT: + return (m_blob[0] >= 8) ? VARIANT_2 : VARIANT_1; + + case CRYPTONIGHT_LITE: + return VARIANT_1; + + case CRYPTONIGHT_HEAVY: + return VARIANT_0; + + default: + break; + } + + return m_algorithm.variant(); +} diff --git a/src/common/net/Job.h b/src/common/net/Job.h new file mode 100644 index 00000000..b561b9c1 --- /dev/null +++ b/src/common/net/Job.h @@ -0,0 +1,108 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_JOB_H +#define XMRIG_JOB_H + + +#include +#include + + +#include "common/crypto/Algorithm.h" +#include "common/net/Id.h" + + +class Job +{ +public: + Job(); + Job(int poolId, bool nicehash, const xmrig::Algorithm &algorithm, const xmrig::Id &clientId); + ~Job(); + + bool setBlob(const char *blob); + bool setTarget(const char *target); + void setAlgorithm(const char *algo); + + inline bool isNicehash() const { return m_nicehash; } + inline bool isValid() const { return m_size > 0 && m_diff > 0; } + inline bool setId(const char *id) { return m_id.setId(id); } + inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } + inline const uint8_t *blob() const { return m_blob; } + inline const xmrig::Algorithm &algorithm() const { return m_algorithm; } + inline const xmrig::Id &clientId() const { return m_clientId; } + inline const xmrig::Id &id() const { return m_id; } + inline int poolId() const { return m_poolId; } + inline int threadId() const { return m_threadId; } + inline size_t size() const { return m_size; } + inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } + inline uint32_t diff() const { return static_cast(m_diff); } + inline uint64_t target() const { return m_target; } + inline void reset() { m_size = 0; m_diff = 0; } + inline void setClientId(const xmrig::Id &id) { m_clientId = id; } + inline void setPoolId(int poolId) { m_poolId = poolId; } + inline void setThreadId(int threadId) { m_threadId = threadId; } + inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); } + inline void setVariant(int variant) { m_algorithm.parseVariant(variant); } + +# ifdef XMRIG_PROXY_PROJECT + inline char *rawBlob() { return m_rawBlob; } + inline const char *rawTarget() const { return m_rawTarget; } +# endif + + static bool fromHex(const char* in, unsigned int len, unsigned char* out); + static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast(blob + 39); } + static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; } + static void toHex(const unsigned char* in, unsigned int len, char* out); + +# ifdef APP_DEBUG + static char *toHex(const unsigned char* in, unsigned int len); +# endif + + bool operator==(const Job &other) const; + bool operator!=(const Job &other) const; + +private: + xmrig::Variant variant() const; + + bool m_autoVariant; + bool m_nicehash; + int m_poolId; + int m_threadId; + size_t m_size; + uint64_t m_diff; + uint64_t m_target; + uint8_t m_blob[96]; // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk. + xmrig::Algorithm m_algorithm; + xmrig::Id m_clientId; + xmrig::Id m_id; + +# ifdef XMRIG_PROXY_PROJECT + char m_rawBlob[176]; + char m_rawTarget[24]; +# endif +}; + +#endif /* XMRIG_JOB_H */ diff --git a/src/common/net/Pool.cpp b/src/common/net/Pool.cpp new file mode 100644 index 00000000..141e5115 --- /dev/null +++ b/src/common/net/Pool.cpp @@ -0,0 +1,407 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include + + +#include "common/net/Pool.h" +#include "rapidjson/document.h" + + +#ifdef APP_DEBUG +# include "common/log/Log.h" +#endif + + +#ifdef _MSC_VER +# define strncasecmp _strnicmp +# define strcasecmp _stricmp +#endif + + +Pool::Pool() : + m_nicehash(false), + m_tls(false), + m_keepAlive(0), + m_port(kDefaultPort) +{ +} + + +/** + * @brief Parse url. + * + * Valid urls: + * example.com + * example.com:3333 + * stratum+tcp://example.com + * stratum+tcp://example.com:3333 + * + * @param url + */ +Pool::Pool(const char *url) : + m_nicehash(false), + m_tls(false), + m_keepAlive(0), + m_port(kDefaultPort) +{ + parse(url); +} + + +Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : + m_nicehash(nicehash), + m_tls(tls), + m_keepAlive(keepAlive), + m_port(port), + m_host(host), + m_password(password), + m_user(user) +{ + const size_t size = m_host.size() + 8; + assert(size > 8); + + char *url = new char[size](); + snprintf(url, size - 1, "%s:%d", m_host.data(), m_port); + + m_url = url; +} + + +bool Pool::isCompatible(const xmrig::Algorithm &algorithm) const +{ + if (m_algorithms.empty()) { + return true; + } + + for (const auto &a : m_algorithms) { + if (algorithm == a) { + return true; + } + } + +# ifdef XMRIG_PROXY_PROJECT + if (m_algorithm.algo() == xmrig::CRYPTONIGHT && algorithm.algo() == xmrig::CRYPTONIGHT && m_algorithm.variant() == xmrig::VARIANT_XTL) { + return true; + } +# endif + + return false; +} + + +bool Pool::isEqual(const Pool &other) const +{ + return (m_nicehash == other.m_nicehash + && m_tls == other.m_tls + && m_keepAlive == other.m_keepAlive + && m_port == other.m_port + && m_algorithm == other.m_algorithm + && m_fingerprint == other.m_fingerprint + && m_host == other.m_host + && m_password == other.m_password + && m_rigId == other.m_rigId + && m_url == other.m_url + && m_user == other.m_user); +} + + +bool Pool::parse(const char *url) +{ + assert(url != nullptr); + + const char *p = strstr(url, "://"); + const char *base = url; + + if (p) { + if (strncasecmp(url, "stratum+tcp://", 14) == 0) { + m_tls = false; + } + else if (strncasecmp(url, "stratum+ssl://", 14) == 0) { + m_tls = true; + } + else { + return false; + } + + base = url + 14; + } + + if (!strlen(base) || *base == '/') { + return false; + } + + m_url = url; + if (base[0] == '[') { + return parseIPv6(base); + } + + const char *port = strchr(base, ':'); + if (!port) { + m_host = base; + return true; + } + + const size_t size = port++ - base + 1; + char *host = new char[size](); + memcpy(host, base, size - 1); + + m_host = host; + m_port = static_cast(strtol(port, nullptr, 10)); + + return true; +} + + +bool Pool::setUserpass(const char *userpass) +{ + const char *p = strchr(userpass, ':'); + if (!p) { + return false; + } + + char *user = new char[p - userpass + 1](); + strncpy(user, userpass, p - userpass); + + m_user = user; + m_password = p + 1; + + return true; +} + + +rapidjson::Value Pool::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember("url", StringRef(url()), allocator); + obj.AddMember("user", StringRef(user()), allocator); + obj.AddMember("pass", StringRef(password()), allocator); + obj.AddMember("rig-id", rigId() ? Value(StringRef(rigId())).Move() : Value(kNullType).Move(), allocator); + +# ifndef XMRIG_PROXY_PROJECT + obj.AddMember("nicehash", isNicehash(), allocator); +# endif + + if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { + obj.AddMember("keepalive", m_keepAlive > 0, allocator); + } + else { + obj.AddMember("keepalive", m_keepAlive, allocator); + } + + switch (m_algorithm.variant()) { + case xmrig::VARIANT_AUTO: + case xmrig::VARIANT_0: + case xmrig::VARIANT_1: + case xmrig::VARIANT_2: + obj.AddMember("variant", m_algorithm.variant(), allocator); + break; + + default: + obj.AddMember("variant", StringRef(m_algorithm.variantName()), allocator); + break; + } + + obj.AddMember("tls", isTLS(), allocator); + obj.AddMember("tls-fingerprint", fingerprint() ? Value(StringRef(fingerprint())).Move() : Value(kNullType).Move(), allocator); + + return obj; +} + + +void Pool::adjust(const xmrig::Algorithm &algorithm) +{ + if (!isValid()) { + return; + } + + if (!m_algorithm.isValid()) { + m_algorithm.setAlgo(algorithm.algo()); + adjustVariant(algorithm.variant()); + } + + rebuild(); +} + + +void Pool::setAlgo(const xmrig::Algorithm &algorithm) +{ + m_algorithm = algorithm; + + rebuild(); +} + + +#ifdef APP_DEBUG +void Pool::print() const +{ + LOG_NOTICE("url: %s", m_url.data()); + LOG_DEBUG ("host: %s", m_host.data()); + LOG_DEBUG ("port: %d", static_cast(m_port)); + LOG_DEBUG ("user: %s", m_user.data()); + LOG_DEBUG ("pass: %s", m_password.data()); + LOG_DEBUG ("rig-id %s", m_rigId.data()); + LOG_DEBUG ("algo: %s", m_algorithm.name()); + LOG_DEBUG ("nicehash: %d", static_cast(m_nicehash)); + LOG_DEBUG ("keepAlive: %d", m_keepAlive); +} +#endif + + +bool Pool::parseIPv6(const char *addr) +{ + const char *end = strchr(addr, ']'); + if (!end) { + return false; + } + + const char *port = strchr(end, ':'); + if (!port) { + return false; + } + + const size_t size = end - addr; + char *host = new char[size](); + memcpy(host, addr + 1, size - 1); + + m_host = host; + m_port = static_cast(strtol(port + 1, nullptr, 10)); + + return true; +} + + +void Pool::addVariant(xmrig::Variant variant) +{ + const xmrig::Algorithm algorithm(m_algorithm.algo(), variant); + if (!algorithm.isValid() || m_algorithm == algorithm) { + return; + } + + m_algorithms.push_back(algorithm); +} + + +void Pool::adjustVariant(const xmrig::Variant variantHint) +{ +# ifndef XMRIG_PROXY_PROJECT + using namespace xmrig; + + if (m_host.contains(".nicehash.com")) { + m_keepAlive = false; + m_nicehash = true; + bool valid = true; + + if (m_host.contains("cryptonight.") && m_port == 3355) { + valid = m_algorithm.algo() == CRYPTONIGHT; + m_algorithm.setVariant(VARIANT_0); + } + else if (m_host.contains("cryptonightv7.") && m_port == 3363) { + valid = m_algorithm.algo() == CRYPTONIGHT; + m_algorithm.setVariant(VARIANT_1); + } + else if (m_host.contains("cryptonightheavy.") && m_port == 3364) { + valid = m_algorithm.algo() == CRYPTONIGHT_HEAVY; + m_algorithm.setVariant(VARIANT_0); + } + + if (!valid) { + m_algorithm.setAlgo(INVALID_ALGO); + } + + return; + } + + if (m_host.contains(".minergate.com")) { + m_keepAlive = false; + bool valid = true; + m_algorithm.setVariant(VARIANT_1); + + if (m_host.contains("xmr.pool.")) { + valid = m_algorithm.algo() == CRYPTONIGHT; + m_algorithm.setVariant(m_port == 45700 ? VARIANT_1 : VARIANT_0); + } + else if (m_host.contains("aeon.pool.") && m_port == 45690) { + valid = m_algorithm.algo() == CRYPTONIGHT_LITE; + m_algorithm.setVariant(VARIANT_1); + } + + if (!valid) { + m_algorithm.setAlgo(INVALID_ALGO); + } + + return; + } + + if (variantHint != VARIANT_AUTO) { + m_algorithm.setVariant(variantHint); + return; + } + + if (m_algorithm.variant() != VARIANT_AUTO) { + return; + } + + if (m_algorithm.algo() == CRYPTONIGHT_HEAVY) { + m_algorithm.setVariant(VARIANT_0); + } + else if (m_algorithm.algo() == CRYPTONIGHT_LITE) { + m_algorithm.setVariant(VARIANT_1); + } +# endif +} + + +void Pool::rebuild() +{ + m_algorithms.clear(); + + if (!m_algorithm.isValid()) { + return; + } + + m_algorithms.push_back(m_algorithm); + +# ifndef XMRIG_PROXY_PROJECT + addVariant(xmrig::VARIANT_2); + addVariant(xmrig::VARIANT_1); + addVariant(xmrig::VARIANT_0); + addVariant(xmrig::VARIANT_XTL); + addVariant(xmrig::VARIANT_TUBE); + addVariant(xmrig::VARIANT_MSR); + addVariant(xmrig::VARIANT_XHV); + addVariant(xmrig::VARIANT_XAO); + addVariant(xmrig::VARIANT_RTO); + addVariant(xmrig::VARIANT_AUTO); +# endif +} diff --git a/src/common/net/Pool.h b/src/common/net/Pool.h new file mode 100644 index 00000000..123cc131 --- /dev/null +++ b/src/common/net/Pool.h @@ -0,0 +1,116 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_POOL_H +#define XMRIG_POOL_H + + +#include + + +#include "common/crypto/Algorithm.h" +#include "common/utils/c_str.h" +#include "rapidjson/fwd.h" + + +class Pool +{ +public: + constexpr static const char *kDefaultPassword = "x"; + constexpr static const char *kDefaultUser = "x"; + constexpr static uint16_t kDefaultPort = 3333; + constexpr static int kKeepAliveTimeout = 60; + + Pool(); + Pool(const char *url); + Pool(const char *host, + uint16_t port, + const char *user = nullptr, + const char *password = nullptr, + int keepAlive = 0, + bool nicehash = false, + bool tls = false + ); + + inline bool isNicehash() const { return m_nicehash; } + inline bool isTLS() const { return m_tls; } + inline bool isValid() const { return !m_host.isNull() && m_port > 0; } + inline const char *fingerprint() const { return m_fingerprint.data(); } + inline const char *host() const { return m_host.data(); } + inline const char *password() const { return !m_password.isNull() ? m_password.data() : kDefaultPassword; } + inline const char *rigId() const { return m_rigId.data(); } + inline const char *url() const { return m_url.data(); } + inline const char *user() const { return !m_user.isNull() ? m_user.data() : kDefaultUser; } + inline const xmrig::Algorithm &algorithm() const { return m_algorithm; } + inline const xmrig::Algorithms &algorithms() const { return m_algorithms; } + inline int keepAlive() const { return m_keepAlive; } + inline uint16_t port() const { return m_port; } + inline void setFingerprint(const char *fingerprint) { m_fingerprint = fingerprint; } + inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } + inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } + inline void setPassword(const char *password) { m_password = password; } + inline void setRigId(const char *rigId) { m_rigId = rigId; } + inline void setTLS(bool tls) { m_tls = tls; } + inline void setUser(const char *user) { m_user = user; } + inline xmrig::Algorithm &algorithm() { return m_algorithm; } + + inline bool operator!=(const Pool &other) const { return !isEqual(other); } + inline bool operator==(const Pool &other) const { return isEqual(other); } + + bool isCompatible(const xmrig::Algorithm &algorithm) const; + bool isEqual(const Pool &other) const; + bool parse(const char *url); + bool setUserpass(const char *userpass); + rapidjson::Value toJSON(rapidjson::Document &doc) const; + void adjust(const xmrig::Algorithm &algorithm); + void setAlgo(const xmrig::Algorithm &algorithm); + +# ifdef APP_DEBUG + void print() const; +# endif + +private: + bool parseIPv6(const char *addr); + void addVariant(xmrig::Variant variant); + void adjustVariant(const xmrig::Variant variantHint); + void rebuild(); + + bool m_nicehash; + bool m_tls; + int m_keepAlive; + uint16_t m_port; + xmrig::Algorithm m_algorithm; + xmrig::Algorithms m_algorithms; + xmrig::c_str m_fingerprint; + xmrig::c_str m_host; + xmrig::c_str m_password; + xmrig::c_str m_rigId; + xmrig::c_str m_url; + xmrig::c_str m_user; +}; + + +typedef std::vector Pools; + +#endif /* XMRIG_POOL_H */ diff --git a/src/common/net/Storage.h b/src/common/net/Storage.h new file mode 100644 index 00000000..f36ce594 --- /dev/null +++ b/src/common/net/Storage.h @@ -0,0 +1,95 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __STORAGE_H__ +#define __STORAGE_H__ + + +#include +#include + + +namespace xmrig { + + +template +class Storage +{ +public: + inline Storage() : + m_counter(0) + { + } + + + inline uintptr_t add(TYPE *ptr) + { + m_data[m_counter] = ptr; + + return m_counter++; + } + + + inline static void *ptr(uintptr_t id) { return reinterpret_cast(id); } + + + inline TYPE *get(void *id) const { return get(reinterpret_cast(id)); } + inline TYPE *get(uintptr_t id) const + { + assert(m_data.count(id) > 0); + + if (m_data.count(id) == 0) { + return nullptr; + } + + return m_data.at(id); + } + + + inline void remove(void *id) { remove(reinterpret_cast(id)); } + inline void remove(uintptr_t id) + { + TYPE *obj = get(id); + if (obj == nullptr) { + return; + } + + auto it = m_data.find(id); + if (it != m_data.end()) { + m_data.erase(it); + } + + delete obj; + } + + +private: + std::map m_data; + uint64_t m_counter; +}; + + +} /* namespace xmrig */ + + +#endif /* __STORAGE_H__ */ diff --git a/src/common/net/SubmitResult.cpp b/src/common/net/SubmitResult.cpp new file mode 100644 index 00000000..251b2bf1 --- /dev/null +++ b/src/common/net/SubmitResult.cpp @@ -0,0 +1,45 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/net/SubmitResult.h" + + +SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff, int64_t reqId) : + reqId(reqId), + seq(seq), + diff(diff), + actualDiff(actualDiff), + elapsed(0) +{ + start = uv_hrtime(); +} + + +void SubmitResult::done() +{ + elapsed = (uv_hrtime() - start) / 1000000; +} diff --git a/src/common/net/SubmitResult.h b/src/common/net/SubmitResult.h new file mode 100644 index 00000000..e812cbf8 --- /dev/null +++ b/src/common/net/SubmitResult.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SUBMITRESULT_H__ +#define __SUBMITRESULT_H__ + + +#include + + +class SubmitResult +{ +public: + inline SubmitResult() : reqId(0), seq(0), diff(0), actualDiff(0), elapsed(0), start(0) {} + SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff, int64_t reqId = 0); + + void done(); + + int64_t reqId; + int64_t seq; + uint32_t diff; + uint64_t actualDiff; + uint64_t elapsed; + +private: + uint64_t start; +}; + +#endif /* __SUBMITRESULT_H__ */ diff --git a/src/common/net/Tls.cpp b/src/common/net/Tls.cpp new file mode 100644 index 00000000..182d86ff --- /dev/null +++ b/src/common/net/Tls.cpp @@ -0,0 +1,190 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/net/Client.h" +#include "common/net/Tls.h" +#include "common/log/Log.h" + + +#ifdef _MSC_VER +# define strncasecmp(x,y,z) _strnicmp(x,y,z) +#endif + + +Client::Tls::Tls(Client *client) : + m_ready(false), + m_buf(), + m_fingerprint(), + m_client(client), + m_ssl(nullptr) +{ + m_ctx = SSL_CTX_new(SSLv23_method()); + assert(m_ctx != nullptr); + + if (!m_ctx) { + return; + } + + m_writeBio = BIO_new(BIO_s_mem()); + m_readBio = BIO_new(BIO_s_mem()); + SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); +} + + +Client::Tls::~Tls() +{ + if (m_ctx) { + SSL_CTX_free(m_ctx); + } + + if (m_ssl) { + SSL_free(m_ssl); + } +} + + +bool Client::Tls::handshake() +{ + m_ssl = SSL_new(m_ctx); + assert(m_ssl != nullptr); + + if (!m_ssl) { + return false; + } + + SSL_set_connect_state(m_ssl); + SSL_set_bio(m_ssl, m_readBio, m_writeBio); + SSL_do_handshake(m_ssl); + + return send(); +} + + +bool Client::Tls::send(const char *data, size_t size) +{ + SSL_write(m_ssl, data, size); + + return send(); +} + + +const char *Client::Tls::fingerprint() const +{ + return m_ready ? m_fingerprint : nullptr; +} + + +const char *Client::Tls::version() const +{ + return m_ready ? SSL_get_version(m_ssl) : nullptr; +} + + +void Client::Tls::read(const char *data, size_t size) +{ + BIO_write(m_readBio, data, size); + + if (!SSL_is_init_finished(m_ssl)) { + const int rc = SSL_connect(m_ssl); + + if (rc < 0 && SSL_get_error(m_ssl, rc) == SSL_ERROR_WANT_READ) { + send(); + } else if (rc == 1) { + X509 *cert = SSL_get_peer_certificate(m_ssl); + if (!verify(cert)) { + X509_free(cert); + m_client->close(); + + return; + } + + X509_free(cert); + m_ready = true; + m_client->login(); + } + + return; + } + + int bytes_read = 0; + while ((bytes_read = SSL_read(m_ssl, m_buf, sizeof(m_buf))) > 0) { + m_client->parse(m_buf, bytes_read); + } +} + + +bool Client::Tls::send() +{ + return m_client->send(m_writeBio); +} + + +bool Client::Tls::verify(X509 *cert) +{ + if (cert == nullptr) { + LOG_ERR("[%s] Failed to get server certificate", m_client->m_pool.url()); + + return false; + } + + if (!verifyFingerprint(cert)) { + LOG_ERR("[%s] Failed to verify server certificate fingerprint", m_client->m_pool.url()); + + const char *fingerprint = m_client->m_pool.fingerprint(); + if (strlen(m_fingerprint) == 64 && fingerprint != nullptr) { + LOG_ERR("\"%s\" was given", m_fingerprint); + LOG_ERR("\"%s\" was configured", fingerprint); + } + + return false; + } + + return true; +} + + +bool Client::Tls::verifyFingerprint(X509 *cert) +{ + const EVP_MD *digest = EVP_get_digestbyname("sha256"); + if (digest == nullptr) { + return false; + } + + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int dlen; + + if (X509_digest(cert, digest, md, &dlen) != 1) { + return false; + } + + Job::toHex(md, 32, m_fingerprint); + const char *fingerprint = m_client->m_pool.fingerprint(); + + return fingerprint == nullptr || strncasecmp(m_fingerprint, fingerprint, 64) == 0; +} diff --git a/src/common/net/Tls.h b/src/common/net/Tls.h new file mode 100644 index 00000000..6e38f32f --- /dev/null +++ b/src/common/net/Tls.h @@ -0,0 +1,62 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_TLS_H +#define XMRIG_TLS_H + + +#include + + +#include "common/net/Client.h" + + +class Client::Tls +{ +public: + Tls(Client *client); + ~Tls(); + + bool handshake(); + bool send(const char *data, size_t size); + const char *fingerprint() const; + const char *version() const; + void read(const char *data, size_t size); + +private: + bool send(); + bool verify(X509 *cert); + bool verifyFingerprint(X509 *cert); + + BIO *m_readBio; + BIO *m_writeBio; + bool m_ready; + char m_buf[1024 * 2]; + char m_fingerprint[32 * 2 + 8]; + Client *m_client; + SSL *m_ssl; + SSL_CTX *m_ctx; +}; + + +#endif /* XMRIG_TLS_H */ diff --git a/src/common/net/strategies/FailoverStrategy.cpp b/src/common/net/strategies/FailoverStrategy.cpp new file mode 100644 index 00000000..fab78590 --- /dev/null +++ b/src/common/net/strategies/FailoverStrategy.cpp @@ -0,0 +1,165 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "common/interfaces/IStrategyListener.h" +#include "common/net/Client.h" +#include "common/net/strategies/FailoverStrategy.h" +#include "common/Platform.h" + + +FailoverStrategy::FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet) : + m_quiet(quiet), + m_retries(retries), + m_retryPause(retryPause), + m_active(-1), + m_index(0), + m_listener(listener) +{ + for (const Pool &url : urls) { + add(url); + } +} + + +FailoverStrategy::~FailoverStrategy() +{ + for (Client *client : m_pools) { + client->deleteLater(); + } +} + + +int64_t FailoverStrategy::submit(const JobResult &result) +{ + if (m_active == -1) { + return -1; + } + + return m_pools[m_active]->submit(result); +} + + +void FailoverStrategy::connect() +{ + m_pools[m_index]->connect(); +} + + +void FailoverStrategy::resume() +{ + if (!isActive()) { + return; + } + + m_listener->onJob(this, m_pools[m_active], m_pools[m_active]->job()); +} + + +void FailoverStrategy::stop() +{ + for (size_t i = 0; i < m_pools.size(); ++i) { + m_pools[i]->disconnect(); + } + + m_index = 0; + m_active = -1; + + m_listener->onPause(this); +} + + +void FailoverStrategy::tick(uint64_t now) +{ + for (Client *client : m_pools) { + client->tick(now); + } +} + + +void FailoverStrategy::onClose(Client *client, int failures) +{ + if (failures == -1) { + return; + } + + if (m_active == client->id()) { + m_active = -1; + m_listener->onPause(this); + } + + if (m_index == 0 && failures < m_retries) { + return; + } + + if (m_index == client->id() && (m_pools.size() - m_index) > 1) { + m_pools[++m_index]->connect(); + } +} + + +void FailoverStrategy::onJobReceived(Client *client, const Job &job) +{ + if (m_active == client->id()) { + m_listener->onJob(this, client, job); + } +} + + +void FailoverStrategy::onLoginSuccess(Client *client) +{ + int active = m_active; + + if (client->id() == 0 || !isActive()) { + active = client->id(); + } + + for (size_t i = 1; i < m_pools.size(); ++i) { + if (active != static_cast(i)) { + m_pools[i]->disconnect(); + } + } + + if (active >= 0 && active != m_active) { + m_index = m_active = active; + m_listener->onActive(this, client); + } +} + + +void FailoverStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) +{ + m_listener->onResultAccepted(this, client, result, error); +} + + +void FailoverStrategy::add(const Pool &pool) +{ + Client *client = new Client((int) m_pools.size(), Platform::userAgent(), this); + client->setPool(pool); + client->setRetries(m_retries); + client->setRetryPause(m_retryPause * 1000); + client->setQuiet(m_quiet); + + m_pools.push_back(client); +} diff --git a/src/common/net/strategies/FailoverStrategy.h b/src/common/net/strategies/FailoverStrategy.h new file mode 100644 index 00000000..07095b3b --- /dev/null +++ b/src/common/net/strategies/FailoverStrategy.h @@ -0,0 +1,74 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __FAILOVERSTRATEGY_H__ +#define __FAILOVERSTRATEGY_H__ + + +#include + + +#include "common/interfaces/IClientListener.h" +#include "common/interfaces/IStrategy.h" +#include "common/net/Pool.h" + + +class Client; +class IStrategyListener; +class Url; + + +class FailoverStrategy : public IStrategy, public IClientListener +{ +public: + FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); + ~FailoverStrategy(); + +public: + inline bool isActive() const override { return m_active >= 0; } + + int64_t submit(const JobResult &result) override; + void connect() override; + void resume() override; + void stop() override; + void tick(uint64_t now) override; + +protected: + void onClose(Client *client, int failures) override; + void onJobReceived(Client *client, const Job &job) override; + void onLoginSuccess(Client *client) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; + +private: + void add(const Pool &pool); + + const bool m_quiet; + const int m_retries; + const int m_retryPause; + int m_active; + int m_index; + IStrategyListener *m_listener; + std::vector m_pools; +}; + +#endif /* __FAILOVERSTRATEGY_H__ */ diff --git a/src/common/net/strategies/SinglePoolStrategy.cpp b/src/common/net/strategies/SinglePoolStrategy.cpp new file mode 100644 index 00000000..2cfc0976 --- /dev/null +++ b/src/common/net/strategies/SinglePoolStrategy.cpp @@ -0,0 +1,110 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "common/interfaces/IStrategyListener.h" +#include "common/net/Client.h" +#include "common/net/strategies/SinglePoolStrategy.h" +#include "common/Platform.h" + + +SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) : + m_active(false), + m_listener(listener) +{ + m_client = new Client(0, Platform::userAgent(), this); + m_client->setPool(pool); + m_client->setRetries(retries); + m_client->setRetryPause(retryPause * 1000); + m_client->setQuiet(quiet); +} + + +SinglePoolStrategy::~SinglePoolStrategy() +{ + m_client->deleteLater(); +} + + +int64_t SinglePoolStrategy::submit(const JobResult &result) +{ + return m_client->submit(result); +} + + +void SinglePoolStrategy::connect() +{ + m_client->connect(); +} + + +void SinglePoolStrategy::resume() +{ + if (!isActive()) { + return; + } + + m_listener->onJob(this, m_client, m_client->job()); +} + + +void SinglePoolStrategy::stop() +{ + m_client->disconnect(); +} + + +void SinglePoolStrategy::tick(uint64_t now) +{ + m_client->tick(now); +} + + +void SinglePoolStrategy::onClose(Client *client, int failures) +{ + if (!isActive()) { + return; + } + + m_active = false; + m_listener->onPause(this); +} + + +void SinglePoolStrategy::onJobReceived(Client *client, const Job &job) +{ + m_listener->onJob(this, client, job); +} + + +void SinglePoolStrategy::onLoginSuccess(Client *client) +{ + m_active = true; + m_listener->onActive(this, client); +} + + +void SinglePoolStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) +{ + m_listener->onResultAccepted(this, client, result, error); +} diff --git a/src/common/net/strategies/SinglePoolStrategy.h b/src/common/net/strategies/SinglePoolStrategy.h new file mode 100644 index 00000000..1a48d678 --- /dev/null +++ b/src/common/net/strategies/SinglePoolStrategy.h @@ -0,0 +1,64 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SINGLEPOOLSTRATEGY_H__ +#define __SINGLEPOOLSTRATEGY_H__ + + +#include "common/interfaces/IClientListener.h" +#include "common/interfaces/IStrategy.h" + + +class Client; +class IStrategyListener; +class Url; + + +class SinglePoolStrategy : public IStrategy, public IClientListener +{ +public: + SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); + ~SinglePoolStrategy(); + +public: + inline bool isActive() const override { return m_active; } + + int64_t submit(const JobResult &result) override; + void connect() override; + void resume() override; + void stop() override; + void tick(uint64_t now) override; + +protected: + void onClose(Client *client, int failures) override; + void onJobReceived(Client *client, const Job &job) override; + void onLoginSuccess(Client *client) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; + +private: + bool m_active; + Client *m_client; + IStrategyListener *m_listener; +}; + +#endif /* __SINGLEPOOLSTRATEGY_H__ */ diff --git a/src/common/utils/c_str.h b/src/common/utils/c_str.h new file mode 100644 index 00000000..7ce63754 --- /dev/null +++ b/src/common/utils/c_str.h @@ -0,0 +1,102 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __C_STR_H__ +#define __C_STR_H__ + + +#include +#include + +#include + + +namespace xmrig { + + +/** + * @brief Simple C string wrapper. + * + * 1. I know about std:string. + * 2. For some reason I prefer don't use std:string in miner, eg because of file size of MSYS2 builds. + */ +class c_str +{ +public: + inline c_str() : m_data(nullptr) {} + inline c_str(c_str &&other) { m_data = other.m_data; other.m_data = nullptr; } + inline c_str(const c_str &other) : m_data(nullptr) { set(other.data()); } + inline c_str(const char *str) : m_data(nullptr) { set(str); } + inline ~c_str() { free(m_data); } + + + inline void set(const char *str) + { + free(m_data); + + m_data = str != nullptr ? strdup(str) : nullptr; + } + + + inline void set(char *str) + { + free(m_data); + + m_data = str; + } + + + inline bool isEqual(const char *str) const + { + return (m_data != nullptr && str != nullptr && strcmp(m_data, str) == 0) || (m_data == nullptr && m_data == nullptr); + } + + + inline bool contains(const char *str) const + { + return strstr(m_data, str) != nullptr; + } + + + inline bool isNull() const { return m_data == nullptr; } + inline const char *data() const { return m_data; } + inline size_t size() const { return m_data == nullptr ? 0 : strlen(m_data); } + + + inline bool operator!=(const c_str &str) const { return !isEqual(str.data()); } + inline bool operator!=(const char *str) const { return !isEqual(str); } + inline bool operator==(const c_str &str) const { return isEqual(str.data()); } + inline bool operator==(const char *str) const { return isEqual(str); } + inline c_str &operator=(char *str) { set(str); return *this; } + inline c_str &operator=(const c_str &str) { set(str.data()); return *this; } + inline c_str &operator=(const char *str) { set(str); return *this; } + + +private: + char *m_data; +}; + + +} /* namespace xmrig */ + +#endif /* __C_STR_H__ */ diff --git a/src/common/utils/mm_malloc.h b/src/common/utils/mm_malloc.h new file mode 100644 index 00000000..30c721a3 --- /dev/null +++ b/src/common/utils/mm_malloc.h @@ -0,0 +1,43 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __MM_MALLOC_PORTABLE_H__ +#define __MM_MALLOC_PORTABLE_H__ + + +#ifdef _WIN32 +# ifdef __GNUC__ +# include +# else +# include +# endif +#else +# if defined(XMRIG_ARM) && !defined(__clang__) +# include "aligned_malloc.h" +# else +# include +# endif +#endif + + +#endif /* __MM_MALLOC_PORTABLE_H__ */ diff --git a/src/common/utils/timestamp.h b/src/common/utils/timestamp.h new file mode 100644 index 00000000..6b6a8ab2 --- /dev/null +++ b/src/common/utils/timestamp.h @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_TIMESTAMP_H +#define XMRIG_TIMESTAMP_H + + +#include + + +namespace xmrig { + + +static inline int64_t currentMSecsSinceEpoch() +{ + using namespace std::chrono; + if (high_resolution_clock::is_steady) { + return time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); + } + + return time_point_cast(steady_clock::now()).time_since_epoch().count(); +} + + +} /* namespace xmrig */ + +#endif /* XMRIG_TIMESTAMP_H */ diff --git a/src/common/xmrig.h b/src/common/xmrig.h new file mode 100644 index 00000000..52650f0d --- /dev/null +++ b/src/common/xmrig.h @@ -0,0 +1,109 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_XMRIG_H +#define XMRIG_XMRIG_H + + +namespace xmrig +{ + + +enum Algo { + INVALID_ALGO = -1, + CRYPTONIGHT, /* CryptoNight (Monero) */ + CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */ + CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (RYO) */ +}; + + +//--av=1 For CPUs with hardware AES. +//--av=2 Lower power mode (double hash) of 1. +//--av=3 Software AES implementation. +//--av=4 Lower power mode (double hash) of 3. +enum AlgoVariant { + AV_AUTO, // --av=0 Automatic mode. + AV_SINGLE, // --av=1 Single hash mode + AV_DOUBLE, // --av=2 Double hash mode + AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) + AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) + AV_TRIPLE, // --av=5 Triple hash mode + AV_QUAD, // --av=6 Quard hash mode + AV_PENTA, // --av=7 Penta hash mode + AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) + AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) + AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) + AV_MAX +}; + + +enum Variant { + VARIANT_AUTO = -1, // Autodetect + VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy + VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 + VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) + VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) + VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) + VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) + VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) + VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) + VARIANT_2 = 8, // CryptoNight variant 2 + VARIANT_MAX +}; + + +enum AlgoVerify { + VERIFY_HW_AES = 1, + VERIFY_SOFT_AES = 2 +}; + + +enum AesMode { + AES_AUTO, + AES_HW, + AES_SOFT +}; + + +enum OclVendor { + OCL_VENDOR_UNKNOWN = -2, + OCL_VENDOR_MANUAL = -1, + OCL_VENDOR_AMD = 0, + OCL_VENDOR_NVIDIA = 1, + OCL_VENDOR_INTEL = 2 +}; + + +enum Assembly { + ASM_NONE, + ASM_AUTO, + ASM_INTEL, + ASM_RYZEN, + ASM_MAX +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_XMRIG_H */ diff --git a/src/config.json b/src/config.json index 0be5d849..87883a8f 100644 --- a/src/config.json +++ b/src/config.json @@ -1,27 +1,35 @@ { "algo": "cryptonight", + "api": { + "port": 0, + "access-token": null, + "worker-id": null, + "ipv6": false, + "restricted": true + }, "background": false, "colors": true, + "cuda-bfactor": null, + "cuda-bsleep": null, + "cuda-max-threads": 64, "donate-level": 5, "log-file": null, - "print-time": 60, - "retries": 5, - "retry-pause": 5, - "syslog": false, - "threads": null, "pools": [ { - "url": "failover.xmrig.com:443", + "url": "proxy.fee.xmrig.com:9999", "user": "YOUR_WALLET", "pass": "x", - "keepalive": true, + "rig-id": null, "nicehash": false, - "variant": -1 + "keepalive": true, + "variant": 1 } ], - "api": { - "port": 0, - "access-token": null, - "worker-id": null - } + "print-time": 60, + "retries": 5, + "retry-pause": 5, + "threads": null, + "user-agent": null, + "syslog": false, + "watch": false } \ No newline at end of file diff --git a/src/core/Config.cpp b/src/core/Config.cpp new file mode 100644 index 00000000..607feb40 --- /dev/null +++ b/src/core/Config.cpp @@ -0,0 +1,235 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + + +#include "common/config/ConfigLoader.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/ConfigCreator.h" +#include "crypto/CryptoNight_constants.h" +#include "nvidia/NvmlApi.h" +#include "rapidjson/document.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/prettywriter.h" +#include "workers/CudaThread.h" + + +xmrig::Config::Config() : xmrig::CommonConfig(), + m_autoConf(false), + m_shouldSave(false), + m_maxGpuThreads(64), + m_maxGpuUsage(100) +{ +} + + +bool xmrig::Config::reload(const char *json) +{ + return xmrig::ConfigLoader::reload(this, json); +} + + +void xmrig::Config::getJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + doc.SetObject(); + + auto &allocator = doc.GetAllocator(); + + doc.AddMember("algo", StringRef(algorithm().name()), allocator); + + Value api(kObjectType); + api.AddMember("port", apiPort(), allocator); + api.AddMember("access-token", apiToken() ? Value(StringRef(apiToken())).Move() : Value(kNullType).Move(), allocator); + api.AddMember("id", apiId() ? Value(StringRef(apiId())).Move() : Value(kNullType).Move(), allocator); + api.AddMember("worker-id", apiWorkerId() ? Value(StringRef(apiWorkerId())).Move() : Value(kNullType).Move(), allocator); + api.AddMember("ipv6", isApiIPv6(), allocator); + api.AddMember("restricted", isApiRestricted(), allocator); + doc.AddMember("api", api, allocator); + + doc.AddMember("background", isBackground(), allocator); + doc.AddMember("colors", isColors(), allocator); + doc.AddMember("cuda-bfactor", m_cudaCLI.bfactor(), allocator); + doc.AddMember("cuda-bsleep", m_cudaCLI.bsleep(), allocator); + doc.AddMember("cuda-max-threads", m_maxGpuThreads, allocator); + doc.AddMember("donate-level", donateLevel(), allocator); + doc.AddMember("log-file", logFile() ? Value(StringRef(logFile())).Move() : Value(kNullType).Move(), allocator); + + Value pools(kArrayType); + + for (const Pool &pool : m_activePools) { + pools.PushBack(pool.toJSON(doc), allocator); + } + + doc.AddMember("pools", pools, allocator); + doc.AddMember("print-time", printTime(), allocator); + doc.AddMember("retries", retries(), allocator); + doc.AddMember("retry-pause", retryPause(), allocator); + + Value threads(kArrayType); + for (const IThread *thread : m_threads) { + threads.PushBack(thread->toConfig(doc), allocator); + } + doc.AddMember("threads", threads, allocator); + + doc.AddMember("user-agent", userAgent() ? Value(StringRef(userAgent())).Move() : Value(kNullType).Move(), allocator); + doc.AddMember("syslog", isSyslog(), allocator); + doc.AddMember("watch", m_watch, allocator); +} + + +xmrig::Config *xmrig::Config::load(int argc, char **argv, IWatcherListener *listener) +{ + return static_cast(ConfigLoader::load(argc, argv, new ConfigCreator(), listener)); +} + + +bool xmrig::Config::finalize() +{ + if (m_state != NoneState) { + return CommonConfig::finalize(); + } + + if (!CommonConfig::finalize()) { + return false; + } + + if (m_threads.empty() && !m_cudaCLI.setup(m_threads, algorithm().algo())) { + m_autoConf = true; + m_shouldSave = true; + m_cudaCLI.autoConf(m_threads, algorithm().algo()); + + for (IThread *thread : m_threads) { + static_cast(thread)->limit(m_maxGpuUsage, m_maxGpuThreads); + } + } + + NvmlApi::init(); + NvmlApi::bind(m_threads); + return true; +} + + +bool xmrig::Config::parseString(int key, const char *arg) +{ + if (!CommonConfig::parseString(key, arg)) { + return false; + } + + switch (key) { + case CudaBFactorKey: /* --cuda-bfactor */ + m_cudaCLI.parseBFactor(arg); + break; + + case CudaBSleepKey: /* --cuda-bsleep */ + m_cudaCLI.parseBSleep(arg); + break; + + case CudaDevicesKey: /* --cuda-devices */ + m_cudaCLI.parseDevices(arg); + break; + + case CudaLaunchKey: /* --cuda-launch */ + m_cudaCLI.parseLaunch(arg); + break; + + case CudaAffinityKey: /* --cuda-affinity */ + m_cudaCLI.parseAffinity(arg); + break; + + case CudaMaxThreadsKey: + case CudaMaxUsageKey: + return parseUint64(key, strtoul(arg, nullptr, 10)); + + default: + break; + } + + return true; +} + + +bool xmrig::Config::parseUint64(int key, uint64_t arg) +{ + if (!CommonConfig::parseUint64(key, arg)) { + return false; + } + + switch (key) { + case CudaMaxThreadsKey: /* --cuda-max-threads */ + m_maxGpuThreads = static_cast(arg); + break; + + case CudaBFactorKey: /* --cuda-bfactor */ + m_cudaCLI.addBFactor(static_cast(arg)); + break; + + case CudaBSleepKey: /* --cuda-bsleep */ + m_cudaCLI.addBSleep(static_cast(arg)); + break; + + case CudaMaxUsageKey: /* --max-gpu-usage */ + m_maxGpuUsage = static_cast(arg); + break; + + default: + break; + } + + return true; +} + + +void xmrig::Config::parseJSON(const rapidjson::Document &doc) +{ + const rapidjson::Value &threads = doc["threads"]; + + if (threads.IsArray()) { + for (const rapidjson::Value &value : threads.GetArray()) { + if (!value.IsObject()) { + continue; + } + + if (value.HasMember("threads")) { + parseThread(value); + } + } + } +} + + +void xmrig::Config::parseThread(const rapidjson::Value &object) +{ + CudaThread *thread = new CudaThread(object); + if (thread->init(algorithm().algo())) { + m_threads.push_back(thread); + return; + } + + delete thread; +} diff --git a/src/core/Config.h b/src/core/Config.h new file mode 100644 index 00000000..da70b6d9 --- /dev/null +++ b/src/core/Config.h @@ -0,0 +1,81 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CONFIG_H +#define XMRIG_CONFIG_H + + +#include +#include + + +#include "common/config/CommonConfig.h" +#include "common/xmrig.h" +#include "nvidia/CudaCLI.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class ConfigLoader; +class IThread; +class IWatcherListener; + + +class Config : public CommonConfig +{ +public: + Config(); + + bool reload(const char *json); + + void getJSON(rapidjson::Document &doc) const override; + + inline bool isShouldSave() const { return m_shouldSave; } + inline const std::vector &threads() const { return m_threads; } + inline int maxGpuThreads() const { return m_maxGpuThreads; } + + static Config *load(int argc, char **argv, IWatcherListener *listener); + +protected: + bool finalize() override; + bool parseString(int key, const char *arg) override; + bool parseUint64(int key, uint64_t arg) override; + void parseJSON(const rapidjson::Document &doc) override; + +private: + void parseThread(const rapidjson::Value &object); + + bool m_autoConf; + bool m_shouldSave; + CudaCLI m_cudaCLI; + int m_maxGpuThreads; + int m_maxGpuUsage; + std::vector m_threads; +}; + + +} /* namespace xmrig */ + +#endif /* XMRIG_CONFIG_H */ diff --git a/src/core/ConfigCreator.h b/src/core/ConfigCreator.h new file mode 100644 index 00000000..054eb78c --- /dev/null +++ b/src/core/ConfigCreator.h @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONFIGCREATOR_H__ +#define __CONFIGCREATOR_H__ + + +#include "common/interfaces/IConfigCreator.h" +#include "core/Config.h" + + +namespace xmrig { + + +class IConfig; + + +class ConfigCreator : public IConfigCreator +{ +public: + inline IConfig *create() const override + { + return new Config(); + } +}; + + +} /* namespace xmrig */ + + +#endif // __CONFIGCREATOR_H__ diff --git a/src/core/ConfigLoader_platform.h b/src/core/ConfigLoader_platform.h new file mode 100644 index 00000000..c3e54ec5 --- /dev/null +++ b/src/core/ConfigLoader_platform.h @@ -0,0 +1,197 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CONFIGLOADER_PLATFORM_H +#define XMRIG_CONFIGLOADER_PLATFORM_H + + +#ifdef _MSC_VER +# include "getopt/getopt.h" +#else +# include +#endif + + +#include "common/interfaces/IConfig.h" +#include "version.h" + + +namespace xmrig { + + +static char const usage[] = "\ +Usage: " APP_ID " [OPTIONS]\n\ +Options:\n\ + -a, --algo=ALGO specify the algorithm to use\n\ + cryptonight\n" +#ifndef XMRIG_NO_AEON +"\ + cryptonight-lite\n" +#endif +#ifndef XMRIG_NO_SUMO +"\ + cryptonight-heavy\n" +#endif +"\ + -o, --url=URL URL of mining server\n\ + -O, --userpass=U:P username:password pair for mining server\n\ + -u, --user=USERNAME username for mining server\n\ + -p, --pass=PASSWORD password for mining server\n\ + --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\ + -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\ + --nicehash enable nicehash.com support\n\ + --tls enable SSL/TLS support (needs pool support)\n\ + --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n\ + -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ + -R, --retry-pause=N time to pause between retries (default: 5)\n\ + --cuda-devices=N list of CUDA devices to use.\n\ + --cuda-launch=TxB list of launch config for the CryptoNight kernel\n\ + --cuda-max-threads=N limit maximum count of GPU threads in automatic mode\n\ + --cuda-bfactor=[0-12] run CryptoNight core kernel in smaller pieces\n\ + --cuda-bsleep=N insert a delay of N microseconds between kernel launches\n\ + --cuda-affinity=N affine GPU threads to a CPU\n\ + --no-color disable colored output\n\ + --variant algorithm PoW variant\n\ + --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ + --user-agent set custom user-agent string for pool\n\ + -B, --background run the miner in the background\n\ + -c, --config=FILE load a JSON-format configuration file\n\ + -l, --log-file=FILE log all output to a file\n" +# ifdef HAVE_SYSLOG_H +"\ + -S, --syslog use system log for output messages\n" +# endif +"\ + --print-time=N print hashrate report every N seconds\n\ + --api-port=N port for the miner API\n\ + --api-access-token=T access token for API\n\ + --api-worker-id=ID custom worker-id for API\n\ + --api-id=ID custom instance ID for API\n\ + --api-ipv6 enable IPv6 support for API\n\ + --api-no-restricted enable full remote access (only if API token set)\n\ + --dry-run test configuration and exit\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ +"; + + +static char const short_options[] = "a:c:khBp:Px:r:R:s:T:o:u:O:Vl:S"; + + +static struct option const options[] = { + { "algo", 1, nullptr, xmrig::IConfig::AlgorithmKey }, + { "api-access-token", 1, nullptr, xmrig::IConfig::ApiAccessTokenKey }, + { "api-port", 1, nullptr, xmrig::IConfig::ApiPort }, + { "api-worker-id", 1, nullptr, xmrig::IConfig::ApiWorkerIdKey }, + { "api-id", 1, nullptr, xmrig::IConfig::ApiIdKey }, + { "api-ipv6", 0, nullptr, xmrig::IConfig::ApiIPv6Key }, + { "api-no-restricted", 0, nullptr, xmrig::IConfig::ApiRestrictedKey }, + { "background", 0, nullptr, xmrig::IConfig::BackgroundKey }, + { "bfactor", 1, nullptr, xmrig::IConfig::CudaBFactorKey }, // deprecated, use --cuda-bfactor instead. + { "bsleep", 1, nullptr, xmrig::IConfig::CudaBSleepKey }, // deprecated, use --cuda-bsleep instead. + { "cuda-affinity", 1, nullptr, xmrig::IConfig::CudaAffinityKey }, + { "cuda-bfactor", 1, nullptr, xmrig::IConfig::CudaBFactorKey }, + { "cuda-bsleep", 1, nullptr, xmrig::IConfig::CudaBSleepKey }, + { "cuda-devices", 1, nullptr, xmrig::IConfig::CudaDevicesKey }, + { "cuda-launch", 1, nullptr, xmrig::IConfig::CudaLaunchKey }, + { "cuda-max-threads", 1, nullptr, xmrig::IConfig::CudaMaxThreadsKey }, + { "max-gpu-threads", 1, nullptr, xmrig::IConfig::CudaMaxThreadsKey }, // deprecated, use --cuda-max-threads instead. + { "max-gpu-usage", 1, nullptr, xmrig::IConfig::CudaMaxUsageKey }, // deprecated. + { "config", 1, nullptr, xmrig::IConfig::ConfigKey }, + { "donate-level", 1, nullptr, xmrig::IConfig::DonateLevelKey }, + { "dry-run", 0, nullptr, xmrig::IConfig::DryRunKey }, + { "help", 0, nullptr, xmrig::IConfig::HelpKey }, + { "keepalive", 0, nullptr, xmrig::IConfig::KeepAliveKey }, + { "log-file", 1, nullptr, xmrig::IConfig::LogFileKey }, + { "nicehash", 0, nullptr, xmrig::IConfig::NicehashKey }, + { "no-color", 0, nullptr, xmrig::IConfig::ColorKey }, + { "variant", 1, nullptr, xmrig::IConfig::VariantKey }, + { "pass", 1, nullptr, xmrig::IConfig::PasswordKey }, + { "print-time", 1, nullptr, xmrig::IConfig::PrintTimeKey }, + { "retries", 1, nullptr, xmrig::IConfig::RetriesKey }, + { "retry-pause", 1, nullptr, xmrig::IConfig::RetryPauseKey }, + { "syslog", 0, nullptr, xmrig::IConfig::SyslogKey }, + { "url", 1, nullptr, xmrig::IConfig::UrlKey }, + { "user", 1, nullptr, xmrig::IConfig::UserKey }, + { "user-agent", 1, nullptr, xmrig::IConfig::UserAgentKey }, + { "userpass", 1, nullptr, xmrig::IConfig::UserpassKey }, + { "rig-id", 1, nullptr, xmrig::IConfig::RigIdKey }, + { "tls", 0, nullptr, xmrig::IConfig::TlsKey }, + { "tls-fingerprint", 1, nullptr, xmrig::IConfig::FingerprintKey }, + { "version", 0, nullptr, xmrig::IConfig::VersionKey }, + { nullptr, 0, nullptr, 0 } +}; + + +static struct option const config_options[] = { + { "algo", 1, nullptr, xmrig::IConfig::AlgorithmKey }, + { "background", 0, nullptr, xmrig::IConfig::BackgroundKey }, + { "colors", 0, nullptr, xmrig::IConfig::ColorKey }, + { "donate-level", 1, nullptr, xmrig::IConfig::DonateLevelKey }, + { "dry-run", 0, nullptr, xmrig::IConfig::DryRunKey }, + { "log-file", 1, nullptr, xmrig::IConfig::LogFileKey }, + { "print-time", 1, nullptr, xmrig::IConfig::PrintTimeKey }, + { "retries", 1, nullptr, xmrig::IConfig::RetriesKey }, + { "retry-pause", 1, nullptr, xmrig::IConfig::RetryPauseKey }, + { "syslog", 0, nullptr, xmrig::IConfig::SyslogKey }, + { "user-agent", 1, nullptr, xmrig::IConfig::UserAgentKey }, + { "bfactor", 1, nullptr, xmrig::IConfig::CudaBFactorKey }, // deprecated, use --cuda-bfactor instead. + { "bsleep", 1, nullptr, xmrig::IConfig::CudaBSleepKey }, // deprecated, use --cuda-bsleep instead. + { "cuda-bfactor", 1, nullptr, xmrig::IConfig::CudaBFactorKey }, + { "cuda-bsleep", 1, nullptr, xmrig::IConfig::CudaBSleepKey }, + { "cuda-max-threads", 1, nullptr, xmrig::IConfig::CudaMaxThreadsKey }, + { "max-gpu-threads", 1, nullptr, xmrig::IConfig::CudaMaxThreadsKey }, // deprecated, use --cuda-max-threads instead. + { "max-gpu-usage", 1, nullptr, xmrig::IConfig::CudaMaxUsageKey }, // deprecated. + { nullptr, 0, nullptr, 0 } +}; + + +static struct option const pool_options[] = { + { "url", 1, nullptr, xmrig::IConfig::UrlKey }, + { "pass", 1, nullptr, xmrig::IConfig::PasswordKey }, + { "user", 1, nullptr, xmrig::IConfig::UserKey }, + { "userpass", 1, nullptr, xmrig::IConfig::UserpassKey }, + { "nicehash", 0, nullptr, xmrig::IConfig::NicehashKey }, + { "keepalive", 2, nullptr, xmrig::IConfig::KeepAliveKey }, + { "variant", 1, nullptr, xmrig::IConfig::VariantKey }, + { "rig-id", 1, nullptr, xmrig::IConfig::RigIdKey }, + { "tls", 0, nullptr, xmrig::IConfig::TlsKey }, + { "tls-fingerprint", 1, nullptr, xmrig::IConfig::FingerprintKey }, + { nullptr, 0, nullptr, 0 } +}; + + +static struct option const api_options[] = { + { "port", 1, nullptr, xmrig::IConfig::ApiPort }, + { "access-token", 1, nullptr, xmrig::IConfig::ApiAccessTokenKey }, + { "worker-id", 1, nullptr, xmrig::IConfig::ApiWorkerIdKey }, + { "ipv6", 0, nullptr, xmrig::IConfig::ApiIPv6Key }, + { "restricted", 0, nullptr, xmrig::IConfig::ApiRestrictedKey }, + { "id", 1, nullptr, xmrig::IConfig::ApiIdKey }, + { nullptr, 0, nullptr, 0 } +}; + + +} /* namespace xmrig */ + +#endif /* XMRIG_CONFIGLOADER_PLATFORM_H */ diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp new file mode 100644 index 00000000..c2b54e6b --- /dev/null +++ b/src/core/Controller.cpp @@ -0,0 +1,150 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/config/ConfigLoader.h" +#include "common/cpu/Cpu.h" +#include "common/interfaces/IControllerListener.h" +#include "common/log/ConsoleLog.h" +#include "common/log/FileLog.h" +#include "common/log/Log.h" +#include "common/Platform.h" +#include "core/Config.h" +#include "core/Controller.h" +#include "net/Network.h" + + +#ifdef HAVE_SYSLOG_H +# include "common/log/SysLog.h" +#endif + + +class xmrig::ControllerPrivate +{ +public: + inline ControllerPrivate() : + network(nullptr), + config(nullptr) + {} + + + inline ~ControllerPrivate() + { + delete network; + delete config; + } + + + Network *network; + std::vector listeners; + xmrig::Config *config; +}; + + +xmrig::Controller::Controller() + : d_ptr(new ControllerPrivate()) +{ +} + + +xmrig::Controller::~Controller() +{ + ConfigLoader::release(); + + delete d_ptr; +} + + +bool xmrig::Controller::isReady() const +{ + return d_ptr->config && d_ptr->network; +} + + +xmrig::Config *xmrig::Controller::config() const +{ + assert(d_ptr->config != nullptr); + + return d_ptr->config; +} + + +int xmrig::Controller::init(int argc, char **argv) +{ + Cpu::init(); + + d_ptr->config = xmrig::Config::load(argc, argv, this); + if (!d_ptr->config) { + return 1; + } + + Log::init(); + Platform::init(config()->userAgent()); + + if (!config()->isBackground()) { + Log::add(new ConsoleLog(this)); + } + + if (config()->logFile()) { + Log::add(new FileLog(this, config()->logFile())); + } + +# ifdef HAVE_SYSLOG_H + if (config()->isSyslog()) { + Log::add(new SysLog()); + } +# endif + + d_ptr->network = new Network(this); + return 0; +} + + +Network *xmrig::Controller::network() const +{ + assert(d_ptr->network != nullptr); + + return d_ptr->network; +} + + +void xmrig::Controller::addListener(IControllerListener *listener) +{ + d_ptr->listeners.push_back(listener); +} + + +void xmrig::Controller::onNewConfig(IConfig *config) +{ + Config *previousConfig = d_ptr->config; + d_ptr->config = static_cast(config); + + for (xmrig::IControllerListener *listener : d_ptr->listeners) { + listener->onConfigChanged(d_ptr->config, previousConfig); + } + + delete previousConfig; +} diff --git a/src/core/Controller.h b/src/core/Controller.h new file mode 100644 index 00000000..18fcba41 --- /dev/null +++ b/src/core/Controller.h @@ -0,0 +1,64 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CONTROLLER_H +#define XMRIG_CONTROLLER_H + + +#include "common/interfaces/IWatcherListener.h" + + +class Network; +class StatsData; + + +namespace xmrig { + + +class Config; +class ControllerPrivate; +class IControllerListener; + + +class Controller : public IWatcherListener +{ +public: + Controller(); + ~Controller() override; + + bool isReady() const; + Config *config() const; + int init(int argc, char **argv); + Network *network() const; + void addListener(IControllerListener *listener); + +protected: + void onNewConfig(IConfig *config) override; + +private: + ControllerPrivate *d_ptr; +}; + +} /* namespace xmrig */ + +#endif /* XMRIG_CONTROLLER_H */ diff --git a/src/crypto/CryptoNight.cpp b/src/crypto/CryptoNight.cpp index a668ee32..84ef42fb 100644 --- a/src/crypto/CryptoNight.cpp +++ b/src/crypto/CryptoNight.cpp @@ -26,22 +26,23 @@ #include -#include "Cpu.h" +#include "common/cpu/Cpu.h" +#include "common/net/Job.h" +#include "common/utils/mm_malloc.h" #include "crypto/CryptoNight.h" #include "crypto/CryptoNight_test.h" #include "crypto/CryptoNight_x86.h" -#include "net/Job.h" #include "net/JobResult.h" -#include "Options.h" +alignas(16) cryptonight_ctx *CryptoNight::m_ctx = nullptr; xmrig::Algo CryptoNight::m_algorithm = xmrig::CRYPTONIGHT; xmrig::AlgoVerify CryptoNight::m_av = xmrig::VERIFY_HW_AES; bool CryptoNight::hash(const Job &job, JobResult &result, cryptonight_ctx *ctx) { - fn(job.variant())(job.blob(), job.size(), result.result, ctx); + fn(job.algorithm().variant())(job.blob(), job.size(), result.result, &ctx); return *reinterpret_cast(result.result + 24) < job.target(); } @@ -50,9 +51,13 @@ bool CryptoNight::hash(const Job &job, JobResult &result, cryptonight_ctx *ctx) bool CryptoNight::init(xmrig::Algo algorithm) { m_algorithm = algorithm; - m_av = Cpu::hasAES() ? xmrig::VERIFY_HW_AES : xmrig::VERIFY_SOFT_AES; + m_av = xmrig::Cpu::info()->hasAES() ? xmrig::VERIFY_HW_AES : xmrig::VERIFY_SOFT_AES; - return selfTest(); + const bool valid = selfTest(); + freeCtx(m_ctx); + m_ctx = nullptr; + + return valid; } @@ -60,101 +65,162 @@ CryptoNight::cn_hash_fun CryptoNight::fn(xmrig::Algo algorithm, xmrig::AlgoVerif { using namespace xmrig; - assert(variant == VARIANT_NONE || variant == VARIANT_V1); + assert(variant >= VARIANT_0 && variant < VARIANT_MAX); - static const cn_hash_fun func_table[16] = { - cryptonight_single_hash, - cryptonight_single_hash, + static const cn_hash_fun func_table[VARIANT_MAX * 2 * 3] = { + cryptonight_single_hash, + cryptonight_single_hash, - cryptonight_single_hash, - cryptonight_single_hash, + cryptonight_single_hash, + cryptonight_single_hash, -# ifndef XMRIG_NO_AEON - cryptonight_single_hash, - cryptonight_single_hash, + nullptr, nullptr, // VARIANT_TUBE + + cryptonight_single_hash, + cryptonight_single_hash, + + cryptonight_single_hash, + cryptonight_single_hash, + + nullptr, nullptr, // VARIANT_XHV + + cryptonight_single_hash, + cryptonight_single_hash, + + cryptonight_single_hash, + cryptonight_single_hash, - cryptonight_single_hash, - cryptonight_single_hash, + cryptonight_single_hash, + cryptonight_single_hash, + +# ifndef XMRIG_NO_AEON + cryptonight_single_hash, + cryptonight_single_hash, + + cryptonight_single_hash, + cryptonight_single_hash, + + nullptr, nullptr, // VARIANT_TUBE + nullptr, nullptr, // VARIANT_XTL + nullptr, nullptr, // VARIANT_MSR + nullptr, nullptr, // VARIANT_XHV + nullptr, nullptr, // VARIANT_XAO + nullptr, nullptr, // VARIANT_RTO + nullptr, nullptr, // VARIANT_2 # else nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, # endif # ifndef XMRIG_NO_SUMO - cryptonight_single_hash, - cryptonight_single_hash, - nullptr, nullptr, + cryptonight_single_hash, + cryptonight_single_hash, + + nullptr, nullptr, // VARIANT_1 + + cryptonight_single_hash, + cryptonight_single_hash, + + nullptr, nullptr, // VARIANT_XTL + nullptr, nullptr, // VARIANT_MSR + + cryptonight_single_hash, + cryptonight_single_hash, + + nullptr, nullptr, // VARIANT_XAO + nullptr, nullptr, // VARIANT_RTO + nullptr, nullptr, // VARIANT_2 # else nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr # endif - -# ifndef XMRIG_NO_IPBC - nullptr, nullptr, - cryptonight_single_hash, - cryptonight_single_hash, -# else - nullptr, nullptr, nullptr, nullptr, -# endif }; -# ifndef XMRIG_NO_SUMO - if (algorithm == CRYPTONIGHT_HEAVY) { - variant = VARIANT_NONE; - } -# endif + const size_t index = VARIANT_MAX * 2 * algorithm + 2 * variant + av - 1; -# ifndef XMRIG_NO_IPBC - if (algorithm == CRYPTONIGHT_IPBC) { - variant = VARIANT_V1; - } -# endif +# ifndef NDEBUG + cn_hash_fun func = func_table[index]; - return func_table[4 * algorithm + 2 * variant + av - 1]; + assert(index < sizeof(func_table) / sizeof(func_table[0])); + assert(func != nullptr); + + return func; +# else + return func_table[index]; +# endif } -bool CryptoNight::selfTest() { - if (fn(xmrig::VARIANT_NONE) == nullptr || fn(xmrig::VARIANT_V1) == nullptr) { - return false; - } - - uint8_t output[32]; +cryptonight_ctx *CryptoNight::createCtx(xmrig::Algo algorithm) +{ cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); + ctx->memory = static_cast(_mm_malloc(xmrig::cn_select_memory(algorithm), 16)); + + return ctx; +} - fn(xmrig::VARIANT_NONE)(test_input, 76, output, ctx); - if (m_algorithm == xmrig::CRYPTONIGHT && memcmp(output, test_output_v0, 32) == 0) { - fn(xmrig::VARIANT_V1)(test_input, 76, output, ctx); +void CryptoNight::freeCtx(cryptonight_ctx *ctx) +{ + _mm_free(ctx->memory); + _mm_free(ctx); +} + + +bool CryptoNight::selfTest() { + using namespace xmrig; - _mm_free(ctx); + m_ctx = createCtx(m_algorithm); - return memcmp(output, test_output_v1, 32) == 0; + if (m_algorithm == xmrig::CRYPTONIGHT) { + return verify(VARIANT_0, test_output_v0) && + verify(VARIANT_1, test_output_v1) && + verify(VARIANT_2, test_output_v2) && + verify(VARIANT_XTL, test_output_xtl) && + verify(VARIANT_MSR, test_output_msr) && + verify(VARIANT_XAO, test_output_xao) && + verify(VARIANT_RTO, test_output_rto); } # ifndef XMRIG_NO_AEON - if (m_algorithm == xmrig::CRYPTONIGHT_LITE && memcmp(output, test_output_v0_lite, 32) == 0) { - fn(xmrig::VARIANT_V1)(test_input, 76, output, ctx); - - _mm_free(ctx); + if (m_algorithm == xmrig::CRYPTONIGHT_LITE) { + return verify(VARIANT_0, test_output_v0_lite) && + verify(VARIANT_1, test_output_v1_lite); + } +# endif - return memcmp(output, test_output_v1_lite, 32) == 0; +# ifndef XMRIG_NO_SUMO + if (m_algorithm == xmrig::CRYPTONIGHT_HEAVY) { + return verify(VARIANT_0, test_output_v0_heavy) && + verify(VARIANT_XHV, test_output_xhv_heavy) && + verify(VARIANT_TUBE, test_output_tube_heavy); } # endif -# ifndef XMRIG_NO_SUMO - if (m_algorithm == xmrig::CRYPTONIGHT_HEAVY && memcmp(output, test_output_heavy, 32) == 0) { - _mm_free(ctx); + return false; +} - return true; - } -# endif -# ifndef XMRIG_NO_IPBC - const bool rc = m_algorithm == xmrig::CRYPTONIGHT_IPBC && memcmp(output, test_output_ipbc, 32) == 0; -# else - const bool rc = false; -# endif +bool CryptoNight::verify(xmrig::Variant variant, const uint8_t *referenceValue) +{ + if (!m_ctx) { + return false; + } + + uint8_t output[32]; + + cn_hash_fun func = fn(variant); + if (!func) { + return false; + } - _mm_free(ctx); + func(test_input, 76, output, &m_ctx); - return rc; + return memcmp(output, referenceValue, 32) == 0; } diff --git a/src/crypto/CryptoNight.h b/src/crypto/CryptoNight.h index b1ecc13d..f9f0f04b 100644 --- a/src/crypto/CryptoNight.h +++ b/src/crypto/CryptoNight.h @@ -22,30 +22,21 @@ * along with this program. If not, see . */ -#ifndef __CRYPTONIGHT_H__ -#define __CRYPTONIGHT_H__ +#ifndef XMRIG_CRYPTONIGHT_H +#define XMRIG_CRYPTONIGHT_H #include #include +#include "common/xmrig.h" #include "crypto/CryptoNight_constants.h" -#include "xmrig.h" - - -#define AEON_MEMORY 1048576 -#define AEON_MASK 0xFFFF0 -#define AEON_ITER 0x40000 - -#define MONERO_MEMORY 2097152 -#define MONERO_MASK 0x1FFFF0 -#define MONERO_ITER 0x80000 struct cryptonight_ctx { - alignas(16) uint8_t state0[200]; - alignas(16) uint8_t memory[xmrig::CRYPTONIGHT_HEAVY_MEMORY]; // big enough for all algos. TODO: change size in runtime. + alignas(16) uint8_t state[224]; + alignas(16) uint8_t *memory; }; @@ -56,19 +47,24 @@ class JobResult; class CryptoNight { public: - typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx); + typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx); static inline cn_hash_fun fn(xmrig::Variant variant) { return fn(m_algorithm, m_av, variant); } static bool hash(const Job &job, JobResult &result, cryptonight_ctx *ctx); static bool init(xmrig::Algo algorithm); static cn_hash_fun fn(xmrig::Algo algorithm, xmrig::AlgoVerify av, xmrig::Variant variant); + static cryptonight_ctx *createCtx(xmrig::Algo algorithm); + static void freeCtx(cryptonight_ctx *ctx); private: static bool selfTest(); + static bool verify(xmrig::Variant variant, const uint8_t *referenceValue); + alignas(16) static cryptonight_ctx *m_ctx; static xmrig::Algo m_algorithm; static xmrig::AlgoVerify m_av; }; -#endif /* __CRYPTONIGHT_H__ */ + +#endif /* XMRIG_CRYPTONIGHT_H */ diff --git a/src/crypto/CryptoNight_constants.h b/src/crypto/CryptoNight_constants.h index cc7dc2a8..f13891a7 100644 --- a/src/crypto/CryptoNight_constants.h +++ b/src/crypto/CryptoNight_constants.h @@ -29,7 +29,7 @@ #include -#include "xmrig.h" +#include "common/xmrig.h" namespace xmrig @@ -38,6 +38,8 @@ namespace xmrig constexpr const size_t CRYPTONIGHT_MEMORY = 2 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_MASK = 0x1FFFF0; constexpr const uint32_t CRYPTONIGHT_ITER = 0x80000; +constexpr const uint32_t CRYPTONIGHT_MSR_ITER = 0x40000; +constexpr const uint32_t CRYPTONIGHT_XAO_ITER = 0x100000; constexpr const size_t CRYPTONIGHT_LITE_MEMORY = 1 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_LITE_MASK = 0xFFFF0; @@ -47,16 +49,11 @@ constexpr const size_t CRYPTONIGHT_HEAVY_MEMORY = 4 * 1024 * 1024; constexpr const uint32_t CRYPTONIGHT_HEAVY_MASK = 0x3FFFF0; constexpr const uint32_t CRYPTONIGHT_HEAVY_ITER = 0x40000; -constexpr const size_t CRYPTONIGHT_IPBC_MEMORY = 1 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_IPBC_MASK = 0xFFFF0; -constexpr const uint32_t CRYPTONIGHT_IPBC_ITER = 0x40000; - template inline constexpr size_t cn_select_memory() { return 0; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_IPBC_MEMORY; } inline size_t cn_select_memory(Algo algorithm) @@ -72,8 +69,8 @@ inline size_t cn_select_memory(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MEMORY; - case CRYPTONIGHT_IPBC: - return CRYPTONIGHT_IPBC_MEMORY; + default: + break; } return 0; @@ -84,7 +81,7 @@ template inline constexpr uint32_t cn_select_mask() { retur template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_IPBC_MASK; } + inline uint32_t cn_select_mask(Algo algorithm) { @@ -99,22 +96,42 @@ inline uint32_t cn_select_mask(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_MASK; - case CRYPTONIGHT_IPBC: - return CRYPTONIGHT_IPBC_MASK; + default: + break; } return 0; } -template inline constexpr uint32_t cn_select_iter() { return 0; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_IPBC_ITER; } +template inline constexpr uint32_t cn_select_iter() { return 0; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_MSR_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } +template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } + -inline uint32_t cn_select_iter(Algo algorithm) +inline uint32_t cn_select_iter(Algo algorithm, Variant variant) { + switch (variant) { + case VARIANT_MSR: + return CRYPTONIGHT_MSR_ITER; + + case VARIANT_RTO: + return CRYPTONIGHT_XAO_ITER; + + default: + break; + } + switch(algorithm) { case CRYPTONIGHT: @@ -126,14 +143,26 @@ inline uint32_t cn_select_iter(Algo algorithm) case CRYPTONIGHT_HEAVY: return CRYPTONIGHT_HEAVY_ITER; - case CRYPTONIGHT_IPBC: - return CRYPTONIGHT_IPBC_ITER; + default: + break; } return 0; } +template inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } +template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } + + } /* namespace xmrig */ diff --git a/src/crypto/CryptoNight_monero.h b/src/crypto/CryptoNight_monero.h index a667a3b3..52229026 100644 --- a/src/crypto/CryptoNight_monero.h +++ b/src/crypto/CryptoNight_monero.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -22,30 +23,31 @@ * along with this program. If not, see . */ -#ifndef __CRYPTONIGHT_MONERO_H__ -#define __CRYPTONIGHT_MONERO_H__ +#ifndef XMRIG_CRYPTONIGHT_MONERO_H +#define XMRIG_CRYPTONIGHT_MONERO_H +#include +#include // VARIANT ALTERATIONS #ifndef XMRIG_ARM # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (VARIANT > 0) { \ + if (IS_V1) { \ tweak1_2_##part = (*reinterpret_cast(input + 35 + part * size) ^ \ - *(reinterpret_cast(ctx->state##part) + 24)); \ + *(reinterpret_cast(ctx[part]->state) + 24)); \ } #else # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (VARIANT > 0) { \ - volatile const uint64_t a = *reinterpret_cast(input + 35 + part * size); \ - volatile const uint64_t b = *(reinterpret_cast(ctx->state##part) + 24); \ - tweak1_2_##part = a ^ b; \ + if (IS_V1) { \ + memcpy(&tweak1_2_##part, input + 35 + part * size, sizeof tweak1_2_##part); \ + tweak1_2_##part ^= *(reinterpret_cast(ctx[part]->state) + 24); \ } #endif #define VARIANT1_1(p) \ - if (VARIANT > 0) { \ + if (IS_V1) { \ const uint8_t tmp = reinterpret_cast(p)[11]; \ static const uint32_t table = 0x75310; \ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ @@ -53,9 +55,96 @@ } #define VARIANT1_2(p, part) \ - if (VARIANT > 0) { \ + if (IS_V1) { \ (p) ^= tweak1_2_##part; \ } -#endif /* __CRYPTONIGHT_MONERO_H__ */ +#ifndef XMRIG_ARM +# define VARIANT2_INIT(part) \ + __m128i division_result_xmm_##part = _mm_cvtsi64_si128(h##part[12]); \ + __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(h##part[13]); + +#ifdef _MSC_VER +# define VARIANT2_SET_ROUNDING_MODE() if (VARIANT == xmrig::VARIANT_2) { _control87(RC_DOWN, MCW_RC); } +#else +# define VARIANT2_SET_ROUNDING_MODE() if (VARIANT == xmrig::VARIANT_2) { fesetround(FE_DOWNWARD); } +#endif + +# define VARIANT2_INTEGER_MATH(part, cl, cx) \ + do { \ + const uint64_t sqrt_result = static_cast(_mm_cvtsi128_si64(sqrt_result_xmm_##part)); \ + const uint64_t cx_0 = _mm_cvtsi128_si64(cx); \ + cl ^= static_cast(_mm_cvtsi128_si64(division_result_xmm_##part)) ^ (sqrt_result << 32); \ + const uint32_t d = static_cast(cx_0 + (sqrt_result << 1)) | 0x80000001UL; \ + const uint64_t cx_1 = _mm_cvtsi128_si64(_mm_srli_si128(cx, 8)); \ + const uint64_t division_result = static_cast(cx_1 / d) + ((cx_1 % d) << 32); \ + division_result_xmm_##part = _mm_cvtsi64_si128(static_cast(division_result)); \ + sqrt_result_xmm_##part = int_sqrt_v2(cx_0 + division_result); \ + } while (0) + +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1) \ + do { \ + const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \ + const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ + const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ + } while (0) + +# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ + do { \ + const __m128i chunk1 = _mm_xor_si128(_mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))), _mm_set_epi64x(lo, hi)); \ + const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ + hi ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[0]; \ + lo ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[1]; \ + const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ + _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ + } while (0) + +#else +# define VARIANT2_INIT(part) \ + uint64_t division_result_##part = h##part[12]; \ + uint64_t sqrt_result_##part = h##part[13]; + +# define VARIANT2_INTEGER_MATH(part, cl, cx) \ + do { \ + const uint64_t cx_0 = _mm_cvtsi128_si64(cx); \ + cl ^= division_result_##part ^ (sqrt_result_##part << 32); \ + const uint32_t d = static_cast(cx_0 + (sqrt_result_##part << 1)) | 0x80000001UL; \ + const uint64_t cx_1 = _mm_cvtsi128_si64(_mm_srli_si128(cx, 8)); \ + division_result_##part = static_cast(cx_1 / d) + ((cx_1 % d) << 32); \ + const uint64_t sqrt_input = cx_0 + division_result_##part; \ + sqrt_result_##part = sqrt(sqrt_input + 18446744073709551616.0) * 2.0 - 8589934592.0; \ + const uint64_t s = sqrt_result_##part >> 1; \ + const uint64_t b = sqrt_result_##part & 1; \ + const uint64_t r2 = (uint64_t)(s) * (s + b) + (sqrt_result_##part << 32); \ + sqrt_result_##part += ((r2 + b > sqrt_input) ? -1 : 0) + ((r2 + (1ULL << 32) < sqrt_input - s) ? 1 : 0); \ + } while (0) + +# define VARIANT2_SHUFFLE(base_ptr, offset, _a, _b, _b1) \ + do { \ + const uint64x2_t chunk1 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10))); \ + const uint64x2_t chunk2 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20))); \ + const uint64x2_t chunk3 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ + } while (0) + +# define VARIANT2_SHUFFLE2(base_ptr, offset, _a, _b, _b1, hi, lo) \ + do { \ + const uint64x2_t chunk1 = veorq_u64(vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10))), vcombine_u64(vcreate_u64(hi), vcreate_u64(lo))); \ + const uint64x2_t chunk2 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20))); \ + hi ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[0]; \ + lo ^= ((uint64_t*)((base_ptr) + ((offset) ^ 0x20)))[1]; \ + const uint64x2_t chunk3 = vld1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ + vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ + } while (0) +#endif +#endif /* XMRIG_CRYPTONIGHT_MONERO_H */ diff --git a/src/crypto/CryptoNight_test.h b/src/crypto/CryptoNight_test.h index 695175fb..95e12197 100644 --- a/src/crypto/CryptoNight_test.h +++ b/src/crypto/CryptoNight_test.h @@ -26,54 +26,210 @@ #define __CRYPTONIGHT_TEST_H__ -const static uint8_t test_input[76] = { +const static uint8_t test_input[380] = { + 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, + 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, + 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62, + 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92, + 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01, 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19, 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9, 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F, 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46, - 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02 + 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02, + 0x07, 0x07, 0xB4, 0x87, 0xD0, 0xD6, 0x05, 0x26, 0xE0, 0xC6, 0xDD, 0x9B, 0xC7, 0x18, 0xC3, 0xCF, + 0x52, 0x04, 0xBD, 0x4F, 0x9B, 0x27, 0xF6, 0x73, 0xB9, 0x3F, 0xEF, 0x7B, 0xB2, 0xF7, 0x2B, 0xBB, + 0x3F, 0x3E, 0x9C, 0x3E, 0x9D, 0x33, 0x1E, 0xDE, 0xAD, 0xBE, 0xEF, 0x4E, 0x00, 0x91, 0x81, 0x29, + 0x74, 0xB2, 0x70, 0xE7, 0x6D, 0xD2, 0x2A, 0x5F, 0x52, 0x04, 0x93, 0xE6, 0x18, 0x89, 0x40, 0xD8, + 0xC6, 0xE3, 0x90, 0x6E, 0xAA, 0x6A, 0xB7, 0xE2, 0x08, 0x7E, 0x78, 0x0E, + 0x01, 0x00, 0xEE, 0xB2, 0xD1, 0xD6, 0x05, 0xFF, 0x27, 0x7F, 0x26, 0xDB, 0xAA, 0xB2, 0xC9, 0x26, + 0x30, 0xC6, 0xCF, 0x11, 0x64, 0xEA, 0x6C, 0x8A, 0xE0, 0x98, 0x01, 0xF8, 0x75, 0x4B, 0x49, 0xAF, + 0x79, 0x70, 0xAE, 0xEE, 0xA7, 0x62, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x47, 0x8C, 0x63, 0xE7, 0xD8, + 0x40, 0x02, 0x3C, 0xDA, 0xEA, 0x92, 0x52, 0x53, 0xAC, 0xFD, 0xC7, 0x8A, 0x4C, 0x31, 0xB2, 0xF2, + 0xEC, 0x72, 0x7B, 0xFF, 0xCE, 0xC0, 0xE7, 0x12, 0xD4, 0xE9, 0x2A, 0x01, + 0x07, 0x07, 0xA9, 0xB7, 0xD1, 0xD6, 0x05, 0x3F, 0x0D, 0x5E, 0xFD, 0xC7, 0x03, 0xFC, 0xFC, 0xD2, + 0xCE, 0xBC, 0x44, 0xD8, 0xAB, 0x44, 0xA6, 0xA0, 0x3A, 0xE4, 0x4D, 0x8F, 0x15, 0xAF, 0x62, 0x17, + 0xD1, 0xE0, 0x92, 0x85, 0xE4, 0x73, 0xF9, 0x00, 0x00, 0x00, 0xA0, 0xFC, 0x09, 0xDE, 0xAB, 0xF5, + 0x8B, 0x6F, 0x1D, 0xCA, 0xA8, 0xBA, 0xAC, 0x74, 0xDD, 0x74, 0x19, 0xD5, 0xD6, 0x10, 0xEC, 0x38, + 0xCF, 0x50, 0x29, 0x6A, 0x07, 0x0B, 0x93, 0x8F, 0x8F, 0xA8, 0x10, 0x04 }; -const static uint8_t test_output_v0[32] = { +const static uint8_t test_output_v0[160] = { + 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7, + 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00, 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66, - 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F + 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F, + 0xA1, 0xB4, 0xFA, 0xE3, 0xE5, 0x76, 0xCE, 0xCF, 0xB7, 0x9C, 0xAF, 0x3E, 0x29, 0x92, 0xE4, 0xE0, + 0x31, 0x24, 0x05, 0x48, 0xBF, 0x8D, 0x5F, 0x7B, 0x11, 0x03, 0x60, 0xAA, 0xD7, 0x50, 0x3F, 0x0C, + 0x2D, 0x30, 0xF3, 0x87, 0x4F, 0x86, 0xA1, 0x4A, 0xB5, 0xA2, 0x1A, 0x08, 0xD0, 0x44, 0x2C, 0x9D, + 0x16, 0xE9, 0x28, 0x49, 0xA1, 0xFF, 0x85, 0x6F, 0x12, 0xBB, 0x7D, 0xAB, 0x11, 0x1C, 0xE7, 0xF7, + 0x2D, 0x9D, 0x19, 0xE4, 0xD2, 0x26, 0x44, 0x1E, 0xCD, 0x22, 0x08, 0x24, 0xA8, 0x97, 0x46, 0x62, + 0x04, 0x84, 0x90, 0x4A, 0xEE, 0x99, 0x14, 0xED, 0xB8, 0xC6, 0x0D, 0x37, 0xA1, 0x66, 0x17, 0xB0 }; -// Monero v7 -const static uint8_t test_output_v1[32] = { +// Cryptonight variant 1 (Monero v7) +const static uint8_t test_output_v1[160] = { + 0xF2, 0x2D, 0x3D, 0x62, 0x03, 0xD2, 0xA0, 0x8B, 0x41, 0xD9, 0x02, 0x72, 0x78, 0xD8, 0xBC, 0xC9, + 0x83, 0xAC, 0xAD, 0xA9, 0xB6, 0x8E, 0x52, 0xE3, 0xC6, 0x89, 0x69, 0x2A, 0x50, 0xE9, 0x21, 0xD9, 0xC9, 0xFA, 0xE8, 0x42, 0x5D, 0x86, 0x88, 0xDC, 0x23, 0x6B, 0xCD, 0xBC, 0x42, 0xFD, 0xB4, 0x2D, - 0x37, 0x6C, 0x6E, 0xC1, 0x90, 0x50, 0x1A, 0xA8, 0x4B, 0x04, 0xA4, 0xB4, 0xCF, 0x1E, 0xE1, 0x22 + 0x37, 0x6C, 0x6E, 0xC1, 0x90, 0x50, 0x1A, 0xA8, 0x4B, 0x04, 0xA4, 0xB4, 0xCF, 0x1E, 0xE1, 0x22, + 0xE7, 0x8C, 0x5A, 0x6E, 0x38, 0x30, 0x68, 0x4A, 0x73, 0xFC, 0x1B, 0xC6, 0x6D, 0xFC, 0x8D, 0x98, + 0xB4, 0xC2, 0x23, 0x39, 0xAD, 0xE0, 0x9D, 0xF6, 0x6D, 0x8C, 0x6A, 0xAA, 0xF9, 0xB2, 0xE3, 0x4C, + 0xB6, 0x90, 0x6C, 0xE6, 0x15, 0x5E, 0x46, 0x07, 0x9C, 0xB2, 0x6B, 0xAC, 0x3B, 0xAC, 0x1A, 0xDE, + 0x92, 0x2C, 0xD6, 0x0C, 0x46, 0x9D, 0x9B, 0xC2, 0x84, 0x52, 0x65, 0xF6, 0xBD, 0xFA, 0x0D, 0x74, + 0x00, 0x66, 0x10, 0x07, 0xF1, 0x19, 0x06, 0x3A, 0x6C, 0xFF, 0xEE, 0xB2, 0x40, 0xE5, 0x88, 0x2B, + 0x6C, 0xAB, 0x6B, 0x1D, 0x88, 0xB8, 0x44, 0x25, 0xF4, 0xEA, 0xB7, 0xEC, 0xBA, 0x12, 0x8A, 0x24 +}; + + +// Cryptonight variant 2 (Monero v8) +const static uint8_t test_output_v2[160] = { + 0x97, 0x37, 0x82, 0x82, 0xCF, 0x10, 0xE7, 0xAD, 0x03, 0x3F, 0x7B, 0x80, 0x74, 0xC4, 0x0E, 0x14, + 0xD0, 0x6E, 0x7F, 0x60, 0x9D, 0xDD, 0xDA, 0x78, 0x76, 0x80, 0xB5, 0x8C, 0x05, 0xF4, 0x3D, 0x21, + 0x87, 0x1F, 0xCD, 0x68, 0x23, 0xF6, 0xA8, 0x79, 0xBB, 0x3F, 0x33, 0x95, 0x1C, 0x8E, 0x8E, 0x89, + 0x1D, 0x40, 0x43, 0x88, 0x0B, 0x02, 0xDF, 0xA1, 0xBB, 0x3B, 0xE4, 0x98, 0xB5, 0x0E, 0x75, 0x78, + 0xE6, 0x0D, 0x24, 0x0F, 0x65, 0x85, 0x60, 0x3A, 0x4A, 0xE5, 0x5F, 0x54, 0x9B, 0xC8, 0x79, 0x93, + 0xEB, 0x3D, 0x98, 0x2C, 0xFE, 0x9B, 0xFB, 0x15, 0xB6, 0x88, 0x21, 0x94, 0xB0, 0x05, 0x86, 0x5C, + 0x59, 0x8B, 0x93, 0x7A, 0xDA, 0xD2, 0xA2, 0x14, 0xED, 0xB7, 0xC4, 0x5D, 0xA1, 0xEF, 0x26, 0xF3, + 0xC7, 0x73, 0x29, 0x4D, 0xF1, 0xC8, 0x2C, 0xE0, 0xD0, 0xE9, 0xED, 0x0C, 0x70, 0x75, 0x05, 0x3E, + 0x5B, 0xF6, 0xA0, 0x6E, 0xEA, 0xDE, 0x87, 0x0B, 0x06, 0x29, 0x03, 0xBF, 0xB4, 0x85, 0x9D, 0x04, + 0x75, 0x1A, 0xCD, 0x1E, 0xD6, 0xAA, 0x1B, 0x05, 0x24, 0x6A, 0x2C, 0x80, 0x69, 0x68, 0xDC, 0x97 +}; + + +// Stellite (XTL) +const static uint8_t test_output_xtl[160] = { + 0x8F, 0xE5, 0xF0, 0x5F, 0x02, 0x2A, 0x61, 0x7D, 0xE5, 0x3F, 0x79, 0x36, 0x4B, 0x25, 0xCB, 0xC3, + 0xC0, 0x8E, 0x0E, 0x1F, 0xE3, 0xBE, 0x48, 0x57, 0x07, 0x03, 0xFE, 0xE1, 0xEC, 0x0E, 0xB0, 0xB1, + 0x21, 0x26, 0xFF, 0x98, 0xE6, 0x86, 0x08, 0x5B, 0xC9, 0x96, 0x44, 0xA3, 0xB8, 0x4E, 0x28, 0x90, + 0x76, 0xED, 0xAD, 0xB9, 0xAA, 0xAC, 0x01, 0x94, 0x1D, 0xBE, 0x3E, 0xEA, 0xAD, 0xEE, 0xB2, 0xCF, + 0xB0, 0x43, 0x4B, 0x88, 0xFC, 0xB2, 0xF3, 0x82, 0x9D, 0xD7, 0xDF, 0x51, 0x97, 0x2C, 0x5A, 0xE3, + 0xC7, 0x16, 0x0B, 0xC8, 0x7C, 0xB7, 0x2F, 0x1C, 0x55, 0x33, 0xCA, 0xE1, 0xEE, 0x08, 0xA4, 0x86, + 0x60, 0xED, 0x6E, 0x9D, 0x2D, 0x05, 0x0D, 0x7D, 0x02, 0x49, 0x23, 0x39, 0x7C, 0xC3, 0x6D, 0x3D, + 0x05, 0x51, 0x28, 0xF1, 0x9B, 0x3C, 0xDF, 0xC4, 0xEA, 0x8A, 0xA6, 0x6A, 0x3C, 0x8B, 0xE2, 0xAF, + 0x47, 0x00, 0xFC, 0x36, 0xED, 0x50, 0xBB, 0xD2, 0x2E, 0x63, 0x4B, 0x93, 0x11, 0x0C, 0xA7, 0xBA, + 0x32, 0x6E, 0x47, 0x4D, 0xCE, 0xCC, 0x82, 0x54, 0x1D, 0x06, 0xF8, 0x06, 0x86, 0xBD, 0x22, 0x48 +}; + + +// Masari (MSR) +const static uint8_t test_output_msr[160] = { + 0x3C, 0x7A, 0x61, 0x08, 0x4C, 0x5E, 0xB8, 0x65, 0xB4, 0x98, 0xAB, 0x2F, 0x5A, 0x1A, 0xC5, 0x2C, + 0x49, 0xC1, 0x77, 0xC2, 0xD0, 0x13, 0x34, 0x42, 0xD6, 0x5E, 0xD5, 0x14, 0x33, 0x5C, 0x82, 0xC5, + 0x69, 0xDF, 0x38, 0x51, 0x1B, 0xB3, 0xEB, 0x7D, 0xE7, 0x6B, 0x08, 0x8E, 0xB6, 0x7E, 0xB7, 0x1C, + 0x5F, 0x3C, 0x81, 0xC9, 0xF7, 0xCE, 0xAE, 0x28, 0xC0, 0xFE, 0xEB, 0xBA, 0x0B, 0x40, 0x38, 0x1D, + 0x44, 0xD0, 0xD5, 0xD3, 0x98, 0x1F, 0xA3, 0x0E, 0xE9, 0x89, 0x1A, 0xD7, 0x88, 0xCC, 0x25, 0x76, + 0x9C, 0xFF, 0x4D, 0x7F, 0x9C, 0xCF, 0x48, 0x07, 0x91, 0xF9, 0x82, 0xF5, 0x4C, 0xE9, 0xBD, 0x82, + 0x36, 0x36, 0x64, 0x14, 0xED, 0xB8, 0x54, 0xEE, 0x22, 0xA1, 0x66, 0xA3, 0x87, 0x10, 0x76, 0x1F, + 0x5A, 0xCD, 0x4C, 0x31, 0x4C, 0xBA, 0x41, 0xD2, 0xDB, 0x6C, 0x31, 0x2E, 0x7A, 0x64, 0x15, 0xFF, + 0xA6, 0xD9, 0xB9, 0x7D, 0x1C, 0x3C, 0x98, 0xDD, 0x16, 0xE6, 0xD3, 0xAA, 0xEF, 0xB6, 0xB3, 0x53, + 0x74, 0xD1, 0xAC, 0x5C, 0x04, 0x26, 0x7D, 0x71, 0xDE, 0xAB, 0x66, 0x28, 0x91, 0x3A, 0x6F, 0x4F +}; + + +// Alloy (XAO) +const static uint8_t test_output_xao[160] = { + 0x9A, 0x29, 0xD0, 0xC4, 0xAF, 0xDC, 0x63, 0x9B, 0x65, 0x53, 0xB1, 0xC8, 0x37, 0x35, 0x11, 0x4C, + 0x5D, 0x77, 0x16, 0x21, 0x42, 0x97, 0x5C, 0xB8, 0x50, 0xC0, 0xA5, 0x1F, 0x64, 0x07, 0xBD, 0x33, + 0xF1, 0xC9, 0x98, 0x40, 0x42, 0xDE, 0x39, 0xD1, 0xBA, 0x2D, 0xAD, 0xEC, 0xFE, 0xEA, 0xD8, 0x46, + 0x56, 0x1C, 0x32, 0x90, 0x42, 0x63, 0x10, 0x80, 0xD7, 0x01, 0xE4, 0xE6, 0x20, 0xB3, 0x60, 0x45, + 0x05, 0xE5, 0xC2, 0x18, 0xCD, 0x07, 0xA4, 0x40, 0x42, 0x91, 0xE2, 0xA4, 0x52, 0x54, 0x79, 0xBA, + 0xCD, 0x7E, 0x61, 0x2D, 0x7F, 0x7E, 0x69, 0x5E, 0xD7, 0xC0, 0x06, 0x65, 0xD7, 0xA1, 0xB8, 0xB8, + 0x1E, 0x31, 0x1C, 0xD3, 0xB7, 0xBC, 0x78, 0x3C, 0x01, 0xAF, 0x77, 0xAA, 0xF3, 0x0F, 0x4C, 0xF2, + 0xD1, 0x8B, 0x58, 0xC7, 0xEB, 0x99, 0x91, 0x53, 0x43, 0x71, 0x47, 0x99, 0x9E, 0x04, 0xA4, 0xEA, + 0xB8, 0xA3, 0xB0, 0x9E, 0x09, 0xF5, 0x57, 0x5C, 0xCF, 0x8A, 0xC6, 0xCA, 0x88, 0x51, 0x9A, 0x01, + 0x31, 0xCC, 0x0C, 0xA6, 0x53, 0xB5, 0x5F, 0xFD, 0x7D, 0x29, 0x3A, 0x35, 0xE9, 0x0E, 0x25, 0x6C +}; + + +// Arto (RTO) +const static uint8_t test_output_rto[160] = { + 0x82, 0x66, 0x1E, 0x1C, 0x6E, 0x64, 0x36, 0x66, 0x84, 0x06, 0x32, 0x7A, 0x9B, 0xB1, 0x13, 0x19, + 0xA5, 0x56, 0x16, 0x15, 0xDF, 0xEC, 0x1C, 0x9E, 0xE3, 0x88, 0x4A, 0x6C, 0x1C, 0xEB, 0x76, 0xA5, + 0xB3, 0xFB, 0xF4, 0x3F, 0x2B, 0x6A, 0x3A, 0x39, 0xA3, 0x6E, 0x08, 0x33, 0x67, 0x90, 0x31, 0xB9, + 0x3F, 0x27, 0xE4, 0x79, 0x32, 0x61, 0x6B, 0x5C, 0x8A, 0xF8, 0xAF, 0xC0, 0x60, 0xFD, 0x83, 0xB7, + 0x11, 0x11, 0x89, 0xB4, 0xDC, 0xAE, 0x40, 0xC8, 0x64, 0xAA, 0x4D, 0x19, 0x23, 0x7B, 0xD3, 0x27, + 0xB2, 0x0F, 0xA7, 0x50, 0x7D, 0xCA, 0xF5, 0x03, 0x06, 0xB2, 0x26, 0x62, 0xF3, 0x68, 0x2D, 0x30, + 0x6F, 0x93, 0x1E, 0xFF, 0xCD, 0x85, 0x40, 0x28, 0x5F, 0xC3, 0x8C, 0x76, 0x51, 0x9E, 0xD5, 0x06, + 0x32, 0xD6, 0x35, 0x83, 0xF6, 0x3B, 0x54, 0x4F, 0xA1, 0x9C, 0x13, 0xD8, 0xC4, 0x0E, 0x01, 0x2F, + 0x29, 0xDB, 0x8C, 0x1C, 0xB7, 0x06, 0x86, 0x79, 0x6D, 0xFF, 0x9F, 0x89, 0x3B, 0x3A, 0xA5, 0x79, + 0xE7, 0x81, 0x4E, 0x2A, 0xBD, 0x62, 0xC1, 0x1B, 0x7C, 0xB9, 0x33, 0x7B, 0xEE, 0x95, 0x80, 0xB3 }; #ifndef XMRIG_NO_AEON -const static uint8_t test_output_v0_lite[32] = { +const static uint8_t test_output_v0_lite[160] = { + 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E, + 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88, 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE, - 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD + 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD, + 0x38, 0x08, 0xE1, 0x17, 0x0B, 0x99, 0x8D, 0x1A, 0x3C, 0xCE, 0x35, 0xC5, 0xC7, 0x3A, 0x00, 0x2E, + 0xCB, 0x54, 0xF0, 0x78, 0x2E, 0x9E, 0xDB, 0xC7, 0xDF, 0x2E, 0x71, 0x9A, 0x16, 0x97, 0xC4, 0x18, + 0x4B, 0x97, 0x07, 0xFE, 0x5D, 0x98, 0x9A, 0xD6, 0xD8, 0xE5, 0x92, 0x66, 0x87, 0x7F, 0x19, 0x37, + 0xA2, 0x5E, 0xE6, 0x96, 0xB5, 0x97, 0x33, 0x89, 0xE0, 0xA7, 0xC9, 0xDD, 0x4A, 0x7E, 0x9E, 0x53, + 0xBE, 0x91, 0x2B, 0xF5, 0xF5, 0xAF, 0xDD, 0x09, 0xA2, 0xF4, 0xA4, 0x56, 0xEB, 0x96, 0x22, 0xC9, + 0x94, 0xFB, 0x7B, 0x28, 0xC9, 0x97, 0x65, 0x04, 0xAC, 0x4F, 0x84, 0x71, 0xDA, 0x6E, 0xD8, 0xC5 }; -// AEON v2 -const static uint8_t test_output_v1_lite[32] = { +// AEON v7 +const static uint8_t test_output_v1_lite[160] = { + 0x6D, 0x8C, 0xDC, 0x44, 0x4E, 0x9B, 0xBB, 0xFD, 0x68, 0xFC, 0x43, 0xFC, 0xD4, 0x85, 0x5B, 0x22, + 0x8C, 0x8A, 0x1B, 0xD9, 0x1D, 0x9D, 0x00, 0x28, 0x5B, 0xEC, 0x02, 0xB7, 0xCA, 0x2D, 0x67, 0x41, 0x87, 0xC4, 0xE5, 0x70, 0x65, 0x3E, 0xB4, 0xC2, 0xB4, 0x2B, 0x7A, 0x0D, 0x54, 0x65, 0x59, 0x45, - 0x2D, 0xFA, 0xB5, 0x73, 0xB8, 0x2E, 0xC5, 0x2F, 0x15, 0x2B, 0x7F, 0xF9, 0x8E, 0x79, 0x44, 0x6F + 0x2D, 0xFA, 0xB5, 0x73, 0xB8, 0x2E, 0xC5, 0x2F, 0x15, 0x2B, 0x7F, 0xF9, 0x8E, 0x79, 0x44, 0x6F, + 0x16, 0x08, 0x74, 0xC7, 0xA2, 0xD2, 0xA3, 0x97, 0x95, 0x76, 0xCA, 0x4D, 0x06, 0x39, 0x7A, 0xAB, + 0x6C, 0x87, 0x58, 0x33, 0x4D, 0xC8, 0x5A, 0xAB, 0x04, 0x27, 0xFE, 0x8B, 0x1C, 0x23, 0x2F, 0x32, + 0xC0, 0x44, 0xFF, 0x0D, 0xB5, 0x3B, 0x27, 0x96, 0x06, 0x89, 0x7B, 0xA3, 0x0B, 0xD0, 0xCE, 0x9E, + 0x90, 0x22, 0x77, 0x5A, 0xAD, 0xA1, 0xE5, 0xB6, 0xFC, 0xCB, 0x39, 0x7E, 0x2B, 0x10, 0xEE, 0xB4, + 0x8C, 0x2B, 0xA4, 0x1F, 0x60, 0x76, 0x39, 0xD7, 0xF6, 0x46, 0x77, 0x18, 0x20, 0xAD, 0xD4, 0xC9, + 0x87, 0xF7, 0x37, 0xDA, 0xFD, 0xBA, 0xBA, 0xD2, 0xF2, 0x68, 0xDC, 0x26, 0x8D, 0x1B, 0x08, 0xC6 }; #endif #ifndef XMRIG_NO_SUMO -const static uint8_t test_output_heavy[32] = { +const static uint8_t test_output_v0_heavy[160] = { + 0x99, 0x83, 0xF2, 0x1B, 0xDF, 0x20, 0x10, 0xA8, 0xD7, 0x07, 0xBB, 0x2F, 0x14, 0xD7, 0x86, 0x64, + 0xBB, 0xE1, 0x18, 0x7F, 0x55, 0x01, 0x4B, 0x39, 0xE5, 0xF3, 0xD6, 0x93, 0x28, 0xE4, 0x8F, 0xC2, 0x4D, 0x94, 0x7D, 0xD6, 0xDB, 0x6E, 0x07, 0x48, 0x26, 0x4A, 0x51, 0x2E, 0xAC, 0xF3, 0x25, 0x4A, - 0x1F, 0x1A, 0xA2, 0x5B, 0xFC, 0x0A, 0xAD, 0x82, 0xDE, 0xA8, 0x99, 0x96, 0x88, 0x52, 0xD2, 0x7D + 0x1F, 0x1A, 0xA2, 0x5B, 0xFC, 0x0A, 0xAD, 0x82, 0xDE, 0xA8, 0x99, 0x96, 0x88, 0x52, 0xD2, 0x7D, + 0x3E, 0xE1, 0x23, 0x03, 0x5A, 0x63, 0x7B, 0x66, 0xF6, 0xD7, 0xC2, 0x2A, 0x34, 0x5E, 0x88, 0xE7, + 0xFA, 0xC4, 0x25, 0x36, 0x54, 0xCB, 0xD2, 0x5C, 0x2F, 0x80, 0x2A, 0xF9, 0xCC, 0x43, 0xF7, 0xCD, + 0xE5, 0x18, 0xA8, 0x05, 0x60, 0x18, 0xA5, 0x73, 0x72, 0x9B, 0x32, 0xDC, 0x69, 0x83, 0xC1, 0xE1, + 0x1F, 0xDB, 0xDA, 0x6B, 0xAC, 0xEC, 0x9F, 0x67, 0xF8, 0x27, 0x1D, 0xC7, 0xE6, 0x46, 0x42, 0xF9, + 0x53, 0x62, 0x0A, 0x54, 0x7D, 0x43, 0xEA, 0x18, 0x94, 0xED, 0xD8, 0x92, 0x06, 0x6A, 0xA1, 0x51, + 0xAD, 0xB1, 0xFD, 0x89, 0xFB, 0x5C, 0xB4, 0x25, 0x6A, 0xDD, 0xB0, 0x09, 0xC5, 0x72, 0x87, 0xEB }; -#endif -#ifndef XMRIG_NO_IPBC -const static uint8_t test_output_ipbc[32] = { - 0xb2, 0x47, 0x86, 0xf0, 0x7f, 0x6f, 0x4b, 0x55, 0x3e, 0xa1, 0xbb, 0xe8, 0xa1, 0x75, 0x00, 0x2d, - 0x07, 0x9a, 0x21, 0x0e, 0xbd, 0x06, 0x6a, 0xb0, 0xfd, 0x96, 0x9e, 0xe6, 0xe4, 0x69, 0x67, 0xbb +const static uint8_t test_output_xhv_heavy[160] = { + 0x5A, 0xC3, 0xF7, 0x85, 0xC4, 0x90, 0xC5, 0x85, 0x50, 0xEC, 0x95, 0xD2, 0x72, 0x65, 0x63, 0x57, + 0x7E, 0x7C, 0x1C, 0x21, 0x2D, 0x0C, 0xDE, 0x59, 0x12, 0x73, 0x20, 0x1E, 0x44, 0xFD, 0xD5, 0xB6, + 0x1F, 0x4E, 0xB2, 0x0A, 0x36, 0x51, 0x4B, 0xF5, 0x4D, 0xC9, 0xE0, 0x90, 0x2C, 0x16, 0x47, 0x3F, + 0xDE, 0x18, 0x29, 0x8E, 0xBB, 0x34, 0x2B, 0xEF, 0x7A, 0x04, 0x22, 0xD1, 0xB1, 0xF2, 0x48, 0xDA, + 0xE3, 0x7F, 0x4B, 0x4C, 0xB4, 0xDF, 0xE8, 0xD3, 0x70, 0xE2, 0xE7, 0x44, 0x25, 0x87, 0x12, 0xF9, + 0x8F, 0x28, 0x0B, 0xCE, 0x2C, 0xEE, 0xDD, 0x88, 0x94, 0x35, 0x48, 0x51, 0xAE, 0xC8, 0x9C, 0x0B, + 0xED, 0x2F, 0xE6, 0x0F, 0x39, 0x05, 0xB4, 0x4A, 0x8F, 0x38, 0x44, 0x2D, 0x4B, 0xE9, 0x7B, 0x81, + 0xC6, 0xB0, 0xE0, 0x0A, 0x39, 0x8C, 0x38, 0xFE, 0x63, 0x31, 0x47, 0x65, 0x0D, 0x2B, 0xF4, 0x96, + 0x13, 0x91, 0x89, 0xB4, 0x5B, 0xA9, 0x2A, 0x7A, 0x09, 0x65, 0x14, 0x20, 0x76, 0x24, 0x6C, 0x80, + 0x1D, 0x3F, 0x9F, 0xCD, 0x68, 0x39, 0xA9, 0x42, 0x27, 0xC1, 0x0C, 0x53, 0x98, 0x35, 0x60, 0x7A +}; + + +// TUBE +const static uint8_t test_output_tube_heavy[160] = { + 0xFE, 0x53, 0x35, 0x20, 0x76, 0xEA, 0xE6, 0x89, 0xFA, 0x3B, 0x4F, 0xDA, 0x61, 0x46, 0x34, 0xCF, + 0xC3, 0x12, 0xEE, 0x0C, 0x38, 0x7D, 0xF2, 0xB8, 0xB7, 0x4D, 0xA2, 0xA1, 0x59, 0x74, 0x12, 0x35, + 0xCD, 0x3F, 0x29, 0xDF, 0x07, 0x4A, 0x14, 0xAD, 0x0B, 0x98, 0x99, 0x37, 0xCA, 0x14, 0x68, 0xA3, + 0x8D, 0xAE, 0x86, 0xC1, 0xA3, 0x54, 0x05, 0xBE, 0xEA, 0x6D, 0x29, 0x24, 0x0C, 0x82, 0x97, 0x74, + 0xA0, 0x64, 0x77, 0xCD, 0x8D, 0x8A, 0xC3, 0x10, 0xB4, 0x89, 0x0E, 0xBB, 0x7D, 0xE6, 0x32, 0x8F, + 0xF4, 0x2D, 0xB6, 0x9E, 0x8A, 0xF9, 0xF8, 0xEE, 0x2C, 0xD0, 0x74, 0xED, 0xA9, 0xAA, 0xA1, 0xFB, + 0xE2, 0xC9, 0x89, 0x66, 0xD6, 0x66, 0x52, 0xA2, 0x16, 0xDA, 0x36, 0xA0, 0x10, 0x62, 0xD2, 0xB1, + 0x76, 0xD1, 0x31, 0xE9, 0x1C, 0x08, 0xB6, 0xCA, 0xAF, 0x89, 0xB9, 0x3D, 0x2C, 0xFA, 0x9A, 0x30, + 0x74, 0x6A, 0x96, 0xA1, 0x95, 0x6C, 0xBB, 0x46, 0x4D, 0xE0, 0xEB, 0x28, 0xBE, 0x2A, 0x8C, 0x34, + 0x57, 0x79, 0xBE, 0x52, 0xFB, 0xBC, 0x68, 0x43, 0x45, 0xF4, 0xDF, 0xA5, 0xA8, 0xFD, 0x55, 0xA6 }; #endif diff --git a/src/crypto/CryptoNight_x86.h b/src/crypto/CryptoNight_x86.h index 481dd35b..8dcdd414 100644 --- a/src/crypto/CryptoNight_x86.h +++ b/src/crypto/CryptoNight_x86.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -22,8 +23,8 @@ * along with this program. If not, see . */ -#ifndef __CRYPTONIGHT_X86_H__ -#define __CRYPTONIGHT_X86_H__ +#ifndef XMRIG_CRYPTONIGHT_X86_H +#define XMRIG_CRYPTONIGHT_X86_H #ifdef __GNUC__ @@ -34,6 +35,7 @@ #endif +#include "common/crypto/keccak.h" #include "crypto/CryptoNight.h" #include "crypto/CryptoNight_constants.h" #include "crypto/CryptoNight_monero.h" @@ -42,7 +44,6 @@ extern "C" { -#include "crypto/c_keccak.h" #include "crypto/c_groestl.h" #include "crypto/c_blake256.h" #include "crypto/c_jh.h" @@ -73,10 +74,7 @@ static inline void do_skein_hash(const uint8_t *input, size_t len, uint8_t *outp void (* const extra_hashes[4])(const uint8_t *, size_t, uint8_t *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; - #if defined(__x86_64__) || defined(_M_AMD64) -# define EXTRACT64(X) _mm_cvtsi128_si64(X) - # ifdef __GNUC__ static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi) { @@ -88,13 +86,14 @@ static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi) #define __umul128 _umul128 # endif #elif defined(__i386__) || defined(_M_IX86) -# define HI32(X) \ - _mm_srli_si128((X), 4) - +static inline int64_t _mm_cvtsi128_si64(__m128i a) +{ + return ((uint64_t)(uint32_t)_mm_cvtsi128_si32(a) | ((uint64_t)(uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(a, 4)) << 32)); +} -# define EXTRACT64(X) \ - ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ - ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32)) +static inline __m128i _mm_cvtsi64_si128(int64_t a) { + return _mm_set_epi64x(0, a); +} static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) { // multiplier = ab = a * 2^32 + b @@ -386,83 +385,715 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) } -template -inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx *__restrict__ ctx) +static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) +{ + alignas(16) uint32_t k[4]; + alignas(16) uint32_t x[4]; + + _mm_store_si128((__m128i*) k, key); + _mm_store_si128((__m128i*) x, _mm_xor_si128(in, _mm_set_epi64x(0xffffffffffffffff, 0xffffffffffffffff))); + + #define BYTE(p, i) ((unsigned char*)&x[p])[i] + k[0] ^= saes_table[0][BYTE(0, 0)] ^ saes_table[1][BYTE(1, 1)] ^ saes_table[2][BYTE(2, 2)] ^ saes_table[3][BYTE(3, 3)]; + x[0] ^= k[0]; + k[1] ^= saes_table[0][BYTE(1, 0)] ^ saes_table[1][BYTE(2, 1)] ^ saes_table[2][BYTE(3, 2)] ^ saes_table[3][BYTE(0, 3)]; + x[1] ^= k[1]; + k[2] ^= saes_table[0][BYTE(2, 0)] ^ saes_table[1][BYTE(3, 1)] ^ saes_table[2][BYTE(0, 2)] ^ saes_table[3][BYTE(1, 3)]; + x[2] ^= k[2]; + k[3] ^= saes_table[0][BYTE(3, 0)] ^ saes_table[1][BYTE(0, 1)] ^ saes_table[2][BYTE(1, 2)] ^ saes_table[3][BYTE(2, 3)]; + #undef BYTE + + return _mm_load_si128((__m128i*)k); +} + + +static inline __m128i int_sqrt_v2(const uint64_t n0) +{ + __m128d x = _mm_castsi128_pd(_mm_add_epi64(_mm_cvtsi64_si128(n0 >> 12), _mm_set_epi64x(0, 1023ULL << 52))); + x = _mm_sqrt_sd(_mm_setzero_pd(), x); + uint64_t r = static_cast(_mm_cvtsi128_si64(_mm_castpd_si128(x))); + + const uint64_t s = r >> 20; + r >>= 19; + + uint64_t x2 = (s - (1022ULL << 32)) * (r - s - (1022ULL << 32) + 1); +# if (defined(_MSC_VER) || __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 1)) && (defined(__x86_64__) || defined(_M_AMD64)) + _addcarry_u64(_subborrow_u64(0, x2, n0, (unsigned long long int*)&x2), r, 0, (unsigned long long int*)&r); +# else + if (x2 < n0) ++r; +# endif + + return _mm_cvtsi64_si128(r); +} + + +template +static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i cx) +{ + if (VARIANT == xmrig::VARIANT_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1); + _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); + } else { + __m128i tmp = _mm_xor_si128(bx0, cx); + mem_out[0] = _mm_cvtsi128_si64(tmp); + + tmp = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(tmp), _mm_castsi128_ps(tmp))); + uint64_t vh = _mm_cvtsi128_si64(tmp); + + uint8_t x = static_cast(vh >> 24); + static const uint16_t table = 0x7531; + const uint8_t index = (((x >> (VARIANT == xmrig::VARIANT_XTL ? 4 : 3)) & 6) | (x & 1)) << 1; + vh ^= ((table >> index) & 0x3) << 28; + + mem_out[1] = vh; + } +} + + +template +inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) { constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; - if (VARIANT > 0 && size < 43) { + if (IS_V1 && size < 43) { memset(output, 0, 32); return; } - keccak(input, (int) size, ctx->state0, 200); + xmrig::keccak(input, size, ctx[0]->state); - VARIANT1_INIT(0); + cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); - cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory); + const uint8_t* l0 = ctx[0]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); - const uint8_t* l0 = ctx->memory; - uint64_t* h0 = reinterpret_cast(ctx->state0); + VARIANT1_INIT(0); + VARIANT2_INIT(0); + VARIANT2_SET_ROUNDING_MODE(); uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); - uint64_t idx0 = h0[0] ^ h0[4]; + uint64_t idx0 = al0; for (size_t i = 0; i < ITERATIONS; i++) { __m128i cx; + if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { + cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + } - if (SOFT_AES) { - cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], _mm_set_epi64x(ah0, al0)); + const __m128i ax0 = _mm_set_epi64x(ah0, al0); + if (VARIANT == xmrig::VARIANT_TUBE) { + cx = aes_round_tweak_div(cx, ax0); + } + else if (SOFT_AES) { + cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0); } else { - cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); - cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0)); + cx = _mm_aesenc_si128(cx, ax0); } - _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); - VARIANT1_1(&l0[idx0 & MASK]); - idx0 = EXTRACT64(cx); - bx0 = cx; + + if (IS_V1 || VARIANT == xmrig::VARIANT_2) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx0, bx1, cx); + } else { + _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + } + + idx0 = _mm_cvtsi128_si64(cx); uint64_t hi, lo, cl, ch; cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - lo = __umul128(idx0, cl, &hi); + if (VARIANT == xmrig::VARIANT_2) { + VARIANT2_INTEGER_MATH(0, cl, cx); + lo = __umul128(idx0, cl, &hi); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo); + } + else { + lo = __umul128(idx0, cl, &hi); + } al0 += hi; ah0 += lo; - VARIANT1_2(ah0, 0); ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; - VARIANT1_2(ah0, 0); - if (ALGO == xmrig::CRYPTONIGHT_IPBC) { - ((uint64_t*)&l0[idx0 & MASK])[1] ^= ((uint64_t*)&l0[idx0 & MASK])[0]; - } + if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } else if (IS_V1) { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; + } else { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; + } + + al0 ^= cl; ah0 ^= ch; + idx0 = al0; + + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; + int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; + int64_t q = n / (d | 0x5); + + ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; + + if (VARIANT == xmrig::VARIANT_XHV) { + d = ~d; + } + + idx0 = d ^ q; + } + if (VARIANT == xmrig::VARIANT_2) { + bx1 = bx0; + } + bx0 = cx; + } + + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); + + xmrig::keccakf(h0, 24); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); +} + + +#ifndef XMRIG_NO_ASM +extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx *ctx); +extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx* ctx0, cryptonight_ctx* ctx1); + + +template +inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MEM = xmrig::cn_select_memory(); + + xmrig::keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + + if (ASM == xmrig::ASM_INTEL) { + cnv2_mainloop_ivybridge_asm(ctx[0]); + } + else { + cnv2_mainloop_ryzen_asm(ctx[0]); + } + + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); +} + + +template +inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MEM = xmrig::cn_select_memory(); + + xmrig::keccak(input, size, ctx[0]->state); + xmrig::keccak(input + size, size, ctx[1]->state); + + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); + + cnv2_double_mainloop_sandybridge_asm(ctx[0], ctx[1]); + + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); + + xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); + xmrig::keccakf(reinterpret_cast(ctx[1]->state), 24); + + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); + extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); +} +#endif + + +template +inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + + if (IS_V1 && size < 43) { + memset(output, 0, 64); + return; + } + + xmrig::keccak(input, size, ctx[0]->state); + xmrig::keccak(input + size, size, ctx[1]->state); + + const uint8_t* l0 = ctx[0]->memory; + const uint8_t* l1 = ctx[1]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); + uint64_t* h1 = reinterpret_cast(ctx[1]->state); + + VARIANT1_INIT(0); + VARIANT1_INIT(1); + VARIANT2_INIT(0); + VARIANT2_INIT(1); + VARIANT2_SET_ROUNDING_MODE(); + + cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); + cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + + uint64_t al0 = h0[0] ^ h0[4]; + uint64_t al1 = h1[0] ^ h1[4]; + uint64_t ah0 = h0[1] ^ h0[5]; + uint64_t ah1 = h1[1] ^ h1[5]; + + __m128i bx00 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i bx01 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); + __m128i bx10 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); + __m128i bx11 = _mm_set_epi64x(h1[9] ^ h1[11], h1[8] ^ h1[10]); + + uint64_t idx0 = al0; + uint64_t idx1 = al1; + + for (size_t i = 0; i < ITERATIONS; i++) { + __m128i cx0, cx1; + if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { + cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); + } + + const __m128i ax0 = _mm_set_epi64x(ah0, al0); + const __m128i ax1 = _mm_set_epi64x(ah1, al1); + if (VARIANT == xmrig::VARIANT_TUBE) { + cx0 = aes_round_tweak_div(cx0, ax0); + cx1 = aes_round_tweak_div(cx1, ax1); + } + else if (SOFT_AES) { + cx0 = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0); + cx1 = soft_aesenc((uint32_t*)&l1[idx1 & MASK], ax1); + } + else { + cx0 = _mm_aesenc_si128(cx0, ax0); + cx1 = _mm_aesenc_si128(cx1, ax1); + } + + if (IS_V1 || (VARIANT == xmrig::VARIANT_2)) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); + } else { + _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); + _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); + } + + idx0 = _mm_cvtsi128_si64(cx0); + idx1 = _mm_cvtsi128_si64(cx1); + + uint64_t hi, lo, cl, ch; + cl = ((uint64_t*) &l0[idx0 & MASK])[0]; + ch = ((uint64_t*) &l0[idx0 & MASK])[1]; + if (VARIANT == xmrig::VARIANT_2) { + VARIANT2_INTEGER_MATH(0, cl, cx0); + lo = __umul128(idx0, cl, &hi); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo); + } else { + lo = __umul128(idx0, cl, &hi); + } + + al0 += hi; + ah0 += lo; + + ((uint64_t*)&l0[idx0 & MASK])[0] = al0; + + if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } else if (IS_V1) { + ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; + } else { + ((uint64_t*) &l0[idx0 & MASK])[1] = ah0; + } + al0 ^= cl; + ah0 ^= ch; idx0 = al0; if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { - int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; - int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; + int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; + int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; + + if (VARIANT == xmrig::VARIANT_XHV) { + d = ~d; + } + idx0 = d ^ q; } + + cl = ((uint64_t*) &l1[idx1 & MASK])[0]; + ch = ((uint64_t*) &l1[idx1 & MASK])[1]; + if (VARIANT == xmrig::VARIANT_2) { + VARIANT2_INTEGER_MATH(1, cl, cx1); + lo = __umul128(idx1, cl, &hi); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo); + } else { + lo = __umul128(idx1, cl, &hi); + } + + al1 += hi; + ah1 += lo; + + ((uint64_t*)&l1[idx1 & MASK])[0] = al1; + + if (IS_V1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; + } else if (IS_V1) { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; + } else { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; + } + + al1 ^= cl; + ah1 ^= ch; + idx1 = al1; + + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + int64_t n = ((int64_t*)&l1[idx1 & MASK])[0]; + int32_t d = ((int32_t*)&l1[idx1 & MASK])[2]; + int64_t q = n / (d | 0x5); + + ((int64_t*)&l1[idx1 & MASK])[0] = n ^ q; + + if (VARIANT == xmrig::VARIANT_XHV) { + d = ~d; + } + + idx1 = d ^ q; + } + + if (VARIANT == xmrig::VARIANT_2) { + bx01 = bx00; + bx11 = bx10; + } + bx00 = cx0; + bx10 = cx1; + } + + cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); + cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + + xmrig::keccakf(h0, 24); + xmrig::keccakf(h1, 24); + + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); + extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); +} + + +#define CN_STEP1(a, b0, b1, c, l, ptr, idx) \ + ptr = reinterpret_cast<__m128i*>(&l[idx & MASK]); \ + c = _mm_load_si128(ptr); + + +#define CN_STEP2(a, b0, b1, c, l, ptr, idx) \ + if (VARIANT == xmrig::VARIANT_TUBE) { \ + c = aes_round_tweak_div(c, a); \ + } \ + else if (SOFT_AES) { \ + c = soft_aesenc(c, a); \ + } else { \ + c = _mm_aesenc_si128(c, a); \ + } \ + \ + if (IS_V1 || (VARIANT == xmrig::VARIANT_2)) { \ + cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ + } else { \ + _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ + } + + +#define CN_STEP3(part, a, b0, b1, c, l, ptr, idx) \ + idx = _mm_cvtsi128_si64(c); \ + ptr = reinterpret_cast<__m128i*>(&l[idx & MASK]); \ + uint64_t cl##part = ((uint64_t*)ptr)[0]; \ + uint64_t ch##part = ((uint64_t*)ptr)[1]; + + +#define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ + if (VARIANT == xmrig::VARIANT_2) { \ + VARIANT2_INTEGER_MATH(part, cl##part, c); \ + lo = __umul128(idx, cl##part, &hi); \ + VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo); \ + } else { \ + lo = __umul128(idx, cl##part, &hi); \ + } \ + a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ + \ + if (IS_V1) { \ + _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ + \ + if (VARIANT == xmrig::VARIANT_TUBE || \ + VARIANT == xmrig::VARIANT_RTO) { \ + ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ + } \ + } else { \ + _mm_store_si128(ptr, a); \ + } \ + \ + a = _mm_xor_si128(a, _mm_set_epi64x(ch##part, cl##part)); \ + idx = _mm_cvtsi128_si64(a); \ + \ + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { \ + int64_t n = ((int64_t*)&l[idx & MASK])[0]; \ + int32_t d = ((int32_t*)&l[idx & MASK])[2]; \ + int64_t q = n / (d | 0x5); \ + ((int64_t*)&l[idx & MASK])[0] = n ^ q; \ + if (VARIANT == xmrig::VARIANT_XHV) { \ + d = ~d; \ + } \ + \ + idx = d ^ q; \ + } \ + if (VARIANT == xmrig::VARIANT_2) { \ + b1 = b0; \ + } \ + b0 = c; + + +#define CONST_INIT(ctx, n) \ + __m128i mc##n; \ + __m128i division_result_xmm_##n; \ + __m128i sqrt_result_xmm_##n; \ + if (IS_V1) { \ + mc##n = _mm_set_epi64x(*reinterpret_cast(input + n * size + 35) ^ \ + *(reinterpret_cast((ctx)->state) + 24), 0); \ + } \ + if (VARIANT == xmrig::VARIANT_2) { \ + division_result_xmm_##n = _mm_cvtsi64_si128(h##n[12]); \ + sqrt_result_xmm_##n = _mm_cvtsi64_si128(h##n[13]); \ + } \ + __m128i ax##n = _mm_set_epi64x(h##n[1] ^ h##n[5], h##n[0] ^ h##n[4]); \ + __m128i bx##n##0 = _mm_set_epi64x(h##n[3] ^ h##n[7], h##n[2] ^ h##n[6]); \ + __m128i bx##n##1 = _mm_set_epi64x(h##n[9] ^ h##n[11], h##n[8] ^ h##n[10]); \ + __m128i cx##n = _mm_setzero_si128(); + + +template +inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + + if (IS_V1 && size < 43) { + memset(output, 0, 32 * 3); + return; } - cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0); + for (size_t i = 0; i < 3; i++) { + xmrig::keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + } + + uint8_t* l0 = ctx[0]->memory; + uint8_t* l1 = ctx[1]->memory; + uint8_t* l2 = ctx[2]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); + uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint64_t* h2 = reinterpret_cast(ctx[2]->state); + + CONST_INIT(ctx[0], 0); + CONST_INIT(ctx[1], 1); + CONST_INIT(ctx[2], 2); + VARIANT2_SET_ROUNDING_MODE(); + + uint64_t idx0, idx1, idx2; + idx0 = _mm_cvtsi128_si64(ax0); + idx1 = _mm_cvtsi128_si64(ax1); + idx2 = _mm_cvtsi128_si64(ax2); + + for (size_t i = 0; i < ITERATIONS; i++) { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2; + + CN_STEP1(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx20, bx21, cx2, l2, ptr2, idx2); - keccakf(h0, 24); - extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output); + CN_STEP2(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx20, bx21, cx2, l2, ptr2, idx2); + + CN_STEP3(0, ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP3(1, ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP3(2, ax2, bx20, bx21, cx2, l2, ptr2, idx2); + + CN_STEP4(0, ax0, bx00, bx01, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(1, ax1, bx10, bx11, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(2, ax2, bx20, bx21, cx2, l2, mc2, ptr2, idx2); + } + + for (size_t i = 0; i < 3; i++) { + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); + } } -#endif /* __CRYPTONIGHT_X86_H__ */ +template +inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1;; + + if (IS_V1 && size < 43) { + memset(output, 0, 32 * 4); + return; + } + + for (size_t i = 0; i < 4; i++) { + xmrig::keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + } + + uint8_t* l0 = ctx[0]->memory; + uint8_t* l1 = ctx[1]->memory; + uint8_t* l2 = ctx[2]->memory; + uint8_t* l3 = ctx[3]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); + uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint64_t* h2 = reinterpret_cast(ctx[2]->state); + uint64_t* h3 = reinterpret_cast(ctx[3]->state); + + CONST_INIT(ctx[0], 0); + CONST_INIT(ctx[1], 1); + CONST_INIT(ctx[2], 2); + CONST_INIT(ctx[3], 3); + VARIANT2_SET_ROUNDING_MODE(); + + uint64_t idx0, idx1, idx2, idx3; + idx0 = _mm_cvtsi128_si64(ax0); + idx1 = _mm_cvtsi128_si64(ax1); + idx2 = _mm_cvtsi128_si64(ax2); + idx3 = _mm_cvtsi128_si64(ax3); + + for (size_t i = 0; i < ITERATIONS; i++) + { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2, *ptr3; + + CN_STEP1(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP1(ax3, bx30, bx31, cx3, l3, ptr3, idx3); + + CN_STEP2(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP2(ax3, bx30, bx31, cx3, l3, ptr3, idx3); + + CN_STEP3(0, ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP3(1, ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP3(2, ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP3(3, ax3, bx30, bx31, cx3, l3, ptr3, idx3); + + CN_STEP4(0, ax0, bx00, bx01, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(1, ax1, bx10, bx11, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(2, ax2, bx20, bx21, cx2, l2, mc2, ptr2, idx2); + CN_STEP4(3, ax3, bx30, bx31, cx3, l3, mc3, ptr3, idx3); + } + + for (size_t i = 0; i < 4; i++) { + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); + } +} + + +template +inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) +{ + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + + if (IS_V1 && size < 43) { + memset(output, 0, 32 * 5); + return; + } + + for (size_t i = 0; i < 5; i++) { + xmrig::keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + } + + uint8_t* l0 = ctx[0]->memory; + uint8_t* l1 = ctx[1]->memory; + uint8_t* l2 = ctx[2]->memory; + uint8_t* l3 = ctx[3]->memory; + uint8_t* l4 = ctx[4]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); + uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint64_t* h2 = reinterpret_cast(ctx[2]->state); + uint64_t* h3 = reinterpret_cast(ctx[3]->state); + uint64_t* h4 = reinterpret_cast(ctx[4]->state); + + CONST_INIT(ctx[0], 0); + CONST_INIT(ctx[1], 1); + CONST_INIT(ctx[2], 2); + CONST_INIT(ctx[3], 3); + CONST_INIT(ctx[4], 4); + VARIANT2_SET_ROUNDING_MODE(); + + uint64_t idx0, idx1, idx2, idx3, idx4; + idx0 = _mm_cvtsi128_si64(ax0); + idx1 = _mm_cvtsi128_si64(ax1); + idx2 = _mm_cvtsi128_si64(ax2); + idx3 = _mm_cvtsi128_si64(ax3); + idx4 = _mm_cvtsi128_si64(ax4); + + for (size_t i = 0; i < ITERATIONS; i++) + { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2, *ptr3, *ptr4; + + CN_STEP1(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP1(ax3, bx30, bx31, cx3, l3, ptr3, idx3); + CN_STEP1(ax4, bx40, bx41, cx4, l4, ptr4, idx4); + + CN_STEP2(ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP2(ax3, bx30, bx31, cx3, l3, ptr3, idx3); + CN_STEP2(ax4, bx40, bx41, cx4, l4, ptr4, idx4); + + CN_STEP3(0, ax0, bx00, bx01, cx0, l0, ptr0, idx0); + CN_STEP3(1, ax1, bx10, bx11, cx1, l1, ptr1, idx1); + CN_STEP3(2, ax2, bx20, bx21, cx2, l2, ptr2, idx2); + CN_STEP3(3, ax3, bx30, bx31, cx3, l3, ptr3, idx3); + CN_STEP3(4, ax4, bx40, bx41, cx4, l4, ptr4, idx4); + + CN_STEP4(0, ax0, bx00, bx01, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(1, ax1, bx10, bx11, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(2, ax2, bx20, bx21, cx2, l2, mc2, ptr2, idx2); + CN_STEP4(3, ax3, bx30, bx31, cx3, l3, mc3, ptr3, idx3); + CN_STEP4(4, ax4, bx40, bx41, cx4, l4, mc4, ptr4, idx4); + } + + for (size_t i = 0; i < 5; i++) { + cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); + } +} + +#endif /* XMRIG_CRYPTONIGHT_X86_H */ diff --git a/src/crypto/soft_aes.h b/src/crypto/soft_aes.h index 0703f98d..26c1b06a 100644 --- a/src/crypto/soft_aes.h +++ b/src/crypto/soft_aes.h @@ -105,6 +105,23 @@ static inline __m128i soft_aesenc(const uint32_t* in, __m128i key) return _mm_xor_si128(out, key); } +static inline __m128i soft_aesenc(__m128i in, __m128i key) +{ + uint32_t x0, x1, x2, x3; + x0 = _mm_cvtsi128_si32(in); + x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0x55)); + x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xAA)); + x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xFF)); + + __m128i out = _mm_set_epi32( + (saes_table[0][x3 & 0xff] ^ saes_table[1][(x0 >> 8) & 0xff] ^ saes_table[2][(x1 >> 16) & 0xff] ^ saes_table[3][x2 >> 24]), + (saes_table[0][x2 & 0xff] ^ saes_table[1][(x3 >> 8) & 0xff] ^ saes_table[2][(x0 >> 16) & 0xff] ^ saes_table[3][x1 >> 24]), + (saes_table[0][x1 & 0xff] ^ saes_table[1][(x2 >> 8) & 0xff] ^ saes_table[2][(x3 >> 16) & 0xff] ^ saes_table[3][x0 >> 24]), + (saes_table[0][x0 & 0xff] ^ saes_table[1][(x1 >> 8) & 0xff] ^ saes_table[2][(x2 >> 16) & 0xff] ^ saes_table[3][x3 >> 24])); + + return _mm_xor_si128(out, key); +} + static inline uint32_t sub_word(uint32_t key) { return (saes_sbox[key >> 24 ] << 24) | diff --git a/src/donate.h b/src/donate.h index a77a3050..edb08ee8 100644 --- a/src/donate.h +++ b/src/donate.h @@ -43,8 +43,8 @@ * XMR: 48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD * BTC: 1P7ujsXeX7GxQwHNnJsRMgAdNkFZmNVqJT */ -constexpr const double kDefaultDonateLevel = 0.7; -constexpr const double kMinimumDonateLevel = 0.7; +constexpr const int kDefaultDonateLevel = 2; +constexpr const int kMinimumDonateLevel = 1; #endif /* __DONATE_H__ */ diff --git a/src/interfaces/IThread.h b/src/interfaces/IThread.h new file mode 100644 index 00000000..3a8708e6 --- /dev/null +++ b/src/interfaces/IThread.h @@ -0,0 +1,77 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ITHREAD_H +#define XMRIG_ITHREAD_H + + +#include + + +#include "common/xmrig.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class IThread +{ +public: + enum Type { + CPU, + OpenCL, + CUDA + }; + + enum Multiway { + SingleWay = 1, + DoubleWay, + TripleWay, + QuadWay, + PentaWay + }; + + virtual ~IThread() {} + + virtual Algo algorithm() const = 0; + virtual int priority() const = 0; + virtual int64_t affinity() const = 0; + virtual Multiway multiway() const = 0; + virtual rapidjson::Value toConfig(rapidjson::Document &doc) const = 0; + virtual size_t index() const = 0; + virtual Type type() const = 0; + +# ifndef XMRIG_NO_API + virtual rapidjson::Value toAPI(rapidjson::Document &doc) const = 0; +# endif + +# ifdef APP_DEBUG + virtual void print() const = 0; +# endif +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_ITHREAD_H diff --git a/src/interfaces/IWorker.h b/src/interfaces/IWorker.h index b9b6eb0a..90394c2c 100644 --- a/src/interfaces/IWorker.h +++ b/src/interfaces/IWorker.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,8 @@ class IWorker public: virtual ~IWorker() {} + virtual bool selfTest() = 0; + virtual size_t id() const = 0; virtual uint64_t hashCount() const = 0; virtual uint64_t timestamp() const = 0; virtual void start() = 0; diff --git a/src/net/JobResult.h b/src/net/JobResult.h index e3282584..05e34f87 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -29,17 +29,18 @@ #include -#include "Job.h" +#include "common/net/Job.h" class JobResult { public: inline JobResult() : poolId(0), diff(0), nonce(0) {} - inline JobResult(int poolId, const xmrig::Id &jobId, uint32_t nonce, const uint8_t *result, uint32_t diff) : + inline JobResult(int poolId, const xmrig::Id &jobId, uint32_t nonce, const uint8_t *result, uint32_t diff, const xmrig::Algorithm &algorithm) : poolId(poolId), diff(diff), nonce(nonce), + algorithm(algorithm), jobId(jobId) { memcpy(this->result, result, sizeof(this->result)); @@ -48,19 +49,11 @@ class JobResult inline JobResult(const Job &job) : poolId(0), diff(0), nonce(0) { - jobId = job.id(); - poolId = job.poolId(); - diff = job.diff(); - nonce = *job.nonce(); - } - - - inline JobResult &operator=(const Job &job) { - jobId = job.id(); - poolId = job.poolId(); - diff = job.diff(); - - return *this; + jobId = job.id(); + poolId = job.poolId(); + diff = job.diff(); + nonce = *job.nonce(); + algorithm = job.algorithm(); } @@ -74,6 +67,7 @@ class JobResult uint32_t diff; uint32_t nonce; uint8_t result[32]; + xmrig::Algorithm algorithm; xmrig::Id jobId; }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 7655fc03..828203a1 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -31,37 +31,37 @@ #include "api/Api.h" -#include "log/Log.h" -#include "net/Client.h" +#include "common/log/Log.h" +#include "common/net/Client.h" +#include "common/net/strategies/FailoverStrategy.h" +#include "common/net/strategies/SinglePoolStrategy.h" +#include "common/net/SubmitResult.h" +#include "core/Config.h" +#include "core/Controller.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" -#include "net/strategies/FailoverStrategy.h" -#include "net/strategies/SinglePoolStrategy.h" -#include "net/SubmitResult.h" -#include "net/Url.h" -#include "Options.h" #include "workers/Workers.h" -Network::Network(const Options *options) : - m_options(options), - m_donate(nullptr) +Network::Network(xmrig::Controller *controller) : + m_donate(nullptr), + m_controller(controller) { srand(time(0) ^ (uintptr_t) this); Workers::setListener(this); - const std::vector &pools = options->pools(); + const std::vector &pools = controller->config()->pools(); if (pools.size() > 1) { - m_strategy = new FailoverStrategy(pools, options->retryPause(), options->retries(), this); + m_strategy = new FailoverStrategy(pools, controller->config()->retryPause(), controller->config()->retries(), this); } else { - m_strategy = new SinglePoolStrategy(pools.front(), options->retryPause(), this); + m_strategy = new SinglePoolStrategy(pools.front(), controller->config()->retryPause(), controller->config()->retries(), this); } - if (m_options->donateLevel() > 0) { - m_donate = new DonateStrategy(options->donateLevel(), options->pools().front()->user(), options->algorithm(), this); + if (controller->config()->donateLevel() > 0) { + m_donate = new DonateStrategy(controller->config()->donateLevel(), controller->config()->pools().front().user(), controller->config()->algorithm().algo(), this); } m_timer.data = this; @@ -101,7 +101,15 @@ void Network::onActive(IStrategy *strategy, Client *client) m_state.setPool(client->host(), client->port(), client->ip()); - LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); + const char *tlsVersion = client->tlsVersion(); + LOG_INFO(isColors() ? WHITE_BOLD("use pool ") CYAN_BOLD("%s:%d ") GREEN_BOLD("%s") " \x1B[1;30m%s " + : "use pool %s:%d %s %s", + client->host(), client->port(), tlsVersion ? tlsVersion : "", client->ip()); + + const char *fingerprint = client->tlsFingerprint(); + if (fingerprint != nullptr) { + LOG_INFO("%sfingerprint (SHA-256): \"%s\"", isColors() ? "\x1B[1;30m" : "", fingerprint); + } } @@ -146,26 +154,29 @@ void Network::onResultAccepted(IStrategy *strategy, Client *client, const Submit m_state.add(result, error); if (error) { - LOG_INFO(m_options->colors() ? "\x1B[01;31mrejected\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" - : "rejected (%" PRId64 "/%" PRId64 ") diff %u \"%s\" (%" PRIu64 " ms)", + LOG_INFO(isColors() ? "\x1B[01;31mrejected\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" + : "rejected (%" PRId64 "/%" PRId64 ") diff %u \"%s\" (%" PRIu64 " ms)", m_state.accepted, m_state.rejected, result.diff, error, result.elapsed); } else { - LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" - : "accepted (%" PRId64 "/%" PRId64 ") diff %u (%" PRIu64 " ms)", + LOG_INFO(isColors() ? "\x1B[01;32maccepted\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" + : "accepted (%" PRId64 "/%" PRId64 ") diff %u (%" PRIu64 " ms)", m_state.accepted, m_state.rejected, result.diff, result.elapsed); } } +bool Network::isColors() const +{ + return m_controller->config()->isColors(); +} + + void Network::setJob(Client *client, const Job &job, bool donate) { - if (m_options->colors()) { - LOG_INFO("\x1B[01;35mnew job\x1B[0m from \x1B[01;37m%s:%d\x1B[0m diff \x1B[01;37m%d", client->host(), client->port(), job.diff()); - } - else { - LOG_INFO("new job from %s:%d diff %d", client->host(), client->port(), job.diff()); - } + LOG_INFO(isColors() ? MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%d") " algo " WHITE_BOLD("%s") + : "new job from %s:%d diff %d algo %s", + client->host(), client->port(), job.diff(), job.algorithm().shortName()); m_state.diff = job.diff(); Workers::setJob(job, donate); diff --git a/src/net/Network.h b/src/net/Network.h index fae5c563..51e95d6d 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -30,19 +30,23 @@ #include "api/NetworkState.h" +#include "common/interfaces/IStrategyListener.h" #include "interfaces/IJobResultListener.h" -#include "interfaces/IStrategyListener.h" class IStrategy; -class Options; class Url; +namespace xmrig { + class Controller; +} + + class Network : public IJobResultListener, public IStrategyListener { public: - Network(const Options *options); + Network(xmrig::Controller *controller); ~Network(); void connect(); @@ -58,16 +62,17 @@ class Network : public IJobResultListener, public IStrategyListener private: constexpr static int kTickInterval = 1 * 1000; + bool isColors() const; void setJob(Client *client, const Job &job, bool donate); void tick(); static void onTick(uv_timer_t *handle); - const Options *m_options; IStrategy *m_donate; IStrategy *m_strategy; NetworkState m_state; uv_timer_t m_timer; + xmrig::Controller *m_controller; }; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 83c8aa62..fbaa457e 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -22,23 +22,15 @@ */ -#include "interfaces/IStrategyListener.h" -#include "net/Client.h" -#include "net/Job.h" +#include "common/crypto/keccak.h" +#include "common/interfaces/IStrategyListener.h" +#include "common/net/Client.h" +#include "common/net/Job.h" +#include "common/net/strategies/FailoverStrategy.h" +#include "common/net/strategies/SinglePoolStrategy.h" +#include "common/Platform.h" +#include "common/xmrig.h" #include "net/strategies/DonateStrategy.h" -#include "net/strategies/FailoverStrategy.h" -#include "Platform.h" -#include "xmrig.h" - - -extern "C" -{ -#include "crypto/c_keccak.h" -} - - -const static char *kDonatePool1 = "indeedminers.eu"; -const static char *kDonatePool2 = "indeedminers.eu"; static inline float randomf(float min, float max) { @@ -46,7 +38,7 @@ static inline float randomf(float min, float max) { } -DonateStrategy::DonateStrategy(int level, const char *user, int algo, IStrategyListener *listener) : +DonateStrategy::DonateStrategy(int level, const char *user, xmrig::Algo algo, IStrategyListener *listener) : m_active(false), m_donateTime(level * 60 * 1000), m_idleTime((100 - level) * 60 * 1000), @@ -56,27 +48,26 @@ DonateStrategy::DonateStrategy(int level, const char *user, int algo, IStrategyL uint8_t hash[200]; char userId[65] = { 0 }; - keccak(reinterpret_cast(user), static_cast(strlen(user)), hash, sizeof(hash)); + xmrig::keccak(reinterpret_cast(user), strlen(user), hash); Job::toHex(hash, 32, userId); - if (algo == xmrig::CRYPTONIGHT) { - m_pools.push_back(new Url(kDonatePool1, 3333, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool1, 1111, userId, nullptr, false, true)); - } - else if (algo == xmrig::CRYPTONIGHT_HEAVY) { - m_pools.push_back(new Url(kDonatePool1, 5555, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool1, 5555, userId, nullptr, false, true)); +# ifndef XMRIG_NO_TLS + m_pools.push_back(Pool("indeedminers.eu", 3333, userId, nullptr, false, true)); +# endif + + m_pools.push_back(Pool("indeedminers.eu", 3333, userId, nullptr, false, true)); + + for (Pool &pool : m_pools) { + pool.adjust(xmrig::Algorithm(algo, xmrig::VARIANT_AUTO)); } - else if (algo == xmrig::CRYPTONIGHT_IPBC) { - m_pools.push_back(new Url(kDonatePool1, 7788, userId, nullptr, false, true)); + + if (m_pools.size() > 1) { + m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true); } else { - m_pools.push_back(new Url(kDonatePool1, 2222, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool1, 2222, userId, nullptr, false, true)); + m_strategy = new SinglePoolStrategy(m_pools.front(), 1, 2, this, true); } - m_strategy = new FailoverStrategy(m_pools, 1, 1, this, true); - m_timer.data = this; uv_timer_init(uv_default_loop(), &m_timer); diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 4ef29958..e75e41a4 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -21,17 +21,18 @@ * along with this program. If not, see . */ -#ifndef __DONATESTRATEGY_H__ -#define __DONATESTRATEGY_H__ +#ifndef XMRIG_DONATESTRATEGY_H +#define XMRIG_DONATESTRATEGY_H #include #include -#include "interfaces/IClientListener.h" -#include "interfaces/IStrategy.h" -#include "interfaces/IStrategyListener.h" +#include "common/net/Pool.h" +#include "common/interfaces/IClientListener.h" +#include "common/interfaces/IStrategy.h" +#include "common/interfaces/IStrategyListener.h" class Client; @@ -42,7 +43,7 @@ class Url; class DonateStrategy : public IStrategy, public IStrategyListener { public: - DonateStrategy(int level, const char *user, int algo, IStrategyListener *listener); + DonateStrategy(int level, const char *user, xmrig::Algo algo, IStrategyListener *listener); ~DonateStrategy(); public: @@ -71,8 +72,8 @@ class DonateStrategy : public IStrategy, public IStrategyListener const int m_idleTime; IStrategy *m_strategy; IStrategyListener *m_listener; - std::vector m_pools; + std::vector m_pools; uv_timer_t m_timer; }; -#endif /* __DONATESTRATEGY_H__ */ +#endif /* XMRIG_DONATESTRATEGY_H */ diff --git a/src/nvidia/CudaCLI.cpp b/src/nvidia/CudaCLI.cpp index 70062eff..8d2eed15 100644 --- a/src/nvidia/CudaCLI.cpp +++ b/src/nvidia/CudaCLI.cpp @@ -29,7 +29,7 @@ #include "nvidia/CudaCLI.h" #include "nvidia/cryptonight.h" -#include "workers/GpuThread.h" +#include "workers/CudaThread.h" CudaCLI::CudaCLI() : @@ -38,7 +38,7 @@ CudaCLI::CudaCLI() : } -bool CudaCLI::setup(std::vector &threads, xmrig::Algo algo) +bool CudaCLI::setup(std::vector &threads, xmrig::Algo algo) { if (isEmpty() || m_count == 0) { return false; @@ -50,9 +50,9 @@ bool CudaCLI::setup(std::vector &threads, xmrig::Algo algo) } } - for (int i = 0; i < m_devices.size(); i++) { + for (int i = 0; i < static_cast(m_devices.size()); i++) { nvid_ctx ctx; - ctx.device_id = m_devices[i]; + ctx.device_id = m_devices[static_cast(i)]; ctx.device_blocks = blocks(i); ctx.device_threads = this->threads(i); ctx.device_bfactor = bfactor(i); @@ -63,14 +63,14 @@ bool CudaCLI::setup(std::vector &threads, xmrig::Algo algo) continue; } - threads.push_back(new GpuThread(ctx, affinity(i))); + threads.push_back(new CudaThread(ctx, affinity(i), algo)); } return true; } -void CudaCLI::autoConf(std::vector &threads, xmrig::Algo algo) +void CudaCLI::autoConf(std::vector &threads, xmrig::Algo algo) { if (m_count == 0) { return; @@ -89,7 +89,7 @@ void CudaCLI::autoConf(std::vector &threads, xmrig::Algo algo) continue; } - threads.push_back(new GpuThread(ctx)); + threads.push_back(new CudaThread(ctx, -1, algo)); } } @@ -100,7 +100,7 @@ void CudaCLI::parseDevices(const char *arg) char *pch = strtok(value, ","); while (pch != nullptr) { - const int index = (int) strtoul(pch, nullptr, 10); + const int index = static_cast(strtoul(pch, nullptr, 10)); if (index < m_count) { m_devices.push_back(index); } @@ -133,7 +133,7 @@ void CudaCLI::parseLaunch(const char *arg) while (pch != nullptr && count < 2) { count++; - const int v = (int) strtoul(pch, nullptr, 10); + const int v = static_cast(strtoul(pch, nullptr, 10)); if (count == 1) { m_threads.push_back(v > 0 ? v : -1); } @@ -173,10 +173,10 @@ void CudaCLI::parse(std::vector &vector, const char *arg) const char *pch = strtok(value, ","); while (pch != nullptr) { - vector.push_back((int) strtoul(pch, nullptr, 10)); + vector.push_back(static_cast(strtoul(pch, nullptr, 10))); pch = strtok(nullptr, ","); } free(value); -} \ No newline at end of file +} diff --git a/src/nvidia/CudaCLI.h b/src/nvidia/CudaCLI.h index 929d4d08..d032f0f5 100644 --- a/src/nvidia/CudaCLI.h +++ b/src/nvidia/CudaCLI.h @@ -21,17 +21,20 @@ * along with this program. If not, see . */ -#ifndef __CUDACLI_H__ -#define __CUDACLI_H__ +#ifndef XMRIG_CUDACLI_H +#define XMRIG_CUDACLI_H #include -#include "xmrig.h" +#include "common/xmrig.h" -class GpuThread; +namespace xmrig { + class IThread; +} + class CudaCLI @@ -39,8 +42,8 @@ class CudaCLI public: CudaCLI(); - bool setup(std::vector &threads, xmrig::Algo algo); - void autoConf(std::vector &threads, xmrig::Algo algo); + bool setup(std::vector &threads, xmrig::Algo algo); + void autoConf(std::vector &threads, xmrig::Algo algo); void parseDevices(const char *arg); void parseLaunch(const char *arg); @@ -50,13 +53,8 @@ class CudaCLI inline void parseBFactor(const char *arg) { parse(m_bfactors, arg); } inline void parseBSleep(const char *arg) { parse(m_bsleeps, arg); } -private: - inline int affinity(int index) const { return get(m_affinity, index, -1); } - inline int blocks(int index) const { return get(m_blocks, index, -1); } - inline int threads(int index) const { return get(m_threads, index, -1); } - inline bool isEmpty() const { return m_devices.empty() && m_threads.empty(); } - - inline int bfactor(int index = 0) const { + inline int bfactor(int index = 0) const + { # ifdef _WIN32 return get(m_bfactors, index, 6); # else @@ -64,7 +62,8 @@ class CudaCLI # endif } - inline int bsleep(int index = 0) const { + inline int bsleep(int index = 0) const + { # ifdef _WIN32 return get(m_bsleeps, index, 25); # else @@ -72,6 +71,12 @@ class CudaCLI # endif } +private: + inline int affinity(int index) const { return get(m_affinity, index, -1); } + inline int blocks(int index) const { return get(m_blocks, index, -1); } + inline int threads(int index) const { return get(m_threads, index, -1); } + inline bool isEmpty() const { return m_devices.empty() && m_threads.empty(); } + int get(const std::vector &vector, int index, int defaultValue) const; void parse(std::vector &vector, const char *arg) const; @@ -85,4 +90,4 @@ class CudaCLI }; -#endif /* __CUDACLI_H__ */ +#endif /* XMRIG_CUDACLI_H */ diff --git a/src/nvidia/NvmlApi.cpp b/src/nvidia/NvmlApi.cpp index 261d0ec8..8aa99626 100644 --- a/src/nvidia/NvmlApi.cpp +++ b/src/nvidia/NvmlApi.cpp @@ -4,8 +4,7 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +26,7 @@ #include "nvidia/NvmlApi.h" -#include "workers/GpuThread.h" +#include "workers/CudaThread.h" static uv_lib_t nvmlLib; @@ -136,18 +135,18 @@ const char *NvmlApi::version() } -void NvmlApi::bind(const std::vector &threads) +void NvmlApi::bind(const std::vector &threads) { if (!isAvailable() || !pNvmlDeviceGetCount || !pNvmlDeviceGetHandleByIndex || !pNvmlDeviceGetPciInfo) { return; } - unsigned int count = 0; + uint32_t count = 0; if (pNvmlDeviceGetCount(&count) != NVML_SUCCESS) { return; } - for (unsigned int i = 0; i < count; i++) { + for (uint32_t i = 0; i < count; i++) { nvmlDevice_t device; if (pNvmlDeviceGetHandleByIndex(i, &device) != NVML_SUCCESS) { continue; @@ -158,7 +157,8 @@ void NvmlApi::bind(const std::vector &threads) continue; } - for (GpuThread *thread : threads) { + for (xmrig::IThread *t : threads) { + auto thread = static_cast(t); if (thread->pciBusID() == pci.bus && thread->pciDeviceID() == pci.device && thread->pciDomainID() == pci.domain) { thread->setNvmlId(i); break; diff --git a/src/nvidia/NvmlApi.h b/src/nvidia/NvmlApi.h index 20ce61df..25b6c3c0 100644 --- a/src/nvidia/NvmlApi.h +++ b/src/nvidia/NvmlApi.h @@ -4,8 +4,7 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,8 +20,8 @@ * along with this program. If not, see . */ -#ifndef __NVML_H__ -#define __NVML_H__ +#ifndef XMRIG_NVML_H +#define XMRIG_NVML_H #include @@ -31,7 +30,9 @@ #include "nvidia/Health.h" -class GpuThread; +namespace xmrig { + class IThread; +} class NvmlApi @@ -42,7 +43,7 @@ class NvmlApi static bool health(int id, Health &health); static const char *version(); - static void bind(const std::vector &threads); + static void bind(const std::vector &threads); static inline bool isAvailable() { return m_available; } @@ -51,4 +52,4 @@ class NvmlApi }; -#endif /* __NVML_H__ */ +#endif /* XMRIG_NVML_H */ diff --git a/src/nvidia/NvmlApi_stub.cpp b/src/nvidia/NvmlApi_stub.cpp index 6b294bc4..7a5ace26 100644 --- a/src/nvidia/NvmlApi_stub.cpp +++ b/src/nvidia/NvmlApi_stub.cpp @@ -4,8 +4,7 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2016-2018 XMRig , * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +38,7 @@ void NvmlApi::release() } -bool NvmlApi::health(int id, Health &health) +bool NvmlApi::health(int, Health &) { return false; } @@ -51,6 +50,6 @@ const char *NvmlApi::version() } -void NvmlApi::bind(const std::vector &threads) +void NvmlApi::bind(const std::vector &) { } diff --git a/src/nvidia/cryptonight.h b/src/nvidia/cryptonight.h index b6aaf1f6..749fd9a8 100644 --- a/src/nvidia/cryptonight.h +++ b/src/nvidia/cryptonight.h @@ -28,7 +28,7 @@ #include -#include "xmrig.h" +#include "../common/xmrig.h" typedef struct { @@ -42,10 +42,10 @@ typedef struct { int device_bsleep; int device_clockRate; int device_memoryClockRate; - int device_pciBusID; - int device_pciDeviceID; - int device_pciDomainID; - int syncMode; + uint32_t device_pciBusID; + uint32_t device_pciDeviceID; + uint32_t device_pciDomainID; + uint32_t syncMode; uint32_t *d_input; uint32_t inputlen; @@ -67,7 +67,8 @@ int cuda_get_devicecount(); int cuda_get_runtime_version(); int cuda_get_deviceinfo(nvid_ctx *ctx, xmrig::Algo algo); int cryptonight_gpu_init(nvid_ctx *ctx, xmrig::Algo algo); -void cryptonight_extra_cpu_set_data(nvid_ctx *ctx, const void *data, uint32_t len); -void cryptonight_extra_cpu_prepare(nvid_ctx* ctx, uint32_t startNonce, xmrig::Algo algo); -void cryptonight_gpu_hash(nvid_ctx *ctx, xmrig::Algo algo, int variant, uint32_t startNonce); -void cryptonight_extra_cpu_final(nvid_ctx* ctx, uint32_t startNonce, uint64_t target, uint32_t* rescount, uint32_t *resnonce, xmrig::Algo algo); +void cryptonight_extra_cpu_set_data(nvid_ctx *ctx, const void *data, size_t len); +void cryptonight_extra_cpu_prepare(nvid_ctx *ctx, uint32_t startNonce, xmrig::Algo algo, xmrig::Variant variant); +void cryptonight_gpu_hash(nvid_ctx *ctx, xmrig::Algo algo, xmrig::Variant variant, uint32_t startNonce); +void cryptonight_extra_cpu_final(nvid_ctx *ctx, uint32_t startNonce, uint64_t target, uint32_t *rescount, uint32_t *resnonce, xmrig::Algo algo); +void cryptonight_extra_cpu_free(nvid_ctx *ctx, xmrig::Algo algo); diff --git a/src/nvidia/cuda_core.cu b/src/nvidia/cuda_core.cu index 30bbc511..b390347a 100644 --- a/src/nvidia/cuda_core.cu +++ b/src/nvidia/cuda_core.cu @@ -30,13 +30,11 @@ #include #ifdef _WIN32 -#include -extern "C" void compat_usleep(uint64_t waitTime) +#include +static void compat_usleep(int waitTime) { - if (waitTime > 0) - { - if (waitTime > 100) - { + if (waitTime > 0) { + if (waitTime > 100) { // use a waitable timer for larger intervals > 0.1ms HANDLE timer; @@ -44,33 +42,31 @@ extern "C" void compat_usleep(uint64_t waitTime) ft.QuadPart = -10ll * int64_t(waitTime); // Convert to 100 nanosecond interval, negative value indicates relative time - timer = CreateWaitableTimer(NULL, TRUE, NULL); - SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); + timer = CreateWaitableTimer(nullptr, TRUE, nullptr); + SetWaitableTimer(timer, &ft, 0, nullptr, nullptr, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); - } - else - { - // use a polling loop for short intervals <= 100ms + } else { + // use a polling loop for short intervals <= 0.1ms LARGE_INTEGER perfCnt, start, now; - __int64 elapsed; + int64_t elapsed; QueryPerformanceFrequency(&perfCnt); QueryPerformanceCounter(&start); do { - SwitchToThread(); - QueryPerformanceCounter((LARGE_INTEGER*) &now); - elapsed = (__int64)((now.QuadPart - start.QuadPart) / (float)perfCnt.QuadPart * 1000 * 1000); - } while ( elapsed < waitTime ); + SwitchToThread(); + QueryPerformanceCounter(&now); + elapsed = static_cast(((now.QuadPart - start.QuadPart) / static_cast(perfCnt.QuadPart) * 1000 * 1000)); + } while (elapsed < static_cast(waitTime)); } } } #else #include -extern "C" void compat_usleep(uint64_t waitTime) +static inline void compat_usleep(int waitTime) { - usleep(waitTime); + usleep(static_cast(waitTime)); } #endif @@ -78,7 +74,8 @@ extern "C" void compat_usleep(uint64_t waitTime) #include "cuda_extra.h" #include "cuda_aes.hpp" #include "cuda_device.hpp" -#include "xmrig.h" +#include "cuda_fast_int_math_v2.hpp" +#include "common/xmrig.h" #include "crypto/CryptoNight_constants.h" #if defined(__x86_64__) || defined(_M_AMD64) || defined(__LP64__) @@ -96,12 +93,6 @@ typedef uint64_t IndexType; typedef int IndexType; #endif -__device__ __forceinline__ uint64_t cuda_mul128( uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi ) -{ - *product_hi = __umul64hi( multiplier, multiplicand ); - return (multiplier * multiplicand ); -} - template< typename T > __device__ __forceinline__ T loadGlobal64( T * const addr ) { @@ -140,7 +131,7 @@ template< typename T > __device__ __forceinline__ void storeGlobal64( T* addr, T const & val ) { # if (__CUDA_ARCH__ < 700) - asm volatile("st.global.cg.u64 [%0], %1;" : : _ASM_PTR_(addr), _ASM_PTR_(val)); + asm volatile("st.global.cg.u64 [%0], %1;" : : _ASM_PTR_(addr), "l"(val)); # else *addr = val; # endif @@ -168,19 +159,17 @@ __global__ void cryptonight_core_gpu_phase1( int threads, int bfactor, int parti MEMCPY8( key, ctx_key1 + thread * 40, 20 ); - if( partidx == 0 ) - { + if (partidx == 0) { // first round MEMCPY8( text, ctx_state2 + thread * 50 + sub + 16, 2 ); } - else - { + else { // load previous text data MEMCPY8( text, &long_state[( (uint64_t) thread * MEM) + sub + start - 32], 2 ); } + __syncthreads( ); - for ( int i = start; i < end; i += 32 ) - { + for (int i = start; i < end; i += 32) { cn_aes_pseudo_round_mut( sharedMemory, text, key ); MEMCPY8(&long_state[((uint64_t) thread * MEM) + (sub + i)], text, 2); } @@ -214,20 +203,257 @@ __forceinline__ __device__ uint32_t shuffle(volatile uint32_t* ptr,const uint32_ # else unusedVar( ptr ); unusedVar( sub ); -# if(__CUDACC_VER_MAJOR__ >= 9) - return __shfl_sync(0xFFFFFFFF, val, src, group_n ); +# if (__CUDACC_VER_MAJOR__ >= 9) + return __shfl_sync(__activemask(), val, src, group_n); # else return __shfl( val, src, group_n ); # endif # endif } -template + +template +__forceinline__ __device__ uint64_t shuffle64(volatile uint32_t* ptr,const uint32_t sub,const int val,const uint32_t src, const uint32_t src2) +{ + uint64_t tmp; + ((uint32_t*)&tmp)[0] = shuffle(ptr, sub, val, src); + ((uint32_t*)&tmp)[1] = shuffle(ptr, sub, val, src2); + return tmp; +} + +struct u64 : public uint2 +{ + + __forceinline__ __device__ u64(){} + + __forceinline__ __device__ u64( const uint32_t x0, const uint32_t x1) + { + uint2::x = x0; + uint2::y = x1; + } + + __forceinline__ __device__ operator uint64_t() const + { + return *((uint64_t*)this); + } + + __forceinline__ __device__ u64( const uint64_t x0) + { + ((uint64_t*)&this->x)[0] = x0; + } + + __forceinline__ __device__ u64 operator^=(const u64& other) + { + uint2::x ^= other.x; + uint2::y ^= other.y; + + return *this; + } + + __forceinline__ __device__ u64 operator+(const u64& other) const + { + u64 tmp; + ((uint64_t*)&tmp.x)[0] = ((uint64_t*)&(this->x))[0] + ((uint64_t*)&(other.x))[0]; + + return tmp; + } + + __forceinline__ __device__ u64 operator+=(const uint64_t& other) + { + return ((uint64_t*)&this->x)[0] += other; + } + + __forceinline__ __device__ void print(int i) const + { + if(i<2) + printf("gpu: %lu\n", ((uint64_t*)&this->x)[0]); + } +}; + +/** cryptonight with two threads per hash + */ +template +#ifdef XMR_STAK_THREADS +__launch_bounds__( XMR_STAK_THREADS * 2 ) +#endif +__global__ void cryptonight_core_gpu_phase2_double( + int threads, + int bfactor, + int partidx, + uint32_t *d_long_state, + uint32_t *d_ctx_a, + uint32_t *d_ctx_b, + uint32_t * d_ctx_state, + uint32_t startNonce, + uint32_t * __restrict__ d_input + ) +{ + __shared__ uint32_t sharedMemory[1024]; + + cn_aes_gpu_init( sharedMemory ); + +# if( __CUDA_ARCH__ < 300 ) + extern __shared__ uint64_t externShared[]; + // 8 x 64bit values + volatile uint64_t* myChunks = (volatile uint64_t*)(externShared + (threadIdx.x >> 1) * 8); + volatile uint32_t* sPtr = (volatile uint32_t*)(externShared + (blockDim.x >> 1) * 8) + (threadIdx.x & 0xFFFFFFFE); +# else + extern __shared__ uint64_t chunkMem[]; + volatile uint32_t* sPtr = NULL; + // 8 x 64bit values + volatile uint64_t* myChunks = (volatile uint64_t*)(chunkMem + (threadIdx.x >> 1) * 8); +# endif + + __syncthreads( ); + + const uint64_t tid = (blockDim.x * blockIdx.x + threadIdx.x); + const uint32_t thread = tid >> 1; + const uint32_t sub = tid & 1; + + if (thread >= threads) { + return; + } + + uint8_t *l0 = (uint8_t*)&d_long_state[(IndexType) thread * MEM]; + uint64_t ax0 = ((uint64_t*)(d_ctx_a + thread * 4))[sub]; + uint32_t idx0 = shuffle<2>(sPtr, sub, static_cast(ax0), 0); + uint64_t bx0 = ((uint64_t*)(d_ctx_b + thread * 12))[sub]; + uint64_t bx1 = ((uint64_t*)(d_ctx_b + thread * 12 + 4))[sub]; + uint64_t division_result = ((uint64_t*)(d_ctx_b + thread * 12 + 4 * 2))[0]; + uint32_t sqrt_result = (d_ctx_b + thread * 12 + 4 * 2 + 2)[0]; + + const int batchsize = (ITERATIONS * 2) >> ( 1 + bfactor ); + const int start = partidx * batchsize; + const int end = start + batchsize; + + uint64_t* ptr0; + for (int i = start; i < end; ++i) { + ptr0 = (uint64_t *)&l0[idx0 & 0x1FFFC0]; + + ((ulonglong4*)myChunks)[sub] = ((ulonglong4*)ptr0)[sub]; + + uint32_t idx1 = (idx0 & 0x30) >> 3; + const u64 cx = myChunks[ idx1 + sub ]; + const u64 cx2 = myChunks[ idx1 + ((sub + 1) & 1) ]; + + u64 cx_aes = ax0 ^ u64( + t_fn0( cx.x & 0xff ) ^ t_fn1( (cx.y >> 8) & 0xff ) ^ t_fn2( (cx2.x >> 16) & 0xff ) ^ t_fn3( (cx2.y >> 24 ) ), + t_fn0( cx.y & 0xff ) ^ t_fn1( (cx2.x >> 8) & 0xff ) ^ t_fn2( (cx2.y >> 16) & 0xff ) ^ t_fn3( (cx.x >> 24 ) ) + ); + + { + const uint64_t chunk1 = myChunks[idx1 ^ 2 + sub]; + const uint64_t chunk2 = myChunks[idx1 ^ 4 + sub]; + const uint64_t chunk3 = myChunks[idx1 ^ 6 + sub]; + +# if (__CUDACC_VER_MAJOR__ >= 9) + __syncwarp(); +# else + __syncthreads(); +# endif + + myChunks[idx1 ^ 2 + sub] = chunk3 + bx1; + myChunks[idx1 ^ 4 + sub] = chunk1 + bx0; + myChunks[idx1 ^ 6 + sub] = chunk2 + ax0; + } + + myChunks[idx1 + sub] = cx_aes ^ bx0; + + ((ulonglong4*)ptr0)[sub] = ((ulonglong4*)myChunks)[sub]; + + idx0 = shuffle<2>(sPtr, sub, cx_aes.x, 0); + idx1 = (idx0 & 0x30) >> 3; + ptr0 = (uint64_t *)&l0[idx0 & MASK & 0x1FFFC0]; + + ((ulonglong4*)myChunks)[sub] = ((ulonglong4*)ptr0)[sub]; + + uint64_t cx_mul; + ((uint32_t*)&cx_mul)[0] = shuffle<2>(sPtr, sub, cx_aes.x , 0); + ((uint32_t*)&cx_mul)[1] = shuffle<2>(sPtr, sub, cx_aes.y , 0); + + if (sub == 1) { + // Use division and square root results from the _previous_ iteration to hide the latency + ((uint32_t*)&division_result)[1] ^= sqrt_result; + ((uint64_t*)myChunks)[idx1] ^= division_result; + + const uint32_t dd = (static_cast(cx_mul) + (sqrt_result << 1)) | 0x80000001UL; + division_result = fast_div_v2(cx_aes, dd); + + // Use division_result as an input for the square root to prevent parallel implementation in hardware + sqrt_result = fast_sqrt_v2(cx_mul + division_result); + } + +# if (__CUDACC_VER_MAJOR__ >= 9) + __syncwarp(); +# else + __syncthreads( ); +# endif + + uint64_t c = ((uint64_t*)myChunks)[idx1 + sub]; + + { + uint64_t cl = ((uint64_t*)myChunks)[idx1]; + // sub 0 -> hi, sub 1 -> lo + uint64_t res = sub == 0 ? __umul64hi( cx_mul, cl ) : cx_mul * cl; + + const uint64_t chunk1 = myChunks[ idx1 ^ 2 + sub ] ^ res; + uint64_t chunk2 = myChunks[ idx1 ^ 4 + sub ]; + res ^= ((uint64_t*)&chunk2)[0]; + const uint64_t chunk3 = myChunks[ idx1 ^ 6 + sub ]; + +# if (__CUDACC_VER_MAJOR__ >= 9) + __syncwarp(); +# else + __syncthreads( ); +# endif + + myChunks[idx1 ^ 2 + sub] = chunk3 + bx1; + myChunks[idx1 ^ 4 + sub] = chunk1 + bx0; + myChunks[idx1 ^ 6 + sub] = chunk2 + ax0; + + ax0 += res; + } + + bx1 = bx0; + bx0 = cx_aes; + + myChunks[idx1 + sub] = ax0; + + ((ulonglong4*)ptr0)[sub] = ((ulonglong4*)myChunks)[sub]; + + ax0 ^= c; + idx0 = shuffle<2>(sPtr, sub, static_cast(ax0), 0); + } + + if (bfactor > 0) { + ((uint64_t*)(d_ctx_a + thread * 4))[sub] = ax0; + ((uint64_t*)(d_ctx_b + thread * 12))[sub] = bx0; + ((uint64_t*)(d_ctx_b + thread * 12 + 4))[sub] = bx1; + + if (sub == 1) { + // must be valid only for `sub == 1` + ((uint64_t*)(d_ctx_b + thread * 12 + 4 * 2))[0] = division_result; + (d_ctx_b + thread * 12 + 4 * 2 + 2)[0] = sqrt_result; + } + } +} + + +template #ifdef XMR_STAK_THREADS __launch_bounds__( XMR_STAK_THREADS * 4 ) #endif -__global__ void cryptonight_core_gpu_phase2( int threads, int bfactor, int partidx, uint32_t * d_long_state, uint32_t * d_ctx_a, uint32_t * d_ctx_b, uint32_t * d_ctx_state, - uint32_t startNonce, uint32_t * __restrict__ d_input ) +__global__ void cryptonight_core_gpu_phase2_quad( + int threads, + int bfactor, + int partidx, + uint32_t *d_long_state, + uint32_t *d_ctx_a, + uint32_t *d_ctx_b, + uint32_t *d_ctx_state, + uint32_t startNonce, + uint32_t *__restrict__ d_input + ) { __shared__ uint32_t sharedMemory[1024]; @@ -246,12 +472,13 @@ __global__ void cryptonight_core_gpu_phase2( int threads, int bfactor, int parti #else volatile uint32_t* sPtr = NULL; #endif - if ( thread >= threads ) + if (thread >= threads) { return; + } int i, k; uint32_t j; - const int batchsize = (ITERATIONS * 2) >> ( 2 + bfactor ); + const int batchsize = (ITERATIONS * 2) >> (2 + bfactor); const int start = partidx * batchsize; const int end = start + batchsize; uint32_t * long_state = &d_long_state[(IndexType) thread * MEM]; @@ -259,8 +486,7 @@ __global__ void cryptonight_core_gpu_phase2( int threads, int bfactor, int parti uint32_t t1[2], t2[2], res; uint32_t tweak1_2[2]; - if (VARIANT > 0) - { + if (IS_V1) { uint32_t * state = d_ctx_state + thread * 50; tweak1_2[0] = (d_input[8] >> 24) | (d_input[9] << 8); tweak1_2[0] ^= state[48]; @@ -270,48 +496,71 @@ __global__ void cryptonight_core_gpu_phase2( int threads, int bfactor, int parti a = (d_ctx_a + thread * 4)[sub]; idx0 = shuffle<4>(sPtr,sub, a, 0); - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - { - if(partidx != 0) - { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (partidx != 0) { // state is stored after all ctx_b states idx0 = *(d_ctx_b + threads * 4 + thread); } } + d[1] = (d_ctx_b + thread * 4)[sub]; #pragma unroll 2 - for ( i = start; i < end; ++i ) - { + for (i = start; i < end; ++i) { #pragma unroll 2 - for ( int x = 0; x < 2; ++x ) - { - j = ( ( idx0 & MASK ) >> 2 ) + sub; - - const uint32_t x_0 = loadGlobal32( long_state + j ); - const uint32_t x_1 = shuffle<4>(sPtr,sub, x_0, sub + 1); - const uint32_t x_2 = shuffle<4>(sPtr,sub, x_0, sub + 2); - const uint32_t x_3 = shuffle<4>(sPtr,sub, x_0, sub + 3); - d[x] = a ^ - t_fn0( x_0 & 0xff ) ^ - t_fn1( (x_1 >> 8) & 0xff ) ^ - t_fn2( (x_2 >> 16) & 0xff ) ^ - t_fn3( ( x_3 >> 24 ) ); - + for (int x = 0; x < 2; ++x) { + j = ((idx0 & MASK) >> 2) + sub; + + if (VARIANT == xmrig::VARIANT_TUBE) { + uint32_t k[4]; + k[0] = ~loadGlobal32(long_state + j); + k[1] = shuffle<4>(sPtr,sub, k[0], sub + 1); + k[2] = shuffle<4>(sPtr,sub, k[0], sub + 2); + k[3] = shuffle<4>(sPtr,sub, k[0], sub + 3); + + #pragma unroll 4 + for (int i = 0; i < 4; ++i) { + // only calculate the key if all data are up to date + if (i == sub) { + d[x] = a ^ + t_fn0(k[0] & 0xff) ^ + t_fn1((k[1] >> 8) & 0xff) ^ + t_fn2((k[2] >> 16) & 0xff) ^ + t_fn3((k[3] >> 24)); + } + // the last shuffle is not needed + if (i != 3) { + /* avoid negative number for modulo + * load valid key (k) depending on the round + */ + k[(4 - sub + i) % 4] = shuffle<4>(sPtr,sub, k[0] ^ d[x], i); + } + } + } else { + const uint32_t x_0 = loadGlobal32(long_state + j); + const uint32_t x_1 = shuffle<4>(sPtr,sub, x_0, sub + 1); + const uint32_t x_2 = shuffle<4>(sPtr,sub, x_0, sub + 2); + const uint32_t x_3 = shuffle<4>(sPtr,sub, x_0, sub + 3); + d[x] = a ^ + t_fn0(x_0 & 0xff) ^ + t_fn1((x_1 >> 8) & 0xff) ^ + t_fn2((x_2 >> 16) & 0xff) ^ + t_fn3((x_3 >> 24)); + } //XOR_BLOCKS_DST(c, b, &long_state[j]); t1[0] = shuffle<4>(sPtr,sub, d[x], 0); const uint32_t z = d[0] ^ d[1]; - if(VARIANT > 0) - { + if (IS_V1) { const uint32_t table = 0x75310U; - const uint32_t index = ((z >> 26) & 12) | ((z >> 23) & 2); + const uint32_t index = ((z >> (VARIANT == xmrig::VARIANT_XTL ? 27 : 26)) & 12) | ((z >> 23) & 2); const uint32_t fork_7 = z ^ ((table >> index) & 0x30U) << 24; - storeGlobal32( long_state + j, sub == 2 ? fork_7 : z ); + storeGlobal32(long_state + j, sub == 2 ? fork_7 : z); + } + else { + storeGlobal32(long_state + j, z); } - else - storeGlobal32( long_state + j, z ); //MUL_SUM_XOR_DST(c, a, &long_state[((uint32_t *)c)[0] & MASK]); j = ( ( *t1 & MASK ) >> 2 ) + sub; @@ -324,53 +573,57 @@ __global__ void cryptonight_core_gpu_phase2( int threads, int bfactor, int parti t1[1] = shuffle<4>(sPtr,sub, d[x], 1); #pragma unroll - for ( k = 0; k < 2; k++ ) + for (k = 0; k < 2; k++) { t2[k] = shuffle<4>(sPtr,sub, a, k + sub2); + } *( (uint64_t *) t2 ) += sub2 ? ( *( (uint64_t *) t1 ) * *( (uint64_t*) zz ) ) : __umul64hi( *( (uint64_t *) t1 ), *( (uint64_t*) zz ) ); res = *( (uint64_t *) t2 ) >> ( sub & 1 ? 32 : 0 ); - - if(VARIANT > 0) - { + if (IS_V1) { const uint32_t tweaked_res = tweak1_2[sub & 1] ^ res; - const uint32_t long_state_update = sub2 ? tweaked_res : res; - storeGlobal32( long_state + j, long_state_update ); - } - else - storeGlobal32( long_state + j, res ); + uint32_t long_state_update = sub2 ? tweaked_res : res; + + if (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO) { + uint32_t value = shuffle<4>(sPtr,sub, long_state_update, sub & 1) ^ long_state_update; + long_state_update = sub >= 2 ? value : long_state_update; + } - if (ALGO == xmrig::CRYPTONIGHT_IPBC && sub == 2) { - uint64_t* dst = ((uint64_t*)(long_state + j)); - uint64_t cur = loadGlobal64(dst); - uint64_t prev = loadGlobal64(dst - 1); - storeGlobal64(dst, cur ^ prev); - } + storeGlobal32(long_state + j, long_state_update); + } + else { + storeGlobal32(long_state + j, res); + } a = ( sub & 1 ? yy[1] : yy[0] ) ^ res; idx0 = shuffle<4>(sPtr,sub, a, 0); - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { int64_t n = loadGlobal64( ( (uint64_t *) long_state ) + (( idx0 & MASK ) >> 3)); int32_t d = loadGlobal32( (uint32_t*)(( (uint64_t *) long_state ) + (( idx0 & MASK) >> 3) + 1u )); int64_t q = n / (d | 0x5); - if(sub&1) + if (sub & 1) { storeGlobal64( ( (uint64_t *) long_state ) + (( idx0 & MASK ) >> 3), n ^ q ); + } + + if (VARIANT == xmrig::VARIANT_XHV) { + d = ~d; + } idx0 = d ^ q; } } } - if ( bfactor > 0 ) - { + if (bfactor > 0) { (d_ctx_a + thread * 4)[sub] = a; (d_ctx_b + thread * 4)[sub] = d[1]; - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - if(sub&1) + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (sub&1) { *(d_ctx_b + threads * 4 + thread) = idx0; + } + } } } @@ -406,32 +659,38 @@ __global__ void cryptonight_core_gpu_phase3( int threads, int bfactor, int parti volatile uint32_t* sPtr = NULL; # endif - for ( int i = start; i < end; i += 32 ) - { + for (int i = start; i < end; i += 32) { #pragma unroll - for ( int j = 0; j < 4; ++j ) + for (int j = 0; j < 4; ++j) { text[j] ^= long_state[((IndexType) thread * MEM) + ( sub + i + j)]; + } cn_aes_pseudo_round_mut( sharedMemory, text, key ); - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { #pragma unroll - for ( int j = 0; j < 4; ++j ) - text[j] ^= shuffle<8>(sPtr, subv, text[j], (subv+1)&7); + for (int j = 0; j < 4; ++j) { + text[j] ^= shuffle<8>(sPtr, subv, text[j], (subv+1) & 7); + } } } MEMCPY8( d_ctx_state + thread * 50 + sub + 16, text, 2 ); } -template +template void cryptonight_core_gpu_hash(nvid_ctx* ctx, uint32_t nonce) { - dim3 grid( ctx->device_blocks ); - dim3 block( ctx->device_threads ); - dim3 block4( ctx->device_threads << 2 ); - dim3 block8( ctx->device_threads << 3 ); + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory() / 4; + constexpr bool IS_V1 = xmrig::cn_base_variant() == xmrig::VARIANT_1; + + dim3 grid(ctx->device_blocks); + dim3 block(ctx->device_threads); + dim3 block2(ctx->device_threads << 2); + dim3 block4(ctx->device_threads << 2); + dim3 block8(ctx->device_threads << 3); int partcount = 1 << ctx->device_bfactor; @@ -441,55 +700,71 @@ void cryptonight_core_gpu_hash(nvid_ctx* ctx, uint32_t nonce) * kernel splitting if the user defined a `bfactor >= 5` */ int bfactorOneThree = ctx->device_bfactor - 4; - if( bfactorOneThree < 0 ) + if (bfactorOneThree < 0) { bfactorOneThree = 0; + } - int partcountOneThree = 1 << bfactorOneThree; - - for ( int i = 0; i < partcountOneThree; i++ ) - { + const int partcountOneThree = 1 << bfactorOneThree; + for (int i = 0; i < partcountOneThree; i++) { CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_core_gpu_phase1<<< grid, block8 >>>( ctx->device_blocks*ctx->device_threads, bfactorOneThree, i, ctx->d_long_state, (ALGO == xmrig::CRYPTONIGHT_HEAVY ? ctx->d_ctx_state2 : ctx->d_ctx_state), - ctx->d_ctx_key1 )); + ctx->d_ctx_key1)); - if ( partcount > 1 && ctx->device_bsleep > 0) compat_usleep( ctx->device_bsleep ); + if (partcount > 1 && ctx->device_bsleep > 0) { + compat_usleep(ctx->device_bsleep); + } } - if ( partcount > 1 && ctx->device_bsleep > 0) compat_usleep( ctx->device_bsleep ); - for ( int i = 0; i < partcount; i++ ) - { - CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_core_gpu_phase2<<< - grid, - block4, - block4.x * sizeof(uint32_t) * static_cast< int >( ctx->device_arch[0] < 3 ) - >>>( - ctx->device_blocks*ctx->device_threads, - ctx->device_bfactor, - i, - ctx->d_long_state, - ctx->d_ctx_a, - ctx->d_ctx_b, - ctx->d_ctx_state, - nonce, - ctx->d_input - ) - ); - - if ( partcount > 1 && ctx->device_bsleep > 0) compat_usleep( ctx->device_bsleep ); + if (partcount > 1 && ctx->device_bsleep > 0) { + compat_usleep(ctx->device_bsleep); } - int roundsPhase3 = partcountOneThree; + for (int i = 0; i < partcount; i++) { + if (VARIANT == xmrig::VARIANT_2) { + CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_core_gpu_phase2_double<<< + grid, + block2, + sizeof(uint64_t) * block2.x * 8 + block2.x * sizeof(uint32_t) * static_cast(ctx->device_arch[0] < 3) + >>>( + ctx->device_blocks * ctx->device_threads, + ctx->device_bfactor, + i, + ctx->d_long_state, + ctx->d_ctx_a, + ctx->d_ctx_b, + ctx->d_ctx_state, + nonce, + ctx->d_input + ) + ); + } else { + CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_core_gpu_phase2_quad<<< + grid, + block4, + block4.x * sizeof(uint32_t) * static_cast(ctx->device_arch[0] < 3) + >>>( + ctx->device_blocks * ctx->device_threads, + ctx->device_bfactor, + i, + ctx->d_long_state, + ctx->d_ctx_a, + ctx->d_ctx_b, + ctx->d_ctx_state, + nonce, + ctx->d_input + ) + ); + } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) - { - // cryptonight_heavy used two full rounds over the scratchpad memory - roundsPhase3 *= 2; + if (partcount > 1 && ctx->device_bsleep > 0) { + compat_usleep(ctx->device_bsleep); + } } - for ( int i = 0; i < roundsPhase3; i++ ) - { + const int roundsPhase3 = ALGO == xmrig::CRYPTONIGHT_HEAVY ? partcountOneThree * 2 : partcountOneThree; + for (int i = 0; i < roundsPhase3; i++) { CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_core_gpu_phase3<<< grid, block8, @@ -497,40 +772,79 @@ void cryptonight_core_gpu_hash(nvid_ctx* ctx, uint32_t nonce) >>>( ctx->device_blocks*ctx->device_threads, bfactorOneThree, i, ctx->d_long_state, - ctx->d_ctx_state, ctx->d_ctx_key2 )); + ctx->d_ctx_state, ctx->d_ctx_key2)); } } -void cryptonight_gpu_hash(nvid_ctx *ctx, xmrig::Algo algo, int variant, uint32_t startNonce) +void cryptonight_gpu_hash(nvid_ctx *ctx, xmrig::Algo algo, xmrig::Variant variant, uint32_t startNonce) { using namespace xmrig; - switch (algo) { - case CRYPTONIGHT: - if (variant > 0) { - cryptonight_core_gpu_hash(ctx, startNonce); - } - else { - cryptonight_core_gpu_hash(ctx, startNonce); - } - break; + if (algo == CRYPTONIGHT) { + switch (variant) { + case VARIANT_0: + cryptonight_core_gpu_hash(ctx, startNonce); + break; - case CRYPTONIGHT_LITE: - if (variant > 0) { - cryptonight_core_gpu_hash(ctx, startNonce); - } - else { - cryptonight_core_gpu_hash(ctx, startNonce); - } - break; + case VARIANT_1: + cryptonight_core_gpu_hash(ctx, startNonce); + break; - case CRYPTONIGHT_HEAVY: - cryptonight_core_gpu_hash(ctx, startNonce); - break; + case VARIANT_XTL: + cryptonight_core_gpu_hash(ctx, startNonce); + break; - case CRYPTONIGHT_IPBC: - cryptonight_core_gpu_hash(ctx, startNonce); - break; + case VARIANT_MSR: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_XAO: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_RTO: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_2: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + default: + break; + } + } + else if (algo == CRYPTONIGHT_LITE) { + switch (variant) { + case VARIANT_0: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_1: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + default: + break; + } + } + else if (algo == CRYPTONIGHT_HEAVY) { + switch (variant) { + case VARIANT_0: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_TUBE: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + case VARIANT_XHV: + cryptonight_core_gpu_hash(ctx, startNonce); + break; + + default: + break; + } } } diff --git a/src/nvidia/cuda_extra.cu b/src/nvidia/cuda_extra.cu index 1d3d0aee..dfccda43 100644 --- a/src/nvidia/cuda_extra.cu +++ b/src/nvidia/cuda_extra.cu @@ -29,7 +29,6 @@ #include #include #include -#include #ifdef __CUDACC__ __constant__ @@ -59,7 +58,7 @@ typedef unsigned long long DataLength; #include "cuda_skein.hpp" #include "cuda_device.hpp" #include "cuda_aes.hpp" -#include "xmrig.h" +#include "common/xmrig.h" #include "crypto/CryptoNight_constants.h" __constant__ uint8_t d_sub_byte[16][16] ={ @@ -131,19 +130,32 @@ __device__ __forceinline__ void mix_and_propagate( uint32_t* state ) (state + 4 * 7)[x] = (state + 4 * 7)[x] ^ tmp0[x]; } -template -__global__ void cryptonight_extra_gpu_prepare( int threads, uint32_t * __restrict__ d_input, uint32_t len, uint32_t startNonce, uint32_t * __restrict__ d_ctx_state, uint32_t * __restrict__ d_ctx_state2, uint32_t * __restrict__ d_ctx_a, uint32_t * __restrict__ d_ctx_b, uint32_t * __restrict__ d_ctx_key1, uint32_t * __restrict__ d_ctx_key2 ) + +template +__global__ void cryptonight_extra_gpu_prepare( + int threads, + uint32_t *__restrict__ d_input, + uint32_t len, + uint32_t startNonce, + uint32_t *__restrict__ d_ctx_state, + uint32_t *__restrict__ d_ctx_state2, + uint32_t *__restrict__ d_ctx_a, + uint32_t *__restrict__ d_ctx_b, + uint32_t *__restrict__ d_ctx_key1, + uint32_t *__restrict__ d_ctx_key2 + ) { - int thread = ( blockDim.x * blockIdx.x + threadIdx.x ); + int thread = (blockDim.x * blockIdx.x + threadIdx.x); __shared__ uint32_t sharedMemory[1024]; - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - { + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { cn_aes_gpu_init( sharedMemory ); __syncthreads( ); } - if ( thread >= threads ) + + if (thread >= threads) { return; + } uint32_t ctx_state[50]; uint32_t ctx_a[4]; @@ -152,42 +164,51 @@ __global__ void cryptonight_extra_gpu_prepare( int threads, uint32_t * __restric uint32_t ctx_key2[40]; uint32_t input[21]; - memcpy( input, d_input, len ); - //*((uint32_t *)(((char *)input) + 39)) = startNonce + thread; + memcpy(input, d_input, len); uint32_t nonce = startNonce + thread; - for ( int i = 0; i < sizeof (uint32_t ); ++i ) - ( ( (char *) input ) + 39 )[i] = ( (char*) ( &nonce ) )[i]; //take care of pointer alignment - - cn_keccak( (uint8_t *) input, len, (uint8_t *) ctx_state ); - cryptonight_aes_set_key( ctx_key1, ctx_state ); - cryptonight_aes_set_key( ctx_key2, ctx_state + 8 ); - - XOR_BLOCKS_DST( ctx_state, ctx_state + 8, ctx_a ); - XOR_BLOCKS_DST( ctx_state + 4, ctx_state + 12, ctx_b ); - memcpy( d_ctx_a + thread * 4, ctx_a, 4 * 4 ); - memcpy( d_ctx_b + thread * 4, ctx_b, 4 * 4 ); + for (int i = 0; i < sizeof (uint32_t ); ++i) { + (((char *)input) + 39)[i] = ((char*) (&nonce))[i]; //take care of pointer alignment + } - memcpy( d_ctx_key1 + thread * 40, ctx_key1, 40 * 4 ); - memcpy( d_ctx_key2 + thread * 40, ctx_key2, 40 * 4 ); - memcpy( d_ctx_state + thread * 50, ctx_state, 50 * 4 ); + cn_keccak((uint8_t *) input, len, (uint8_t *) ctx_state); + cryptonight_aes_set_key(ctx_key1, ctx_state); + cryptonight_aes_set_key(ctx_key2, ctx_state + 8); + + XOR_BLOCKS_DST(ctx_state, ctx_state + 8, ctx_a); + XOR_BLOCKS_DST(ctx_state + 4, ctx_state + 12, ctx_b); + memcpy(d_ctx_a + thread * 4, ctx_a, 4 * 4); + + if (VARIANT == xmrig::VARIANT_2) { + memcpy(d_ctx_b + thread * 12, ctx_b, 4 * 4); + // bx1 + XOR_BLOCKS_DST(ctx_state + 16, ctx_state + 20, ctx_b); + memcpy(d_ctx_b + thread * 12 + 4, ctx_b, 4 * 4); + // division_result + memcpy(d_ctx_b + thread * 12 + 2 * 4, ctx_state + 24, 4 * 2); + // sqrt_result + memcpy(d_ctx_b + thread * 12 + 2 * 4 + 2, ctx_state + 26, 4 * 2); + } else { + memcpy(d_ctx_b + thread * 4, ctx_b, 4 * 4); + } - if(ALGO == xmrig::CRYPTONIGHT_HEAVY) - { + memcpy(d_ctx_key1 + thread * 40, ctx_key1, 40 * 4); + memcpy(d_ctx_key2 + thread * 40, ctx_key2, 40 * 4); + memcpy(d_ctx_state + thread * 50, ctx_state, 50 * 4); - for(int i=0; i < 16; i++) - { - for(size_t t = 4; t < 12; ++t) - { - cn_aes_pseudo_round_mut( sharedMemory, ctx_state + 4u * t, ctx_key1 ); + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + for (int i = 0; i < 16; i++) { + for (size_t t = 4; t < 12; ++t) { + cn_aes_pseudo_round_mut(sharedMemory, ctx_state + 4u * t, ctx_key1); } // scipt first 4 * 128bit blocks = 4 * 4 uint32_t values mix_and_propagate(ctx_state + 4 * 4); } // double buffer to move manipulated state into phase1 - memcpy( d_ctx_state2 + thread * 50, ctx_state, 50 * 4 ); + memcpy(d_ctx_state2 + thread * 50, ctx_state, 50 * 4); } } + template __global__ void cryptonight_extra_gpu_final( int threads, uint64_t target, uint32_t* __restrict__ d_res_count, uint32_t * __restrict__ d_res_nonce, uint32_t * __restrict__ d_ctx_state,uint32_t * __restrict__ d_ctx_key2 ) { @@ -251,28 +272,28 @@ __global__ void cryptonight_extra_gpu_final( int threads, uint64_t target, uint3 // Note that comparison is equivalent to subtraction - we can't just compare 8 32-bit values // and expect an accurate result for target > 32-bit without implementing carries + if (hash[3] < target) { + uint32_t idx = atomicInc(d_res_count, 0xFFFFFFFF); - if ( hash[3] < target ) - { - uint32_t idx = atomicInc( d_res_count, 0xFFFFFFFF ); - - if(idx < 10) + if (idx < 10) { d_res_nonce[idx] = thread; + } } } -void cryptonight_extra_cpu_set_data(nvid_ctx *ctx, const void *data, uint32_t len) + +void cryptonight_extra_cpu_set_data(nvid_ctx *ctx, const void *data, size_t len) { - ctx->inputlen = len; + ctx->inputlen = static_cast(len); CUDA_CHECK(ctx->device_id, cudaMemcpy(ctx->d_input, data, len, cudaMemcpyHostToDevice)); } + int cryptonight_extra_cpu_init(nvid_ctx *ctx, xmrig::Algo algo, size_t hashMemSize) { cudaError_t err; err = cudaSetDevice(ctx->device_id); - if(err != cudaSuccess) - { + if (err != cudaSuccess) { printf("GPU %d: %s", ctx->device_id, cudaGetErrorString(err)); return 0; } @@ -294,65 +315,62 @@ int cryptonight_extra_cpu_init(nvid_ctx *ctx, xmrig::Algo algo, size_t hashMemSi break; }; - const int gpuArch = ctx->device_arch[0] * 10 + ctx->device_arch[1]; - - /* Disable L1 cache for GPUs before Volta. - * L1 speed is increased and latency reduced with Volta. - */ - if (gpuArch < 70) - CUDA_CHECK(ctx->device_id, cudaDeviceSetCacheConfig(cudaFuncCachePreferL1)); + CUDA_CHECK(ctx->device_id, cudaDeviceSetCacheConfig(cudaFuncCachePreferShared)); size_t wsize = ctx->device_blocks * ctx->device_threads; CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_state, 50 * sizeof(uint32_t) * wsize)); size_t ctx_b_size = 4 * sizeof(uint32_t) * wsize; - if (algo == xmrig::CRYPTONIGHT_HEAVY) - { + + if (algo == xmrig::CRYPTONIGHT_HEAVY) { // extent ctx_b to hold the state of idx0 ctx_b_size += sizeof(uint32_t) * wsize; // create a double buffer for the state to exchange the mixed state to phase1 CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_state2, 50 * sizeof(uint32_t) * wsize)); } - else + else { + ctx_b_size *= 3; ctx->d_ctx_state2 = ctx->d_ctx_state; + } - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_key1, 40 * sizeof(uint32_t) * wsize)); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_key2, 40 * sizeof(uint32_t) * wsize)); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_text, 32 * sizeof(uint32_t) * wsize)); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_a, 4 * sizeof(uint32_t) * wsize)); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_b, ctx_b_size)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_key1, 40 * sizeof(uint32_t) * wsize)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_key2, 40 * sizeof(uint32_t) * wsize)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_text, 32 * sizeof(uint32_t) * wsize)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_a, 4 * sizeof(uint32_t) * wsize)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_ctx_b, ctx_b_size)); // POW block format http://monero.wikia.com/wiki/PoW_Block_Header_Format - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_input, 21 * sizeof (uint32_t ) )); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_result_count, sizeof (uint32_t ) )); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_result_nonce, 10 * sizeof (uint32_t ) )); - CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_long_state, hashMemSize * wsize)); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_input, 21 * sizeof (uint32_t))); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_result_count, sizeof (uint32_t))); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_result_nonce, 10 * sizeof (uint32_t))); + CUDA_CHECK(ctx->device_id, cudaMalloc(&ctx->d_long_state, hashMemSize * wsize)); + return 1; } -void cryptonight_extra_cpu_prepare(nvid_ctx* ctx, uint32_t startNonce, xmrig::Algo algo) +void cryptonight_extra_cpu_prepare(nvid_ctx *ctx, uint32_t startNonce, xmrig::Algo algo, xmrig::Variant variant) { int threadsperblock = 128; uint32_t wsize = ctx->device_blocks * ctx->device_threads; - dim3 grid( ( wsize + threadsperblock - 1 ) / threadsperblock ); - dim3 block( threadsperblock ); + dim3 grid((wsize + threadsperblock - 1) / threadsperblock); + dim3 block(threadsperblock); - if(algo == xmrig::CRYPTONIGHT_HEAVY) - { - CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_extra_gpu_prepare<<>>( wsize, ctx->d_input, ctx->inputlen, startNonce, - ctx->d_ctx_state,ctx->d_ctx_state2, ctx->d_ctx_a, ctx->d_ctx_b, ctx->d_ctx_key1, ctx->d_ctx_key2 )); - } - else - { - /* pass two times d_ctx_state because the second state is used later in phase1, - * the first is used than in phase3 - */ - CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_extra_gpu_prepare<<>>( wsize, ctx->d_input, ctx->inputlen, startNonce, - ctx->d_ctx_state, ctx->d_ctx_state, ctx->d_ctx_a, ctx->d_ctx_b, ctx->d_ctx_key1, ctx->d_ctx_key2 )); + /* pass two times d_ctx_state because the second state is used later in phase1, + * the first is used than in phase3 + */ + if (algo == xmrig::CRYPTONIGHT_HEAVY) { + CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_extra_gpu_prepare<<>>(wsize, ctx->d_input, ctx->inputlen, startNonce, + ctx->d_ctx_state, ctx->d_ctx_state2, ctx->d_ctx_a, ctx->d_ctx_b, ctx->d_ctx_key1, ctx->d_ctx_key2)); + } else if (variant == xmrig::VARIANT_2) { + CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_extra_gpu_prepare<<>>(wsize, ctx->d_input, ctx->inputlen, startNonce, + ctx->d_ctx_state, ctx->d_ctx_state2, ctx->d_ctx_a, ctx->d_ctx_b, ctx->d_ctx_key1, ctx->d_ctx_key2)); + } else { + CUDA_CHECK_KERNEL(ctx->device_id, cryptonight_extra_gpu_prepare<<>>(wsize, ctx->d_input, ctx->inputlen, startNonce, + ctx->d_ctx_state, ctx->d_ctx_state, ctx->d_ctx_a, ctx->d_ctx_b, ctx->d_ctx_key1, ctx->d_ctx_key2)); } } -void cryptonight_extra_cpu_final(nvid_ctx* ctx, uint32_t startNonce, uint64_t target, uint32_t* rescount, uint32_t *resnonce, xmrig::Algo algo) +void cryptonight_extra_cpu_final(nvid_ctx *ctx, uint32_t startNonce, uint64_t target, uint32_t *rescount, uint32_t *resnonce, xmrig::Algo algo) { int threadsperblock = 128; uint32_t wsize = ctx->device_blocks * ctx->device_threads; @@ -386,6 +404,24 @@ void cryptonight_extra_cpu_final(nvid_ctx* ctx, uint32_t startNonce, uint64_t ta } } +void cryptonight_extra_cpu_free(nvid_ctx *ctx, xmrig::Algo algo) +{ + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_key1)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_key2)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_text)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_a)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_b)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_input)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_result_count)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_result_nonce)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_long_state)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_state)); + + if (algo == xmrig::CRYPTONIGHT_HEAVY) { + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_state2)); + } +} + int cuda_get_devicecount() { int deviceCount = 0; diff --git a/src/nvidia/cuda_extra.h b/src/nvidia/cuda_extra.h index f223f7be..352c26c0 100644 --- a/src/nvidia/cuda_extra.h +++ b/src/nvidia/cuda_extra.h @@ -18,8 +18,6 @@ struct uint3 blockDim; #define __shfl(a,b,c) 1 #endif -#define MEMORY (1 << 21) // 2 MiB / 2097152 B -#define MEMORY_LITE (1 << 20) // 1 MiB / 1048576 B #define AES_BLOCK_SIZE 16 #define AES_KEY_SIZE 32 #define INIT_SIZE_BLK 8 diff --git a/src/nvidia/cuda_fast_int_math_v2.hpp b/src/nvidia/cuda_fast_int_math_v2.hpp new file mode 100644 index 00000000..f3570769 --- /dev/null +++ b/src/nvidia/cuda_fast_int_math_v2.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include + +__device__ __forceinline__ uint32_t get_reciprocal(uint32_t a) +{ + const float a_hi = __uint_as_float((a >> 8) + ((126U + 31U) << 23)); + const float a_lo = __uint2float_rn(a & 0xFF); + + float r; + asm("rcp.approx.f32 %0, %1;" : "=f"(r) : "f"(a_hi)); + const float r_scaled = __uint_as_float(__float_as_uint(r) + (64U << 23)); + + const float h = __fmaf_rn(a_lo, r, __fmaf_rn(a_hi, r, -1.0f)); + return (__float_as_uint(r) << 9) - __float2int_rn(h * r_scaled); +} + +__device__ __forceinline__ uint64_t fast_div_v2(uint64_t a, uint32_t b) +{ + const uint32_t r = get_reciprocal(b); + const uint64_t k = __umulhi(((uint32_t*)&a)[0], r) + ((uint64_t)(r) * ((uint32_t*)&a)[1]) + a; + + uint32_t q[2]; + q[0] = ((uint32_t*)&k)[1]; + + int64_t tmp = a - (uint64_t)(q[0]) * b; + ((int32_t*)(&tmp))[1] -= (k < a) ? b : 0; + + const bool overshoot = ((int32_t*)(&tmp))[1] < 0; + const bool undershoot = tmp >= b; + + q[0] += (undershoot ? 1U : 0U) - (overshoot ? 1U : 0U); + q[1] = ((uint32_t*)(&tmp))[0] + (overshoot ? b : 0U) - (undershoot ? b : 0U); + + return *((uint64_t*)(q)); +} + +__device__ __forceinline__ uint32_t fast_sqrt_v2(const uint64_t n1) +{ + float x = __uint_as_float((((uint32_t*)&n1)[1] >> 9) + ((64U + 127U) << 23)); + float x1; + asm("rsqrt.approx.f32 %0, %1;" : "=f"(x1) : "f"(x)); + asm("sqrt.approx.f32 %0, %1;" : "=f"(x) : "f"(x)); + + // The following line does x1 *= 4294967296.0f; + x1 = __uint_as_float(__float_as_uint(x1) + (32U << 23)); + + const uint32_t x0 = __float_as_uint(x) - (158U << 23); + const int64_t delta0 = n1 - (((int64_t)(x0) * x0) << 18); + const float delta = __int2float_rn(((int32_t*)&delta0)[1]) * x1; + + uint32_t result = (x0 << 10) + __float2int_rn(delta); + const uint32_t s = result >> 1; + const uint32_t b = result & 1; + + const uint64_t x2 = (uint64_t)(s) * (s + b) + ((uint64_t)(result) << 32) - n1; + if ((int64_t)(x2 + b) > 0) --result; + if ((int64_t)(x2 + 0x100000000UL + s) < 0) ++result; + + return result; +} diff --git a/src/version.h b/src/version.h index 880b024e..ebb853cb 100644 --- a/src/version.h +++ b/src/version.h @@ -21,22 +21,21 @@ * along with this program. If not, see . */ -#ifndef __VERSION_H__ -#define __VERSION_H__ +#ifndef XMRIG_VERSION_H +#define XMRIG_VERSION_H -#define APP_ID "xmrig" -#define APP_NAME "XMRig" +#define APP_ID "xmrig-nvidia" +#define APP_NAME "XMRig-NVIDIA" #define APP_DESC "XMRig CUDA miner" -#define APP_VERSION "2.6.1" +#define APP_VERSION "2.8.0-dev" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2018 xmrig.com" #define APP_KIND "nvidia" #define APP_VER_MAJOR 2 -#define APP_VER_MINOR 6 -#define APP_VER_BUILD 1 -#define APP_VER_REV 0 +#define APP_VER_MINOR 8 +#define APP_VER_PATCH 0 #ifdef _MSC_VER # if (_MSC_VER >= 1910) @@ -54,4 +53,4 @@ # endif #endif -#endif /* __VERSION_H__ */ +#endif /* XMRIG_VERSION_H */ diff --git a/src/workers/CudaThread.cpp b/src/workers/CudaThread.cpp new file mode 100644 index 00000000..aea32a6a --- /dev/null +++ b/src/workers/CudaThread.cpp @@ -0,0 +1,206 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + + +#include "rapidjson/document.h" +#include "workers/CudaThread.h" + + +CudaThread::CudaThread() : + m_bfactor(0), + m_blocks(0), + m_bsleep(0), + m_clockRate(0), + m_memoryClockRate(0), + m_nvmlId(-1), + m_smx(0), + m_threads(0), + m_affinity(-1), + m_index(0), + m_threadId(0), + m_pciBusID(0), + m_pciDeviceID(0), + m_pciDomainID(0), + m_syncMode(3), + m_algorithm(xmrig::INVALID_ALGO) +{ + memset(m_arch, 0, sizeof(m_arch)); + memset(m_name, 0, sizeof(m_name)); +} + + +CudaThread::CudaThread(const nvid_ctx &ctx, int64_t affinity, xmrig::Algo algorithm) : + m_bfactor(ctx.device_bfactor), + m_blocks(ctx.device_blocks), + m_bsleep(ctx.device_bsleep), + m_clockRate(ctx.device_clockRate), + m_memoryClockRate(ctx.device_memoryClockRate), + m_nvmlId(-1), + m_smx(ctx.device_mpcount), + m_threads(ctx.device_threads), + m_affinity(affinity), + m_index(static_cast(ctx.device_id)), + m_threadId(0), + m_pciBusID(ctx.device_pciBusID), + m_pciDeviceID(ctx.device_pciDeviceID), + m_pciDomainID(ctx.device_pciDomainID), + m_syncMode(ctx.syncMode), + m_algorithm(algorithm) +{ + memcpy(m_arch, ctx.device_arch, sizeof(m_arch)); + strncpy(m_name, ctx.device_name, sizeof(m_name) - 1); +} + + +CudaThread::CudaThread(const rapidjson::Value &object) : + m_bfactor(0), + m_blocks(0), + m_bsleep(0), + m_clockRate(0), + m_memoryClockRate(0), + m_nvmlId(-1), + m_smx(0), + m_threads(0), + m_affinity(-1), + m_index(0), + m_threadId(0), + m_pciBusID(0), + m_pciDeviceID(0), + m_pciDomainID(0), + m_syncMode(3), + m_algorithm(xmrig::INVALID_ALGO) +{ + memset(m_arch, 0, sizeof(m_arch)); + memset(m_name, 0, sizeof(m_name)); + + setIndex(object["index"].GetUint()); + setThreads(object["threads"].GetInt()); + setBlocks(object["blocks"].GetInt()); + setBFactor(object["bfactor"].GetInt()); + setBSleep(object["bsleep"].GetInt()); + setSyncMode(object["sync_mode"].GetUint()); + + const rapidjson::Value &affinity = object["affine_to_cpu"]; + if (affinity.IsInt()) { + setAffinity(affinity.GetInt()); + } +} + + +bool CudaThread::init(xmrig::Algo algorithm) +{ + if (m_blocks < -1 || m_threads < -1 || m_bfactor < 0 || m_bsleep < 0) { + return false; + } + + if (cuda_get_devicecount() == 0) { + return false; + } + + nvid_ctx ctx; + ctx.device_id = static_cast(m_index); + ctx.device_blocks = m_blocks; + ctx.device_threads = m_threads; + ctx.device_bfactor = m_bfactor; + ctx.device_bsleep = m_bsleep; + ctx.syncMode = m_syncMode; + + if (cuda_get_deviceinfo(&ctx, algorithm) != 0) { + return false; + } + + memcpy(m_arch, ctx.device_arch, sizeof(m_arch)); + strncpy(m_name, ctx.device_name, sizeof(m_name) - 1); + + m_threads = ctx.device_threads; + m_blocks = ctx.device_blocks; + m_smx = ctx.device_mpcount; + + m_clockRate = ctx.device_clockRate; + m_memoryClockRate = ctx.device_memoryClockRate; + m_pciBusID = ctx.device_pciBusID; + m_pciDeviceID = ctx.device_pciDeviceID; + m_pciDomainID = ctx.device_pciDomainID; + + m_algorithm = algorithm; + return true; +} + + +void CudaThread::limit(int maxUsage, int maxThreads) +{ + if (maxThreads > 0) { + if (m_threads > maxThreads) { + m_threads = maxThreads; + } + + return; + } + + if (maxUsage < 100) { + m_threads = static_cast(m_threads / 100.0 * maxUsage); + } +} + + +#ifdef APP_DEBUG +void CudaThread::print() const +{ +} +#endif + + +#ifndef XMRIG_NO_API +rapidjson::Value CudaThread::toAPI(rapidjson::Document &doc) const +{ + return toConfig(doc); +} +#endif + + +rapidjson::Value CudaThread::toConfig(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + Value obj(kObjectType); + auto &allocator = doc.GetAllocator(); + + obj.AddMember("index", static_cast(index()), allocator); + obj.AddMember("threads", m_threads, allocator); + obj.AddMember("blocks", m_blocks, allocator); + obj.AddMember("bfactor", m_bfactor, allocator); + obj.AddMember("bsleep", m_bsleep, allocator); + obj.AddMember("sync_mode", m_syncMode, allocator); + + if (affinity() >= 0) { + obj.AddMember("affine_to_cpu", affinity(), allocator); + } + else { + obj.AddMember("affine_to_cpu", false, allocator); + } + + return obj; +} diff --git a/src/workers/CudaThread.h b/src/workers/CudaThread.h new file mode 100644 index 00000000..b54ac6c2 --- /dev/null +++ b/src/workers/CudaThread.h @@ -0,0 +1,110 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CUDATHREAD_H +#define XMRIG_CUDATHREAD_H + +#include + + +#include "interfaces/IThread.h" +#include "nvidia/cryptonight.h" + + +class CudaThread : public xmrig::IThread +{ +public: + CudaThread(); + CudaThread(const nvid_ctx &ctx, int64_t affinity, xmrig::Algo algorithm); + CudaThread(const rapidjson::Value &object); + + bool init(xmrig::Algo algorithm); + void limit(int maxUsage, int maxThreads); + + inline const char *name() const { return m_name; } + inline const int *arch() const { return m_arch; } + inline int bfactor() const { return m_bfactor; } + inline int blocks() const { return m_blocks; } + inline int bsleep() const { return m_bsleep; } + inline int clockRate() const { return m_clockRate; } + inline int memoryClockRate() const { return m_memoryClockRate; } + inline int nvmlId() const { return m_nvmlId; } + inline int smx() const { return m_smx; } + inline int threads() const { return m_threads; } + inline size_t threadId() const { return m_threadId; } + inline uint32_t pciBusID() const { return m_pciBusID; } + inline uint32_t pciDeviceID() const { return m_pciDeviceID; } + inline uint32_t pciDomainID() const { return m_pciDomainID; } + inline uint32_t syncMode() const { return m_syncMode; } + + inline xmrig::Algo algorithm() const override { return m_algorithm; } + inline int priority() const override { return -1; } + inline int64_t affinity() const override { return m_affinity; } + inline Multiway multiway() const override { return SingleWay; } + inline size_t index() const override { return m_index; } + inline Type type() const override { return CUDA; } + + inline void setAffinity(int affinity) { m_affinity = affinity; } + inline void setBFactor(int bfactor) { if (bfactor >= 0 && bfactor <= 12) { m_bfactor = bfactor; } } + inline void setBlocks(int blocks) { m_blocks = blocks; } + inline void setBSleep(int bsleep) { m_bsleep = bsleep; } + inline void setIndex(size_t index) { m_index = index; } + inline void setNvmlId(int id) { m_nvmlId = id; } + inline void setThreadId(size_t threadId) { m_threadId = threadId; } + inline void setThreads(int threads) { m_threads = threads; } + inline void setSyncMode(uint32_t syncMode) { m_syncMode = syncMode > 3 ? 3 : syncMode; } + +protected: +# ifdef APP_DEBUG + void print() const override; +# endif + +# ifndef XMRIG_NO_API + rapidjson::Value toAPI(rapidjson::Document &doc) const override; +# endif + + rapidjson::Value toConfig(rapidjson::Document &doc) const override; + +private: + char m_name[256]; + int m_arch[2]; + int m_bfactor; + int m_blocks; + int m_bsleep; + int m_clockRate; + int m_memoryClockRate; + int m_nvmlId; + int m_smx; + int m_threads; + int64_t m_affinity; + size_t m_index; + size_t m_threadId; + uint32_t m_pciBusID; + uint32_t m_pciDeviceID; + uint32_t m_pciDomainID; + uint32_t m_syncMode; + xmrig::Algo m_algorithm; +}; + + +#endif /* XMRIG_CUDATHREAD_H */ diff --git a/src/workers/CudaWorker.cpp b/src/workers/CudaWorker.cpp index 911cdd22..0e793e18 100644 --- a/src/workers/CudaWorker.cpp +++ b/src/workers/CudaWorker.cpp @@ -26,34 +26,36 @@ #include +#include "common/log/Log.h" +#include "common/Platform.h" #include "crypto/CryptoNight.h" -#include "Platform.h" +#include "workers/CudaThread.h" #include "workers/CudaWorker.h" -#include "workers/GpuThread.h" #include "workers/Handle.h" #include "workers/Workers.h" CudaWorker::CudaWorker(Handle *handle) : m_id(handle->threadId()), - m_threads(handle->threads()), - m_algorithm(handle->algorithm()), + m_threads(handle->totalWays()), + m_algorithm(handle->config()->algorithm()), m_hashCount(0), m_timestamp(0), m_count(0), - m_sequence(0) + m_sequence(0), + m_blob() { - const GpuThread *thread = handle->gpuThread(); + const CudaThread *thread = static_cast(handle->config()); - m_ctx.device_id = thread->index(); + m_ctx.device_id = static_cast(thread->index()); m_ctx.device_blocks = thread->blocks(); m_ctx.device_threads = thread->threads(); m_ctx.device_bfactor = thread->bfactor(); m_ctx.device_bsleep = thread->bsleep(); - m_ctx.syncMode = 3; + m_ctx.syncMode = thread->syncMode(); if (thread->affinity() >= 0) { - Platform::setThreadAffinity(thread->affinity()); + Platform::setThreadAffinity(static_cast(thread->affinity())); } } @@ -61,7 +63,7 @@ CudaWorker::CudaWorker(Handle *handle) : void CudaWorker::start() { if (cuda_get_deviceinfo(&m_ctx, m_algorithm) != 0 || cryptonight_gpu_init(&m_ctx, m_algorithm) != 1) { - printf("Setup failed for GPU %d. Exitting.\n", (int) m_id); + LOG_ERR("Setup failed for GPU %zu. Exitting.", m_id); return; } @@ -79,14 +81,14 @@ void CudaWorker::start() consumeJob(); } - cryptonight_extra_cpu_set_data(&m_ctx, m_job.blob(), (uint32_t) m_job.size()); + cryptonight_extra_cpu_set_data(&m_ctx, m_blob, m_job.size()); while (!Workers::isOutdated(m_sequence)) { uint32_t foundNonce[10]; uint32_t foundCount; - cryptonight_extra_cpu_prepare(&m_ctx, m_nonce, m_algorithm); - cryptonight_gpu_hash(&m_ctx, m_algorithm, m_job.variant(), m_nonce); + cryptonight_extra_cpu_prepare(&m_ctx, m_nonce, m_algorithm, m_job.algorithm().variant()); + cryptonight_gpu_hash(&m_ctx, m_algorithm, m_job.algorithm().variant(), m_nonce); cryptonight_extra_cpu_final(&m_ctx, m_nonce, m_job.target(), &foundCount, foundNonce, m_algorithm); for (size_t i = 0; i < foundCount; i++) { @@ -103,6 +105,8 @@ void CudaWorker::start() consumeJob(); } + + cryptonight_extra_cpu_free(&m_ctx, m_algorithm); } @@ -129,6 +133,7 @@ void CudaWorker::consumeJob() save(job); if (resume(job)) { + setJob(); return; } @@ -141,6 +146,8 @@ void CudaWorker::consumeJob() else { m_nonce = 0xffffffffU / m_threads * m_id; } + + setJob(); } @@ -153,6 +160,12 @@ void CudaWorker::save(const Job &job) } +void CudaWorker::setJob() +{ + memcpy(m_blob, m_job.blob(), sizeof(m_blob)); +} + + void CudaWorker::storeStats() { using namespace std::chrono; diff --git a/src/workers/CudaWorker.h b/src/workers/CudaWorker.h index 85d29df1..d709abe1 100644 --- a/src/workers/CudaWorker.h +++ b/src/workers/CudaWorker.h @@ -22,15 +22,15 @@ * along with this program. If not, see . */ -#ifndef __CUDAWORKER_H__ -#define __CUDAWORKER_H__ +#ifndef XMRIG_CUDAWORKER_H +#define XMRIG_CUDAWORKER_H #include +#include "common/net/Job.h" #include "interfaces/IWorker.h" -#include "net/Job.h" #include "net/JobResult.h" #include "nvidia/cryptonight.h" @@ -46,6 +46,8 @@ class CudaWorker : public IWorker protected: inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } + inline bool selfTest() override { return true; } + inline size_t id() const override { return m_id; } void start() override; @@ -53,10 +55,11 @@ class CudaWorker : public IWorker bool resume(const Job &job); void consumeJob(); void save(const Job &job); + void setJob(); void storeStats(); - const int m_id; - const int m_threads; + const size_t m_id; + const size_t m_threads; const xmrig::Algo m_algorithm; Job m_job; Job m_pausedJob; @@ -67,7 +70,8 @@ class CudaWorker : public IWorker uint32_t m_pausedNonce; uint64_t m_count; uint64_t m_sequence; + uint8_t m_blob[96]; // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk }; -#endif /* __CUDAWORKER_H__ */ +#endif /* XMRIG_CUDAWORKER_H */ diff --git a/src/workers/Handle.cpp b/src/workers/Handle.cpp index dd2282e4..48299d19 100644 --- a/src/workers/Handle.cpp +++ b/src/workers/Handle.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,17 +23,15 @@ #include "workers/Handle.h" -#include "workers/GpuThread.h" -Handle::Handle(int threadId, GpuThread *thread, int threads, xmrig::Algo algorithm) : - m_gpuThread(thread), +Handle::Handle(size_t threadId, xmrig::IThread *config, uint32_t offset, size_t totalWays) : + m_worker(nullptr), m_threadId(threadId), - m_threads(threads), - m_algorithm(algorithm), - m_worker(nullptr) + m_totalWays(totalWays), + m_offset(offset), + m_config(config) { - thread->setThreadId(threadId); } diff --git a/src/workers/Handle.h b/src/workers/Handle.h index fd461515..41fad856 100644 --- a/src/workers/Handle.h +++ b/src/workers/Handle.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,43 +21,43 @@ * along with this program. If not, see . */ -#ifndef __HANDLE_H__ -#define __HANDLE_H__ +#ifndef XMRIG_HANDLE_H +#define XMRIG_HANDLE_H +#include #include #include -#include "xmrig.h" +#include "interfaces/IThread.h" class IWorker; -class GpuThread; class Handle { public: - Handle(int threadId, GpuThread *thread, int threads, xmrig::Algo algorithm); + Handle(size_t threadId, xmrig::IThread *config, uint32_t offset, size_t totalWays); void join(); void start(void (*callback) (void *)); - inline const GpuThread *gpuThread() const { return m_gpuThread; } - inline int threadId() const { return m_threadId; } - inline int threads() const { return m_threads; } - inline IWorker *worker() const { return m_worker; } - inline void setWorker(IWorker *worker) { m_worker = worker; } - inline xmrig::Algo algorithm() const { return m_algorithm; } + inline IWorker *worker() const { return m_worker; } + inline size_t threadId() const { return m_threadId; } + inline size_t totalWays() const { return m_totalWays; } + inline uint32_t offset() const { return m_offset; } + inline void setWorker(IWorker *worker) { assert(worker != nullptr); m_worker = worker; } + inline xmrig::IThread *config() const { return m_config; } private: - const GpuThread *m_gpuThread; - const int m_threadId; - const int m_threads; - const xmrig::Algo m_algorithm; IWorker *m_worker; + size_t m_threadId; + size_t m_totalWays; + uint32_t m_offset; uv_thread_t m_thread; + xmrig::IThread *m_config; }; -#endif /* __HANDLE_H__ */ +#endif /* XMRIG_HANDLE_H */ diff --git a/src/workers/Hashrate.cpp b/src/workers/Hashrate.cpp index af8b6b52..2a750318 100644 --- a/src/workers/Hashrate.cpp +++ b/src/workers/Hashrate.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,16 +22,20 @@ */ +#include #include #include #include +#include + -#include "log/Log.h" -#include "Options.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" #include "workers/Hashrate.h" -inline const char *format(double h, char* buf, size_t size) +inline static const char *format(double h, char *buf, size_t size) { if (isnormal(h)) { snprintf(buf, size, "%03.1f", h); @@ -42,21 +46,28 @@ inline const char *format(double h, char* buf, size_t size) } -Hashrate::Hashrate(int threads) : +Hashrate::Hashrate(size_t threads, xmrig::Controller *controller) : m_highest(0.0), - m_threads(threads) + m_threads(threads), + m_controller(controller) { m_counts = new uint64_t*[threads]; m_timestamps = new uint64_t*[threads]; m_top = new uint32_t[threads]; - for (int i = 0; i < threads; i++) { - m_counts[i] = new uint64_t[kBucketSize]; - m_timestamps[i] = new uint64_t[kBucketSize]; - m_top[i] = 0; + for (size_t i = 0; i < threads; i++) { + m_counts[i] = new uint64_t[kBucketSize](); + m_timestamps[i] = new uint64_t[kBucketSize](); + m_top[i] = 0; + } + + const int printTime = controller->config()->printTime(); + + if (printTime > 0) { + uv_timer_init(uv_default_loop(), &m_timer); + m_timer.data = this; - memset(m_counts[0], 0, sizeof(uint64_t) * kBucketSize); - memset(m_timestamps[0], 0, sizeof(uint64_t) * kBucketSize); + uv_timer_start(&m_timer, Hashrate::onReport, (printTime + 4) * 1000, printTime * 1000); } } @@ -66,7 +77,7 @@ double Hashrate::calc(size_t ms) const double result = 0.0; double data; - for (int i = 0; i < m_threads; ++i) { + for (size_t i = 0; i < m_threads; ++i) { data = calc(i, ms); if (isnormal(data)) { result += data; @@ -79,6 +90,11 @@ double Hashrate::calc(size_t ms) const double Hashrate::calc(size_t threadId, size_t ms) const { + assert(threadId < m_threads); + if (threadId >= m_threads) { + return nan(""); + } + using namespace std::chrono; const uint64_t now = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); @@ -136,14 +152,15 @@ void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) } -void Hashrate::print() +void Hashrate::print() const { - char num1[8]; - char num2[8]; - char num3[8]; - char num4[8]; + char num1[8] = { 0 }; + char num2[8] = { 0 }; + char num3[8] = { 0 }; + char num4[8] = { 0 }; - LOG_INFO(Options::i()->colors() ? "\x1B[01;37mspeed\x1B[0m 10s/60s/15m \x1B[01;36m%s\x1B[0m \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m max: \x1B[01;36m%s H/s" : "speed 10s/60s/15m %s %s %s H/s max: %s H/s", + LOG_INFO(m_controller->config()->isColors() ? WHITE_BOLD("speed") " 10s/60s/15m " CYAN_BOLD("%s") CYAN(" %s %s ") CYAN_BOLD("H/s") " max " CYAN_BOLD("%s H/s") + : "speed 10s/60s/15m %s %s %s H/s max %s H/s", format(calc(ShortInterval), num1, sizeof(num1)), format(calc(MediumInterval), num2, sizeof(num2)), format(calc(LargeInterval), num3, sizeof(num3)), @@ -152,30 +169,28 @@ void Hashrate::print() } -void Hashrate::print(size_t threadId, int gpuId) -{ - char num1[8]; - char num2[8]; - char num3[8]; - - LOG_INFO(Options::i()->colors() ? "\x1B[01;37mGPU %d\x1B[0m 10s/60s/15m \x1B[01;36m%s\x1B[0m \x1B[22;36m%s %s \x1B[01;36mH/s" : "speed 10s/60s/15m %s %s %s H/s", - gpuId, - format(calc(threadId, ShortInterval), num1, sizeof(num1)), - format(calc(threadId, MediumInterval), num2, sizeof(num2)), - format(calc(threadId, LargeInterval), num3, sizeof(num3)) - ); -} - - void Hashrate::stop() { + uv_timer_stop(&m_timer); } void Hashrate::updateHighest() { - double highest = calc(10000); + double highest = calc(ShortInterval); if (isnormal(highest) && highest > m_highest) { m_highest = highest; } } + + +const char *Hashrate::format(double h, char *buf, size_t size) +{ + return ::format(h, buf, size); +} + + +void Hashrate::onReport(uv_timer_t *handle) +{ + static_cast(handle->data)->print(); +} diff --git a/src/workers/Hashrate.h b/src/workers/Hashrate.h index 9ea5b514..e766f117 100644 --- a/src/workers/Hashrate.h +++ b/src/workers/Hashrate.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,12 @@ #include +#include + + +namespace xmrig { + class Controller; +} class Hashrate @@ -37,26 +43,32 @@ class Hashrate LargeInterval = 900000 }; - Hashrate(int threads); + Hashrate(size_t threads, xmrig::Controller *controller); double calc(size_t ms) const; double calc(size_t threadId, size_t ms) const; void add(size_t threadId, uint64_t count, uint64_t timestamp); - void print(); - void print(size_t threadId, int gpuId); + void print() const; void stop(); void updateHighest(); inline double highest() const { return m_highest; } + inline size_t threads() const { return m_threads; } + + static const char *format(double h, char *buf, size_t size); private: + static void onReport(uv_timer_t *handle); + constexpr static size_t kBucketSize = 2 << 11; constexpr static size_t kBucketMask = kBucketSize - 1; double m_highest; - int m_threads; + size_t m_threads; uint32_t* m_top; uint64_t** m_counts; uint64_t** m_timestamps; + uv_timer_t m_timer; + xmrig::Controller *m_controller; }; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 01619cbe..cfd3f484 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -22,22 +22,20 @@ */ #include - -#ifdef __GNUC__ -# include -#else -# include -#endif +#include #include "api/Api.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" #include "crypto/CryptoNight.h" #include "interfaces/IJobResultListener.h" -#include "log/Log.h" +#include "interfaces/IThread.h" #include "nvidia/NvmlApi.h" -#include "Options.h" +#include "rapidjson/document.h" +#include "workers/CudaThread.h" #include "workers/CudaWorker.h" -#include "workers/GpuThread.h" #include "workers/Handle.h" #include "workers/Hashrate.h" #include "workers/Workers.h" @@ -48,6 +46,7 @@ bool Workers::m_enabled = true; Hashrate *Workers::m_hashrate = nullptr; IJobResultListener *Workers::m_listener = nullptr; Job Workers::m_job; +size_t Workers::m_threadsCount = 0; std::atomic Workers::m_paused; std::atomic Workers::m_sequence; std::list Workers::m_queue; @@ -56,8 +55,8 @@ uint64_t Workers::m_ticks = 0; uv_async_t Workers::m_async; uv_mutex_t Workers::m_mutex; uv_rwlock_t Workers::m_rwlock; -uv_timer_t Workers::m_reportTimer; uv_timer_t Workers::m_timer; +xmrig::Controller *Workers::m_controller = nullptr; struct JobBaton @@ -83,11 +82,46 @@ Job Workers::job() } +size_t Workers::hugePages() +{ + return 0; +} + + +size_t Workers::threads() +{ + return m_threadsCount; +} + + void Workers::printHashrate(bool detail) { + assert(m_controller != nullptr); + if (!m_controller) { + return; + } + if (detail) { - for (const GpuThread *thread : Options::i()->threads()) { - m_hashrate->print(thread->threadId(), thread->index()); + const bool isColors = m_controller->config()->isColors(); + char num1[8] = { 0 }; + char num2[8] = { 0 }; + char num3[8] = { 0 }; + + Log::i()->text("%s| THREAD | GPU | 10s H/s | 60s H/s | 15m H/s | NAME", isColors ? "\x1B[1;37m" : ""); + + size_t i = 0; + for (const xmrig::IThread *t : m_controller->config()->threads()) { + auto thread = static_cast(t); + Log::i()->text("| %6zu | %3zu | %7s | %7s | %7s | %s%s", + i, thread->index(), + Hashrate::format(m_hashrate->calc(i, Hashrate::ShortInterval), num1, sizeof num1), + Hashrate::format(m_hashrate->calc(i, Hashrate::MediumInterval), num2, sizeof num2), + Hashrate::format(m_hashrate->calc(i, Hashrate::LargeInterval), num3, sizeof num3), + isColors ? "\x1B[1;30m" : "", + thread->name() + ); + + i++; } } @@ -103,15 +137,16 @@ void Workers::printHealth() } Health health; - for (const GpuThread *thread : Options::i()->threads()) { + for (const xmrig::IThread *t : m_controller->config()->threads()) { + auto thread = static_cast(t); if (!NvmlApi::health(thread->nvmlId(), health)) { continue; } const uint32_t temp = health.temperature; - if (health.clock && health.power) { - if (Options::i()->colors()) { + if (health.clock && health.clock) { + if (m_controller->config()->isColors()) { LOG_INFO("\x1B[00;35mGPU #%d: \x1B[01m%u\x1B[00;35m/\x1B[01m%u MHz\x1B[00;35m \x1B[01m%uW\x1B[00;35m %s%uC\x1B[00;35m FAN \x1B[01m%u%%", thread->index(), health.clock, health.memClock, health.power / 1000, (temp < 45 ? "\x1B[01;32m" : (temp > 65 ? "\x1B[01;31m" : "\x1B[01;33m")), temp, health.fanSpeed); } @@ -122,7 +157,7 @@ void Workers::printHealth() continue; } - if (Options::i()->colors()) { + if (m_controller->config()->isColors()) { LOG_INFO("\x1B[00;35mGPU #%d: %s%uC\x1B[00;35m FAN \x1B[01m%u%%", thread->index(), (temp < 45 ? "\x1B[01;32m" : (temp > 65 ? "\x1B[01;31m" : "\x1B[01;33m")), temp, health.fanSpeed); } @@ -169,41 +204,49 @@ void Workers::setJob(const Job &job, bool donate) } -void Workers::start(const std::vector &threads) +bool Workers::start(xmrig::Controller *controller) { - const size_t count = threads.size(); - m_hashrate = new Hashrate((int) count); + m_controller = controller; + const std::vector &threads = controller->config()->threads(); + size_t ways = 0; - uv_mutex_init(&m_mutex); - uv_rwlock_init(&m_rwlock); + for (const xmrig::IThread *thread : threads) { + ways += static_cast(thread->multiway()); + } - m_sequence = 1; - m_paused = 1; + m_threadsCount = threads.size(); + m_hashrate = new Hashrate(m_threadsCount, controller); + m_sequence = 1; + m_paused = 1; + uv_mutex_init(&m_mutex); + uv_rwlock_init(&m_rwlock); uv_async_init(uv_default_loop(), &m_async, Workers::onResult); uv_timer_init(uv_default_loop(), &m_timer); uv_timer_start(&m_timer, Workers::onTick, 500, 500); - for (size_t i = 0; i < count; ++i) { - Handle *handle = new Handle((int) i, threads[i], (int) count, Options::i()->algorithm()); + uint32_t offset = 0; + + size_t i = 0; + for (xmrig::IThread *thread : threads) { + Handle *handle = new Handle(i, thread, offset, ways); + offset += static_cast(thread->multiway()); + i++; + m_workers.push_back(handle); handle->start(Workers::onReady); } - const int printTime = Options::i()->printTime(); - if (printTime > 0) { - uv_timer_init(uv_default_loop(), &m_reportTimer); - uv_timer_start(&m_reportTimer, Workers::onReport, (printTime + 4) * 1000, printTime * 1000); + if (controller->config()->isShouldSave()) { + controller->config()->save(); } + + return true; } void Workers::stop() { - if (Options::i()->printTime() > 0) { - uv_timer_stop(&m_reportTimer); - } - uv_timer_stop(&m_timer); m_hashrate->stop(); @@ -227,16 +270,25 @@ void Workers::submit(const Job &result) } +#ifndef XMRIG_NO_API +void Workers::threadsSummary(rapidjson::Document &) +{ +} +#endif + + void Workers::onReady(void *arg) { auto handle = static_cast(arg); - handle->setWorker(new CudaWorker(handle)); - handle->worker()->start(); + IWorker *worker = new CudaWorker(handle); + handle->setWorker(worker); + + start(worker); } -void Workers::onResult(uv_async_t *handle) +void Workers::onResult(uv_async_t *) { JobBaton *baton = new JobBaton(); @@ -250,7 +302,11 @@ void Workers::onResult(uv_async_t *handle) uv_queue_work(uv_default_loop(), &baton->request, [](uv_work_t* req) { JobBaton *baton = static_cast(req->data); - cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); + if (baton->jobs.empty()) { + return; + } + + cryptonight_ctx *ctx = CryptoNight::createCtx(baton->jobs[0].algorithm().algo()); for (const Job &job : baton->jobs) { JobResult result(job); @@ -263,9 +319,9 @@ void Workers::onResult(uv_async_t *handle) } } - _mm_free(ctx); + CryptoNight::freeCtx(ctx); }, - [](uv_work_t* req, int status) { + [](uv_work_t* req, int) { JobBaton *baton = static_cast(req->data); for (const JobResult &result : baton->results) { @@ -273,7 +329,7 @@ void Workers::onResult(uv_async_t *handle) } if (baton->errors > 0 && !baton->jobs.empty()) { - LOG_ERR("GPU #%d COMPUTE ERROR", baton->jobs[0].threadId()); + LOG_ERR("THREAD #%d COMPUTE ERROR", baton->jobs[0].threadId()); } delete baton; @@ -282,17 +338,7 @@ void Workers::onResult(uv_async_t *handle) } -void Workers::onReport(uv_timer_t *handle) -{ - m_hashrate->print(); - - if (NvmlApi::isAvailable()) { - printHealth(); - } -} - - -void Workers::onTick(uv_timer_t *handle) +void Workers::onTick(uv_timer_t *) { for (Handle *handle : m_workers) { if (!handle->worker()) { @@ -305,19 +351,10 @@ void Workers::onTick(uv_timer_t *handle) if ((m_ticks++ & 0xF) == 0) { m_hashrate->updateHighest(); } +} -# ifndef XMRIG_NO_API - Api::tick(m_hashrate); - - if ((m_ticks++ & 0x4) == 0) { - std::vector records; - Health health; - for (const GpuThread *thread : Options::i()->threads()) { - NvmlApi::health(thread->nvmlId(), health); - records.push_back(health); - } - Api::setHealth(records); - } -# endif +void Workers::start(IWorker *worker) +{ + worker->start(); } diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 1053d12e..3233d69b 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#ifndef __WORKERS_H__ -#define __WORKERS_H__ +#ifndef XMRIG_WORKERS_H +#define XMRIG_WORKERS_H #include @@ -30,45 +30,60 @@ #include #include -#include "net/Job.h" +#include "common/net/Job.h" #include "net/JobResult.h" +#include "rapidjson/fwd.h" class Handle; class Hashrate; class IJobResultListener; +class IWorker; + + +namespace xmrig { + class Controller; +} class Workers { public: static Job job(); + static size_t hugePages(); + static size_t threads(); static void printHashrate(bool detail); static void printHealth(); static void setEnabled(bool enabled); static void setJob(const Job &job, bool donate); - static void start(const std::vector &threads); + static bool start(xmrig::Controller *controller); static void stop(); static void submit(const Job &result); static inline bool isEnabled() { return m_enabled; } static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } + static inline Hashrate *hashrate() { return m_hashrate; } static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } static inline void pause() { m_active = false; m_paused = 1; m_sequence++; } static inline void setListener(IJobResultListener *listener) { m_listener = listener; } +# ifndef XMRIG_NO_API + static void threadsSummary(rapidjson::Document &doc); +# endif + private: static void onReady(void *arg); static void onResult(uv_async_t *handle); - static void onReport(uv_timer_t *handle); static void onTick(uv_timer_t *handle); + static void start(IWorker *worker); static bool m_active; static bool m_enabled; static Hashrate *m_hashrate; static IJobResultListener *m_listener; static Job m_job; + static size_t m_threadsCount; static std::atomic m_paused; static std::atomic m_sequence; static std::list m_queue; @@ -77,9 +92,9 @@ class Workers static uv_async_t m_async; static uv_mutex_t m_mutex; static uv_rwlock_t m_rwlock; - static uv_timer_t m_reportTimer; static uv_timer_t m_timer; + static xmrig::Controller *m_controller; }; -#endif /* __WORKERS_H__ */ +#endif /* XMRIG_WORKERS_H */